With its multi-core Propeller brains, this ActivityBot can play music or talk while driving, or change direction while talking, while at the same time decoding IR remote signals and monitoring for collisions with obstacle-detecting touch-whisker sensors. No coding interrupts required!
But if you accidentally drive your robot into an object, be prepared for your ActivityBot to feel it! If the whiskers detect contact, the ActivityBot will jump back and say “Ouch!” then sit still, quietly, until you are ready to drive it more carefully. This project is easy to customize with your own WAV files or with other types of sensors. Or for more of a group challenge, build a walled maze and use it for a driving skill contest!
Requires parts not included in the base ActivityBot Robot kit. See parts list below for details. It is highly recommended that you complete all of the ActivityBot tutorials before trying this project.
*Check your ActivityBot kit; a microSD card was included with some versions as a bonus and it is now sold as an optional accessory.
You will also be using these items that are included in the ActivityBot Kit:
You will need to add the veho360 speaker and its mounting bracket, the whisker circuits, and one IR receiver circuit to your ActivityBot. You will also need to configure your IR remote for Sony protocol.
]
You will need to build and test three sensor circuits on your ActivityBot breadboard: two for whiskers, and one for the Infrared Receiver. When you are done, your board will look something like the one below.
Now it is time to put all the necessary files on the ActivityBot, and then take it for a drive!
You will need to transfer the eleven WAV files from the project folder to the microSD card that comes with the ActivityBot kit. If you have a microSD/USB card adapter, you can use that to load the files onto the SD card directly from your computer before putting the card into the ActivityBoard. If you don’t, just follow the directions below.
Now, you are ready to run the program!
Note: If you are using the ActivityBot 360° Robot (#32600), change #include “abdrive.h” to #include “abdrive360.h” at the beginning of the program before uploading the code to your robot.
The remote’s driving controls take a little bit of practice. This is “set-and-forget” motion – you do not have to hold a button down to make the robot keep moving in that direction. Also, the motions are designed with ramping, so you can control speed as well as direction (with practice!). Be ready to hold the Mute button down to make it stop!
Here are some driving tips:
The AB-IR-Remote-WAV application uses the simpletools and abdrive (or abdrive360) libraries, which may be familiar to you already. It also uses the wavplayer library to play the audio files, and sirc to decode the infrared signals received from the remote controller.
A detailed comment block (all the lines between /* and */) helps other people know what is needed to use the application code, and what to expect from it in action.
/* AB-IR-Remote-Wav.c 10/30/2013 version 0.5 https://learn.parallax.com/activitybot ActivityBot plays WAV files on speaker from SD card Sensors: IR receiver on P10, touch whiskers on P7 & P8 Control with Sony-compatible remote (Parallax #020-00001) (Brightstar: hold Setup until lit, then enter 605) Drive with 5 buttons: Channel+/-, Vol +/-, and mute Number keys select WAV files to play If whiskers are pressed, robot backs up & stops, plays WAV */ #include "simpletools.h" #include "wavplayer.h" // Needs 0.9 or later #include "abdrive.h" // Needs 0.5.5 or later #include "sirc.h"
Inside the main routine, there are a few setup tasks. First, a freqout call lets you know the program is starting, or re-starting if the batteries run low. Next, drive_speed(0,0) starts the servo/encoder control core, but does not move the motors yet. Then, a call to drive_setRampStep determines how quickly the robot will move into and out of maneuvers.
int main() // Main - execution begins! { freqout(4, 2000, 2000); // Start beep - low battery reset alarm drive_speed(0,0); // Start servos/encoders cog drive_setRampStep(10); // Set ramping at 10 ticks/sec per 20 ms sirc_setTimeout(50); // Remote timeout = 50 ms int DO = 22, CLK = 23, DI = 24, CS = 25; // Declare SD I/O pins sd_mount(DO, CLK, DI, CS); // Mount SD card wav_volume(7); // Set vol here, 1 - 10
This program has a loop-within-a-loop structure. The outer loop is a simple while(1) that repeats forever. The inner while loop is conditional, and only repeats if no whisker is pressed. It translates to “add the input states of P7 and P8, and as long as the answer is equal to 2, repeat the loop.” Recall that the whisker touch-sensors are “active-low” circuits that return a 1 if not pressed, and a 0 if pressed. So as long as both whisker circuits are reporting a 1, no object collision has been detected.
while(1) // Outer loop { while((input(7) + input(8)) == 2) // Inner loop while whiskers not pressed {
The inner loop’s first line is all that is needed to receive information from the IR Remote. The sirc library’s sirc_button function decodes infrared patterns detected by the IR receiver, and returns the value corresponding to the remote control button. That value is assigned to the button variable. (If you want to use a different Propeller I/O pin with the IR receiver, change it here.)
int button = sirc_button(10); // check for remote key press
A series of if(button ==… statements comes next, and the one matching the current value of the button variable gets executed. For values 0-9, the audio file named in the wav_play function call is accessed from the microSD card and the Propeller chip generates the audio signals that are played on the veho360 speaker. The wavplayer library launches other Propeller cores to handle those tasks, so the audio files keep playing while the core executing the main function keeps the inner and outer loops looping.
// Audio responses - if number key pressed, play named WAV file if(button == 1)wav_play("hello.wav"); if(button == 2)wav_play("follow.wav"); if(button == 3)wav_play("byebye.wav"); if(button == 4)wav_play("oops.wav"); if(button == 5)wav_play("thankyou.wav"); if(button == 6)wav_play("dontknow.wav"); if(button == 7)wav_play("yes.wav"); if(button == 8)wav_play("no.wav"); if(button == 9)wav_play("maybe.wav"); if(button == 0)wav_play("electro.wav");
If the channel up/down, volume up/down, or mute button is pressed, the corresponding drive_rampStep function call sets the wheel speeds to make the robot move in the direction noted in the comment.
Since these are calls to drive_rampStep and not to drive_speed, a quick tap on the button will set a slower motion, but holding the button down for a moment longer will set a faster motion. Likewise, a quick tap on the mute button will slow down a motion, but you must hold the button down to stop.
The drive_rampStep function is part of the abdrive library, which uses a separate core to handle the servo motor and encoder control. So, the function call only needs to set the new direction, and the robot will continue on that course until a new IR button press sets a new direction. And, the core executing the main function is free to continue with the inner and outer while loops.
// Motion responses - if key pressed, set wheel speeds if(button == CH_UP)drive_rampStep(128, 128); // Forward if(button == CH_DN)drive_rampStep(-128, -128); // Backward if(button == VOL_DN)drive_rampStep(-128, 128); // Left turn if(button == VOL_UP)drive_rampStep(128, -128); // Right turn if(button == MUTE)drive_rampStep(0, 0); // Stop
Recall that the inner loop is conditional – it only repeats if neither one of the whisker touch-sensors is pressed. But if a whisker IS pressed, the code execution drops out of the inner loop to the code below. Here, drive_speed functions make the motors stop, back up quickly for 500 milliseconds, and stop again. Then, a call to wav_play makes the ActivityBot say “Ouch!”. The robot will not drive again until it receives another IR signal.
// Sensor response - if a whisker is pressed drive_speed(0, 0); // Stop driving drive_speed(-100, -100); // Back up 0.5 seconds pause(500); drive_speed(0, 0); // Stop driving wav_play("ouch.wav"); // Play named WAV file pause(1000); // Pause & return to outer loop } }
Here is the whole code listing at once:
/* AB-IR-Remote-Wav.c 10/30/2013 version 0.5 https://learn.parallax.com/activitybot ActivityBot plays WAV files on speaker from SD card Sensors: IR receiver on P10, touch whiskers on P7 & P8 Control with Sony-compatible remote (Parallax #020-00001) (Brightstar: hold Setup until lit, then enter 605) Drive with 5 buttons: Channel+/-, Vol +/-, and mute Number keys select WAV files to play If whiskers are pressed, robot backs up & stops, plays WAV */ #include "simpletools.h" #include "wavplayer.h" // Needs 0.9 or later #include "abdrive.h" // Needs 0.5.5 or later #include "sirc.h" int main() // Main - execution begins! { freqout(4, 2000, 2000); // Start beep - low battery reset alarm drive_speed(0,0); // Start servos/encoders cog drive_setRampStep(10); // Set ramping at 10 ticks/sec per 20 ms sirc_setTimeout(50); // Remote timeout = 50 ms int DO = 22, CLK = 23, DI = 24, CS = 25; // Declare SD I/O pins sd_mount(DO, CLK, DI, CS); // Mount SD card wav_volume(7); // Set vol here, 1 - 10 while(1) // Outer loop { while((input(7) + input(8)) == 2) // Inner loop while whiskers not pressed { int button = sirc_button(10); // check for remote key press // Audio responses - if number key pressed, play named WAV file if(button == 1)wav_play("hello.wav"); if(button == 2)wav_play("follow.wav"); if(button == 3)wav_play("byebye.wav"); if(button == 4)wav_play("oops.wav"); if(button == 5)wav_play("thankyou.wav"); if(button == 6)wav_play("dontknow.wav"); if(button == 7)wav_play("yes.wav"); if(button == 8)wav_play("no.wav"); if(button == 9)wav_play("maybe.wav"); if(button == 0)wav_play("electro.wav"); // Motion responses - if key pressed, set wheel speeds if(button == CH_UP)drive_rampStep(128, 128); // Forward if(button == CH_DN)drive_rampStep(-128, -128); // Backward if(button == VOL_DN)drive_rampStep(-128, 128); // Left turn if(button == VOL_UP)drive_rampStep(128, -128); // Right turn if(button == MUTE)drive_rampStep(0, 0); // Stop } // Sensor response - if a whisker is pressed drive_speed(0, 0); // Stop driving drive_speed(-100, -100); // Back up 0.5 seconds pause(500); drive_speed(0, 0); // Stop driving wav_play("ouch.wav"); // Play named WAV file pause(1000); // Pause & return to outer loop } }
You can use your own WAV files for this project. Give your ActivityBot a vocabulary all its own, add different music tracks, or even sound effects. Our Sound Library features easy how-to’s for using the free Audacity software:
Gather some friends, and see who is the best ActivityBot driver!
Remember this little piece of code, the inner while(… loop? ?
while((input(7) + input(8)) == 2) // Inner loop while whiskers not pressed
If you want to use a different sensor for object detection, this is the line to change. For example, instead of whiskers, let’s say you have a PING))) Ultrasonic Distance Sensor connected to P8. Provided you add #include “ping.h” to the top of your code, just replace that line with the following:
while(ping_cm(8) > 10) // Inner loop while no object within 10 cm
This will keep the inner loop looping as long as the measured distance returned by the PING))) sensor is greater than 10 cm.
Here are some helpful hints for using this activity in a classroom: