ActivityBot -- SIRC control + whiskers
There are sometimes questions about how to combine different lessons in the C-Learning Tutorials. The program below combines ActivityBot using the Sony IR remote control with Navigating by touch.
The hardware setup is the same as in the 2 tutorials. My wiring using the overlay board is here:
http://forums.parallax.com/discussion/comment/1337873/#Comment_1337873
There are 2 potentially tricky changes.
1. Since there is up to 1 second delay if no remote control button is pushed, and we want the response to hitting an object to be immediate, I run the whisker function in its own cog.
.
2. The SIRC command codes are based on my remote control (Sony RMT-DSLR1). If you are using a different remote, use the program in the SIRC tutorial
http://learn.parallax.com/propeller-c-simple-devices/ir-receiver-and-remote
to determine the codes your remote uses for the keys you want to use for each command. Then change the number in the remote control aliases define statements.
Note: that I've added a new version a few posts down that changes the codes to those used in a standard Sony TV remote.
Here's the code:
I hope you enjoy it.
Tom
The hardware setup is the same as in the 2 tutorials. My wiring using the overlay board is here:
http://forums.parallax.com/discussion/comment/1337873/#Comment_1337873
There are 2 potentially tricky changes.
1. Since there is up to 1 second delay if no remote control button is pushed, and we want the response to hitting an object to be immediate, I run the whisker function in its own cog.
.
2. The SIRC command codes are based on my remote control (Sony RMT-DSLR1). If you are using a different remote, use the program in the SIRC tutorial
http://learn.parallax.com/propeller-c-simple-devices/ir-receiver-and-remote
to determine the codes your remote uses for the keys you want to use for each command. Then change the number in the remote control aliases define statements.
Note: that I've added a new version a few posts down that changes the codes to those used in a standard Sony TV remote.
Here's the code:
/*
SIRC Remote control new a.c for overlay board
This worked - There is no delay between whisker touching and bot stopping.
Before using separate cog for whiskers, there was a noticible delay, and whisker fully
compressed before bot would stop.
This version stops, backs up, turns 90 deg from obstacle and stops.
Must press remote key to restart motion. Consider changes to allow continuing motion wo
need to press remote key.
Use multiple cogs - new cog to handle whiskers
Connect 38 kHz IR receiver to Propeller P10
Decodes button presses on Sony-compatible IR remote
Commands Activitybot to move straight, pivot 45 deg, move in a curve,
increase or decrease speed and curve radius, and stop.
Also has whisker code for obstacle avoidance.
This has ramping to speed. Increment = 4 ticks per 1/50 sec (4/0.020 sec).
To get from 0 to 100 takes 25 increments = 0.5 sec
Future: add code for autonomous movement selectable from remote,
Load EEProm and Run
*/
#include "simpletools.h" // Libraries included
#include "sirc.h"
#include "abdrive.h" // abdrive library
// ***** Remote control aliases -- uses Sony camera remote RMT-DSLR1 *****
#define fwd 58 // up arrow -- forward
#define stp 57 // center -- stop
#define rvs 59 // down arrow -- reverse
#define pl 62 // left arrow -- pivot left
#define pr 63 // right arrow -- pivot right
#define cvl 56 // menu -- curve left
#define cvr 61 // trash can -- curve right
#define ispd 74 // plus rocker -- increase speed
#define dspd 75 // minus rocker -- decrease speed
// ***** Pin Defines *****
#define spkrpin 3 // speaker pin for overlay board
#define SIRCpin 10 // SIRC input pin
#define Rwpin 8 // Right whisker pin
#define Lwpin 7 // Left whisker pin
int *cogwhisker; // pointers to cog IDs
void whisker(); // monitors whiskers, if hit: stops, backs away, turns away, runs in separate cog
volatile int bumpflg;
int Lspd, Rspd = 0; // Left and Right command wheel speeds
int main() // **** main function ****
{
int spd = 50; // initial speed once fwd command given
int dflg = 0; // flag: -1=fwd or rev, 0=stopped, 1=curve left, 2=curve right, 3=pivot L or R
drive_speed(0, 0);
sirc_setTimeout(1000); // -1 if no remote code in 1 sec
bumpflg = 0; // Gives control to remote
cogwhisker = cog_run(whisker, 100); // start monitoring whiskers
freqout(spkrpin,1000, 3000); // Speaker tone: 1 s, 3 kHz
while(1) // Repeat indefinitely
{
int button = sirc_button(SIRCpin); // get code from SIRC remote
switch(button) // decode signal from SIRC and calc drive command
{
case stp : // Center button - Q
Lspd = 0; // stop
Rspd = 0;
dflg = 0;
break;
case fwd : // Top Arrow - M
Lspd = spd; // forward
Rspd = spd;
dflg = -1;
break;
case rvs : // Down Arrow
Lspd = -spd; // reverse
Rspd = -spd;
dflg = -1;
break;
case pr : // Right Arrow - N
Lspd = 13;
Rspd = -13; // Pivot Right 45 deg & stop
dflg = 3;
break;
case pl : // Left Arrow - P
Lspd = -13;
Rspd = 13; // Pivot Left 45 deg & stop
dflg = 3;
break;
case cvr : // Curve Right - L
if (spd < 25) spd=25;
Lspd = spd;
Rspd = spd-20;
dflg = 2;
break;
case cvl : // Curve Left - K
if (spd < 25) spd=25;
Lspd = spd-20;
Rspd = spd;
dflg = 1;
break;
case ispd : // Up-Rocker - H -- Increase speed
if (dflg == 1) // curving left - increase spd and move in curve at new spd
{
spd=spd+5;
if (spd > 100) spd = 100;
Lspd = spd-20;
Rspd = spd;
}
else if (dflg == 2) // curving right - increase spd and move in curve at new spd
{
spd=spd+5;
if (spd > 100) spd = 100;
Lspd = spd;
Rspd = spd-20;
}
else if (dflg == -1) // straight ahead - increase spd and move at new spd
{
spd=spd+5;
if (spd > 100) spd = 100;
Lspd = spd;
Rspd = spd;
}
else
{
spd=spd+5;
if (spd > 100) spd = 100;
}
break; // Finish Up-Rocker
case dspd : // Down-Rocker -- decrease spd
if (dflg == 1) // curving left - decrease spd and move at new spd
{
spd=spd-5;
if (spd < 25) spd = 25;
Lspd = spd-20;
Rspd = spd;
}
else if (dflg == 2) // curving right - decrease spd and move at new spd
{
spd=spd-5;
if (spd < 25) spd = 25;
Lspd = spd;
Rspd = spd-20;
}
else if (dflg == -1) // straight ahead - decrease spd and move at new spd
{
spd=spd-5;
if (spd < 0) spd = 0;
Lspd = spd;
Rspd = spd;
}
else // stopped
{
spd=spd-5;
if (spd < 0) spd = 0;
}
break; // Finish Down-Rocker
default :
break;
} // end switch
if(dflg == 3) // execute pivot
{
if( ! bumpflg) drive_ramp(0,0); // stop for pivot, whiskers not controlling movement
if( ! bumpflg) // whiskers not controlling movement
{
drive_ramp(Lspd, Rspd); // now pivot 45 deg
pause(1000);
Lspd = 0; // and stop, executed with other drive cmds below
Rspd = 0;
dflg = 0;
}
}
if( ! bumpflg) drive_ramp(Lspd, Rspd); // execute drive comnd, whiskers not cntrling movement
} // end while
} // end main
void whisker() // If whisker pressed, stop & move away from obstacle:
// 1. disable SIRC control, 2. stop bot, 3. back up, 4. turn away from obstacle,
// 5. stop, 6. restore SIRC control
{
while(1)
{
// If whisker pressed, avoid obstacle.
// First just right whisker - input(8) is 0 if whisker is pressed
if(! input(Rwpin))
{
bumpflg = 1; // Set flag so main will not give conflicting drive commands
drive_speed(0,0);
drive_ramp(-60, -60); // Back up 0.5 seconds
pause(500);
drive_ramp(0,0);
drive_speed(-26, 26); // Turn left 1 seconds -- 90 deg
pause(1000);
drive_ramp(0, 0); // stop
}
// Just left whisker - input(7)
else if(! input(Lwpin))
{
bumpflg = 1;
drive_speed(0,0);
drive_ramp(-60, -60); // Back up 0.5 seconds
pause(500);
drive_ramp(0,0);
drive_speed(26, -26); // Turn right 1 seconds -- 90 deg
pause(1000);
drive_ramp(0,0); // stop
}
bumpflg = 0; // clear flag, allow main to have control
}
}
I hope you enjoy it.
Tom
Comments
Tom
I just noticed that in the program posted above all of the "<" and ">" operators had been changed to a combination of & lt and ; for < and similar for > probably during one of the forum upgrades.
I've fixed them in the program above.
Tom
1. It now uses a standard Sony TV remote. Previously I was using a Sony DSLR camera remote. The change was made by simply changing the values in the #DEFINE statements.
2. The "whisker" code now uses 'waitpne' instead of looping to check each whisker. waitpne halts the 'whisker' cog until there is a change in either pin that the whiskers are connected to.
/* SIRC TV Remote control 9.c for overlay board This worked - There is no delay between whisker touching and bot stopping. Before using separate cog for whiskers, there was a noticible delay, and whisker fully compressed before bot would stop. This version stops, backs up, turns 90 deg from obstacle and stops. Must press remote key to restart motion. Consider changes to allow continuing motion wo need to press remote key. Use multiple cogs - new cog to handle whiskers Connect 38 kHz IR receiver to Propeller P10 Decodes button presses on Sony-compatible IR TV remote Commands Activitybot to move straight, pivot 45 deg, move in a curve, increase or decrease speed and curve radius, and stop. Also has whisker code for obstacle avoidance. This has ramping to speed. Increment = 4 ticks per 1/50 sec (4/0.020 sec). To get from 0 to 100 takes 25 increments = 0.5 sec Future: add code for autonomous movement selectable from remote, Load EEProm and Run */ #include "simpletools.h" // Libraries included #include "sirc.h" #include "abdrive.h" // abdrive library // ***** Remote control aliases -- uses Sony TV remote ***** #define fwd 2 // #2 -- forward #define stp 5 // #5 -- stop #define rvs 8 // #8 -- reverse #define pl 4 // #4 -- pivot left #define pr 6 // #6 -- pivot right #define cvl 1 // #1 -- curve left #define cvr 3 // #3 -- curve right #define ispd 18 // plus volume -- increase speed #define dspd 19 // minus volume -- decrease speed // ***** Pin Defines ***** #define spkrpin 3 // speaker pin for overlay board #define SIRCpin 10 // SIRC input pin #define Rwpin 8 // Right whisker pin -- must be 1 pin number higher than Lwpin #define Lwpin 7 // Left whisker pin int *cogwhisker; // pointers to cog IDs void whisker(); // monitors whiskers, if hit: stops, backs away, turns away, runs in separate cog volatile int bumpflg; int Lspd, Rspd = 0; // Left and Right command wheel speeds int main() // **** main function **** { int spd = 50; // initial speed once fwd command given int dflg = 0; // flag: -1=fwd or rev, 0=stopped, 1=curve left, 2=curve right, 3=pivot L or R drive_speed(0, 0); sirc_setTimeout(1000); // -1 if no remote code in 1 sec bumpflg = 0; // Gives control to remote cogwhisker = cog_run(whisker, 100); // start monitoring whiskers freqout(spkrpin,1000, 3000); // Speaker tone: 1 s, 3 kHz while(1) // Repeat indefinitely { int button = sirc_button(SIRCpin); // get code from SIRC remote switch(button) // decode signal from SIRC and calc drive command { case stp : // Center button - Q Lspd = 0; // stop Rspd = 0; dflg = 0; break; case fwd : // Top Arrow - M Lspd = spd; // forward Rspd = spd; dflg = -1; break; case rvs : // Down Arrow Lspd = -spd; // reverse Rspd = -spd; dflg = -1; break; case pr : // Right Arrow - N Lspd = 13; Rspd = -13; // Pivot Right 45 deg & stop dflg = 3; break; case pl : // Left Arrow - P Lspd = -13; Rspd = 13; // Pivot Left 45 deg & stop dflg = 3; break; case cvr : // Curve Right - L if (spd<25) spd=25; Lspd = spd; Rspd = spd-20; dflg = 2; break; case cvl : // Curve Left - K if (spd<25) spd=25; Lspd = spd-20; Rspd = spd; dflg = 1; break; case ispd : // Up-Rocker - H -- Increase speed if (dflg == 1) // curving left - increase spd and move in curve at new spd { spd=spd+5; if (spd > 100) spd = 100; Lspd = spd-20; Rspd = spd; } else if (dflg == 2) // curving right - increase spd and move in curve at new spd { spd=spd+5; if (spd > 100) spd = 100; Lspd = spd; Rspd = spd-20; } else if (dflg == -1) // straight ahead - increase spd and move at new spd { spd=spd+5; if (spd > 100) spd = 100; Lspd = spd; Rspd = spd; } else { spd=spd+5; if (spd > 100) spd = 100; } break; // Finish Up-Rocker case dspd : // Down-Rocker -- decrease spd if (dflg == 1) // curving left - decrease spd and move at new spd { spd=spd-5; if (spd < 25) spd = 25; Lspd = spd-20; Rspd = spd; } else if (dflg == 2) // curving right - decrease spd and move at new spd { spd=spd-5; if (spd < 25) spd = 25; Lspd = spd; Rspd = spd-20; } else if (dflg == -1) // straight ahead - decrease spd and move at new spd { spd=spd-5; if (spd <0) spd = 0; Lspd = spd; Rspd = spd; } else // stopped { spd=spd-5; if (spd <0) spd = 0; } break; // Finish Down-Rocker default : break; } // end switch if(dflg == 3) // execute pivot { if( ! bumpflg) drive_ramp(0,0); // stop for pivot, whiskers not controlling movement if( ! bumpflg) // whiskers not controlling movement { drive_ramp(Lspd, Rspd); // now pivot 45 deg pause(1000); Lspd = 0; // and stop Rspd = 0; dflg = 0; } } if( ! bumpflg) drive_ramp(Lspd, Rspd); // execute drive comnd, whiskers not cntrling movement } // end while } // end main void whisker() // If whisker pressed, stop & move away from obstacle: // 1. stop bot, 2. disable SIRC control, 3. back up, 4. turn away from obstacle, // 5. stop, 6. restore SIRC control { // uses waitpne(wstate, wmask) int wmask = 1 << Rwpin | 1 << Lwpin; // build 32 bit int mask with whisker pin numbers int wstate = wmask; // in normal running both pins are high, hit whisker pin drops to low int RLval; while(1) // runs continuously { waitpne(wstate, wmask); //stop cog until a whisker is pressed RLval = get_states(Rwpin, Lwpin); // get whisker pin values bumpflg = 1; // Set flag so main will not give conflicting drive commands drive_speed(0,0); // stop drive_ramp(-60, -60); // Back up 0.5 seconds pause(500); drive_ramp(0,0); // and stop // ***** Check direction to turn ***** switch(RLval) // decode whiskers 0b00=both, 0b01=right, 0b10=left, 0b11=neither { case 0 : // *** both whiskers hit, turn right drive_speed(26, -26); // Turn right 1 seconds -- 90 deg break; case 1 : // *** Right whisker hit, turn left drive_speed(-26, 26); // Turn left 1 seconds -- 90 deg break; case 2 : // *** Left whisker hit, turn right drive_speed(26, -26); // Turn right 1 seconds -- 90 deg break; case 3 : // *** Neither whisker hit, don't turn break; } // end switch // now do the 1 second delay for the 90 degree turn pause(1000); drive_ramp(0, 0); // and stop Lspd = 0; // prevents bot from resuming last movement command in main Rspd = 0; bumpflg = 0; // clear flag, allow main to have control } // end while } // end whisker function