Question re cog_run and cog_end
twm47099
Posts: 867
I am having some difficulty understanding starting and stopping cogs using cog_run and cog_end.
The program below runs the ActivityBot using a bluetooth joystick controller app of an android tablet. I run the serial communication with the android tablet from a function (getbtjoy) in a separate cog. I use cog_run to start it and don't ever stop it. That works well.
I added a function (do_ping) in a new cog to use ping to measure distance and control an RBG Led as distance to an object decreases (green >= 12 inches, yellow < 12 in., red < 5in.) I use the soft buttons in the app to turn the ping cog on and off.
I had a few problems with that. There are 2 blocks of code below set off by // ***** where the problem code is / was located. I tried a few different things, but what I have now works. But I don't understand why the other methods didn't.
First, I attempted to have "int *cog = cog_run(&do_ping,20); and cog_end(cog) in the conditionals (second group of // *****) without previously declaring int *cog. I got errors during the build for not having cog previously declared.
I guessed that had to do something with them being in conditional statements. Is that correct?
Then I added the code (now commented out) in the first group of // *** that declared int *cog; and cog = 0; (I tried a few variations of this). The program built and ran, but once I turned on PING I could not turn it off and sometimes it would prevent anything else from running (no joystick or button control).
Then I added the cog_run, pause, cog_end code in the beginning and took out the previous declarations. Now everything runs well, although I get a brief ping response at the start. Once do_ping is started using a button, I can turn it off and on with button presses as desired.
I would like to be able to run this without having to initially run and end the do_ping cog. Can you explain why the declaration method didn't work and if it is possible to remove the initial cog_run and cog_end?
Thanks
Tom
The program below runs the ActivityBot using a bluetooth joystick controller app of an android tablet. I run the serial communication with the android tablet from a function (getbtjoy) in a separate cog. I use cog_run to start it and don't ever stop it. That works well.
I added a function (do_ping) in a new cog to use ping to measure distance and control an RBG Led as distance to an object decreases (green >= 12 inches, yellow < 12 in., red < 5in.) I use the soft buttons in the app to turn the ping cog on and off.
I had a few problems with that. There are 2 blocks of code below set off by // ***** where the problem code is / was located. I tried a few different things, but what I have now works. But I don't understand why the other methods didn't.
First, I attempted to have "int *cog = cog_run(&do_ping,20); and cog_end(cog) in the conditionals (second group of // *****) without previously declaring int *cog. I got errors during the build for not having cog previously declared.
I guessed that had to do something with them being in conditional statements. Is that correct?
Then I added the code (now commented out) in the first group of // *** that declared int *cog; and cog = 0; (I tried a few variations of this). The program built and ran, but once I turned on PING I could not turn it off and sometimes it would prevent anything else from running (no joystick or button control).
Then I added the cog_run, pause, cog_end code in the beginning and took out the previous declarations. Now everything runs well, although I get a brief ping response at the start. Once do_ping is started using a button, I can turn it off and on with button presses as desired.
I would like to be able to run this without having to initially run and end the do_ping cog. Can you explain why the declaration method didn't work and if it is possible to remove the initial cog_run and cog_end?
Thanks
Tom
/* C code for use with Propeller ActivityBot and Joystick BT Commander App by Kas - used with Samsung Tablet (c) T. Montemarano 2014-08-01, MIT License Written for BT Commander V5 - Changed protocol -- need to do data TX to android coded button 6 as 'end' to terminate program button 5 as E-stop button 2 as Ping start - stop Uncomment print statements and Run with terminal and switch at 1 to debug App options setup Joystick Props -- behavior - deselect auto return to center constraint - box Buttons Props -- display 6 Advanced -- auto connect - on Refresh Interval - 100ms Timeout - Off Uses RN42 Blutooth module. I'm using Sparkfun part that has same form as X-Bee socket Connect BT DO to pin 9 (Will be Propeller Rx), BT DI to Prop pin 8 (will be Prop Tx) Need to pair RN42 to android BT and connect (with ABot switch in position 1) To run ActivityBot Load to EEPROM, switch to 2, ABot will beep (piezo setup as in Learn examples) After the beep and a second or so, the ABot will respond to the Joystick. Joystick data is x = -100 (Full Left), y=-100 (Full down), x=+100 full right, y=+100 full up. The buttons are decoded as Ascii 'A' Button 1 lit, 'B' 1 grey, 'C' 2 lit, etc. Button code is sent when button is pressed. The Joystick zones are setup as approx +/- 15 y = 0 speed, +/- 15 x = drive straight fwd or back. abs(y) >15 = move fwd (JS positive), move backwards (JS negative), Abs(x) > approx 15 = add differential to y speed to turn or pivot (x positive -turn right. Both x and y are scaled to set max speed and turning rates in the calculations of x2 and y2. The app is free on Googleplay 'joystick BT Commander". The link on the app page leads to the details regarding the data protocols used. */ #include "simpletools.h" #include "fdserial.h" #include "abdrive.h" #include "ping.h" volatile char c1[9]; volatile int c0 = 1; volatile int a; volatile int joydata; int x; int y; int z; int dist; fdserial *blut; void getbtjoy(); void do_ping(); int main() { freqout(4, 1000, 2000); // Speaker tone: 1 s, 2 kHz int x2; int y2; int xyval; int yspd = 0; int xspd = 0; cog_run(&getbtjoy, 22); drive_ramp(0, 0); // ****************************************************************************** // int *cog; // needed to declare cog outside of conditional int *cog = cog_run(&do_ping,20); // need this and the next 2 statements? pause(50); cog_end(cog); // cog=0; // ********************************************************************************* while(c0) { if(a==8) { pause(50); // try to get rid of pause xyval = joydata; y2 = (xyval & 511) - 200; x2 = (xyval >> 10) -200; printi("x = %d\n", x2); printi("y = %d\n", y2); yspd = (abs(y2) / 15)* 15; // scale the fwd & rev motion if(y2 <0) yspd = yspd / -2; // go slower in reverse xspd = (abs(x2) / 15) * 4; // scale the turning if(x2<0) xspd = xspd * -1; printi(" left right %d %d\n",yspd+xspd, yspd-xspd); drive_ramp(yspd+xspd, yspd-xspd); // drive, turning differential added to yspd } if(a==3) { a=0; printi(" button = %d\n\n", c1[2]); // ************************************************************** if(c1[2]=='C') // Button 2, on turns on ping { *cog = cog_run(&do_ping,20); a=0; } if(c1[2]=='D') // Button 2, off turns off ping { cog_end(cog); a=0; } // ************************************************************** } } // end while c0 drive_ramp(0, 0); // stop movement at end of program // printi(" end \n\n"); cog_end(cog); // if ping running when quit is pressed, turn off } // end main void getbtjoy() { // fdserial * fdserial_open(int rxpin, int txpin, int mode, int baudrate) blut = fdserial_open(9, 8, 0, 115200); while(c0) // continue until button 6 - quit - is pressed { a=0; int i = 1; z = 1; c1[1] = fdserial_rxChar(blut); // read first byte from blut if(c1[1] == 2) // if STX read next 7 bytes { z = 1; while(z) { i++; c1[i] = fdserial_rxChar(blut); if((c1[i]==3) && (i==3 || i==8)) z = 0; } // end while z, android string i = 2 => button, i = 7 => x,y values if(i==8) { a=8; x = (c1[2] - 48) * 100 + (c1[3] - 48) * 10 + (c1[4] - 48); y = (c1[5] - 48) * 100 + (c1[6] - 48) * 10 + (c1[7] - 48); joydata = (x << 10) | y; } // end if i= 8 if(i==3) { a=3; // printi(" button = %d\n\n", c1[2]); } if((i==3) && (c1[2]=='K' || c1[2]=='L')) // Button 6, ends program { c0 = 0; //printi(" end \n\n"); } if((i==3) && (c1[2]=='I' || c1[2]=='J')) { //E-stop on button 5 press, using JS restarts movement drive_ramp(0, 0); } } // end if c1=2 } // end while c0 } // end getbtjoy void do_ping() { while(1) { dist = ping_cm(5); if(dist<=20) // turn on red LED { high(6); low(7); } else if(dist<=36) // turn on yellow LED { high(6); high(7); } else // turn on green LED { low(6); high(7); } pause(50); } // end while }
Comments
That method used: int cog = cogstart(&blink, NULL, stack, sizeof(stack));
I added in the statements for stack size and changed the function parameters to correspond with those required by that method (including changing &blinky to &go_ping). When I called it in the program above, Ping and the RBG LED turned on and detected distance, but it prevented anything else from being controlled. I couldn't find a cogstop function in the library so I couldn't try stopping the Ping cog.
Any suggestions.
Tom
P.S. I marked changes with comments that have // <-- and/or // -->
Andy,
Thanks for the help. As you stated, the solution was declaring as a global and removing the * from 'cog' when the function is called in the conditional. I tried reducing the stack size to what i orignally had and it still worked. But since the effect on code size is negligible, for the final version, I kept them as you suggested.
Do you think it would be useful to post the final code once I clean it up (using bluetooth to control activityBot) and if so in which forum?
I still get confused about pointers and when to use * and &. Maybe a pointer tutorial for the C - Learning system would be useful?
Thanks again,
Tom
Ah, good, thanks for the update. I'm glad that cleared it up. Yes, a tutorial on pointers would be in order. The suggestion is causing a traffic jam of bad pun titles in my head though, starting with Pointers on Pointers. Yes, it would be great if you posted the final project. The Projects forum came to mind first, but this (Learn) and Robotics are also good candidates. Your call.
Andy
Andy
Dave and Andy,
I tried my program without the & for each cog_run, and as Dave stated it worked the same as with them.
Tom
I found another issue and have a question.
If ping was running when ending the program by pressing the exit button on the bluetooth device, ping kept running after the main program had ended. So I had added a cog_end(cog) just before the last } of main. That is in the in the code you had marked up.
But I found that sometimes restarting the code (pressing the reset button and having code reloaded from eeprom), that pressing the ping button on the BT device would not restart ping and the program would no longer accept any commands from the BT device.
The ping button on the BT device is a toggle and the first time pressing the button if ping had been running when exit was pressed would be ping stop. So the program was trying to stop a cog that had not been started. To fix that I added a flag "w" that was reset to 0 at the start of main, set to 1 when do_ping was started, and reset to 0 when do_ping was stopped. When receiving a command to end ping I added a test for w. The code segments that were changed are below.
But that leads to another question. Since the ping cog kept running when main ended, I assume that the getbtjoy() cog is also still running. When I press reset I believe it stops, but is there any reason to stop it before ending main??
These are the code changes to not try to stop a non-running do_ping()
Tom
Whether or not to shut down your peripheral cogs depends on whether or not the application needs to continue running after the main function has stopped. Another thing to consider would be if a device can enter a state that the main function cannot bring it back from during initialization. For example, let's say the initialization sends a sequence to the device that would only make sense if the device had been properly shut down previously. A power reset might put the device into the receptive state, but pressing and releasing the RST button might not. So, if your application expects that the RST button might be pressed and released, the initialization sequence will need a way to wake the device back up.
There are some delays built into the beginning of the program that can add up. There is a 0.7 second delay built into simpletools to prevent Windows machines from mistaking print messages from the Propeller as messages from a plug and play serial mouse. The abdrive library could also stand to load calibration data more quickly (it's on my list). So, if certain tasks are performed before that, the main function might miss them.
Andy