In part 1 and part 2 of this series, I explained how to interface the STEMBoT and its remote, from pairing to programming its buttons. In this final post, I’ll go over a complete program that gives purpose to every programmable button and both joysticks.
This program controls the onboard LED, a servo port, the motors, and the LED, SHT21, and MPU6050 plug and play modules. If you don’t have one or more of these modules, you can comment out the sections of code that use them by placing a pound sign (#) in front of the code. The LED module should be plugged into the top port, the SHT21 temperature module should be in the right port, and the MPU6050 accelerometer should be in the left port.
The joysticks are used to control each motor, and pressing the joystick buttons will change the motor speed. The directional pad (d-pad) will cause the robot to move forward or backward 1 foot, or turn 90 degrees left or right. The right and left buttons will cause the servo to move from one side to another, and the triggers will flash the LEDs on the plug-and-play module in one direction or the other. The start button prints acceleration readings to the LCD, and the back button prints temperature readings (in Fahrenheit). Finally, the colored buttons on the right will illuminate the onboard LED, and the yellow Y button will turn them all off.
To get started, download the code and drag it to the apps folder of your STEMBoT. After resetting your bot, it should appear in the list of apps on the main menu. Be ready to pair your remote once you open the app! After pairing, the program is ready to go and you can try out all of the buttons on your remote.
The code itself starts by importing the required modules. The standard “async def main():” header defines the start of the program. The first two lines are ones we’ve seen in part 1 of this series: they create Remote() and RemoteData() objects for interacting with the controller. The next line sets up a Servo() object as s1 (this will be the servo port closest to the top of the board). The first major block of code sets up the motors and functions for controlling them. The motorWake() and motorSleep() functions enable and disable the motors. The motorStop() function combined with the brake_mode setting will cause the motors to stop in place. Otherwise, the wheels will keep spinning on their own inertia. The remaining four functions are used for d-pad movement, and will put the motors to sleep once complete, which helps to save power.
The next block of code contains a function that cycles through the LEDs in the top port. It starts by turning them all off, then turns on one according to the number in ledNum, which is then increased or decreased by 1, depending on the direction passed to the function (either “CW” for clockwise or “CCW” for counterclockwise). This function was written with the circular LED module in mind, but it will work with the rectangular module.
The following blocks of code access the accelerometer and temperature sensor modules, and will print the results to the LCD (black text on a white background). If you want to switch the modules around, “left” and “right” can be changed.
Once the program is selected from the main menu, the pairing code starts. Just like in part 1, the r.pair() method is called to get the controller and the STEMBoT talking to each other. The surrounding code is used for feedback, so you know whether or not the pairing was successful (using the r.is_paired() method).
The final block of code starts with a while(1) statement, so everything that comes after occurs in an infinite loop. The code will try to read the remote’s signal, and if that fails, the motors will turn off. That way, if you drive the STEMBoT outside of signal range, it won’t drive itself off a cliff! The try…except block of code is a form of error handling, which is a vital part of complex software.
Just like in part 2, this code will test if the colored buttons are being pressed, and will turn on the onboard LED corresponding to the button. If the yellow Y button is pressed, a short for loop is executed to shut them off (because there’s no yellow LED!).
Next, the LB and RB buttons are tested, and will turn the servo from one angle to another. The triggers will illuminate the LED plug-and-play module in one direction or the other by using the function described earlier.
Pressing the start button will print acceleration data, and pressing the back button prints temperature data. This section of code is done with an if..elif statement to give acceleration data priority if both buttons are pressed (if the start button is pressed, the elif section will not execute). If you wanted to give the temperature data priority, you could replace the elif with if. Then, if both buttons are pressed, the graphics.paint() function in the second if statement will overwrite the acceleration data.
The next block of code changes the speed variable either higher or lower depending on which joystick button is pressed. Pressing the left joystick button decreases the speed and the right joystick increases it. This happens in increments of 100, and will limit the speed between 100 and 400, giving 4 speeds. A delay of almost half a second is included in these statements to prevent accidentally registering multiple button presses (this delay is the same amount of time the main menu uses!).
The final block of code will drive the motors based on the joysticks, similar to the two-joystick driving mode offered in the basic code. The big difference is that the speed isn’t based on how far you push the joysticks, it’s fixed based on the speed variable which can be changed by clicking the joysticks.
This program was written to demonstrate the power that users have over the controller, and is easily modifiable to suit your needs. I hope that this series gives you the knowledge and confidence to start writing your own wireless controller programs!