How Does it All Work Together?

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
  }            
}