Super Mario RPG has a challenge to complete 100 consecutive jumps on a single enemy. The reward is a powerful piece of armor for Mario.
It is recommended to do this in Mushroom Way (the zone directly after Mario's Pad), where you can find Spikey enemies which take no damage from jumps, allowing you to try again and again without re-entering combat with other enemies. Plus, there is a mushroom in a chest in the area northwest of the spikeys so you can refill on flower power!
I couldn't get beyond 30 jumps doing it by hand, so I found another way.
Thanks to reddit user Imaginary-Cod-8685 for the basis for this python script. https://www.reddit.com/r/MarioRPG/comments/181eu91/100_jumps_mario_rpg/
This python script was run on a Raspberry Pi 3B connected to a PCA9685 servo controller and a MG995 servo to repeatedly press the A button on a Switch Pro controller with very precise timing.
I ran sudo pip3 install adafruit-circuitpython-servokit
on the pi before running the python script, in order to install the "ServoKit" library. It is also necessary to enable I2C via the Raspberry Pi config application. It is a regular GUI app on recent rasperry pi OS releases.
I have refined the script to eliminate cumulative timing error from time.sleep() calls, and in fact this code does a spin-wait instead of time.sleep between events for the most accurate and precise possible timing. To be more precise than this, I assume it would be required to drive the servo with an Arduino or something with a real-time OS.
The following script is what I used to complete the 100 jumps challenge. You will need to make modifications, at least to the nopress
and pressDepth
variables. nopress
is the servo position in degrees for the "un-pressed" state. pressDepth
is the change which should be applied to the servo position in order to cause the button to be pressed. pressDepth
could be positive or negative depending on your servo positioning and which direction you need it to rotate to press the button. You want the button to be pressed fully and 100% reliably, but not pressed too hard as you could cause undue wear to the button, or excessive stress to the servo.
Important timing numbers are near the bottom in arguments to the press
function.
from adafruit_servokit import ServoKit
import time
counter = 1
kit = ServoKit(channels=16)
globals()['auto'] = 'off'
time_stored = time.time()
waits = 0
def wait(s):
global time_stored
global waits
global counter
# You can add a time offset here if needed, but I ended up not needing to
#if (counter == 30):
# time_stored = time_stored + -0.005
end_time = time_stored + s
time_stored = end_time
while time.time() < end_time:
waits = waits + 1
nopress = 130
pressDepth = -16
# Initialize servo at "no press" position, wait half a second
kit.servo[0].angle = nopress
wait(0.5)
def press(totalTime):
pressTime = 0.30
kit.servo[0].angle = nopress + pressDepth
wait(pressTime)
kit.servo[0].angle = nopress
wait(totalTime - pressTime)
# Press to initiate the jumping, wait 1.52 seconds for mario to land.
press(1.52)
# Now jump in a loop with consistent timing.
# This continues until you stop the program.
try:
while True:
press(0.88375)
counter = counter + 1
finally:
kit.servo[0].angle = nopress
wait(0.5)
I ran the script in the "Thonny" application which was pre-installed in Raspberry Pi OS. This application offers convenient start and stop buttons.
The hardware used is as follows (Amazon US links, not affilliate links):
- Switch pro controller (technically optional) (wired or wireless, see what works best for you)
- Raspberry Pi 3B (any Pi should work, however)
- Variable DC power supply
- PCA9685 Servo Controller
- MG995 Servo
- Dupont Wire for connecting the servo controller to the Pi and to the power supply.
- Some scrap wood and screws to securely mount the servo at an appropriate height to consistently press a button on the Switch Pro controller.
I first tried this with a cheap 5 volt 3 amp power supply I had lying around, and no servo controller (servo connected directly to the pi). It was terrible. The timing was incredibly inconsistent and the servo jittered back and forth a lot. Adding the servo controller and bigger power supply completely solved that and made the servo perform very well.
I set the power supply to about 5.5 volts with a limit of 4 amps. In practice, the output only spikes up to about 1 amp while the servo is moving.
The wiring diagram for the whole setup is basically what is shown on Adafruit here (except you don't really need the breadboard): https://learn.adafruit.com/adafruit-16-channel-servo-driver-with-raspberry-pi/hooking-it-up
Here are pictures from the final setup I used.