Dig Inside the Code
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.
Comments Count!
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 http://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"
Setup Tasks Get the Hardware Ready
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
Nested Control Loops
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 {
Decoding the Remote
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
Select a Sound
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");
Select a Motion
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
Dropping Out of the Inner Loop
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 } }
AB-IR-Remote-Wav Complete Code Listing
Here is the whole code listing at once:
/* AB-IR-Remote-Wav.c 10/30/2013 version 0.5 http://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 } }