Bluetooth App to control ActivityBot
twm47099
Posts: 867
Now that I have had my questions answered, I'd like to post a C-program that interfaces with a free android bluetooth joystick app to control the ActivityBot. The app is "Joystick BT Commander" by "Kas". It can be downloaded from GooglePlay. I'm using it on a Samsung Tablet 4, but the author says it works on a number of phones and tablets.
The link to the app is here:
https://play.google.com/store/apps/details?id=org.projectproto.btjoystick
The program below is setup to drive the ActivityBot using the joystick. There are 6 soft buttons on the app that can be used for any user defined function. I use 3 of them in the program to: end the program, as an emergency stop, and to turn ping on and off. The ping function is an example that simply lights the red and green channels of an RBG Led to show distance in front of the Bot to an object (<20cm = red, etc).
I intend to add my PIXY color tracking code as a function to be turned on and off using another button. When on, that code will take over driving the bot to go to a predefined colored object. The pixy code is at post 27 in:
http://forums.parallax.com/showthread.php/155501-Pixy-for-Propeller?p=1279736&highlight=pixy#post1279736
The comments in the code below explain the hardware connections and the BT commander data format. More info is available at the links on the app page on googleplay.
I hope that you find this interesting and something you can expand on.
Tom
The link to the app is here:
https://play.google.com/store/apps/details?id=org.projectproto.btjoystick
The program below is setup to drive the ActivityBot using the joystick. There are 6 soft buttons on the app that can be used for any user defined function. I use 3 of them in the program to: end the program, as an emergency stop, and to turn ping on and off. The ping function is an example that simply lights the red and green channels of an RBG Led to show distance in front of the Bot to an object (<20cm = red, etc).
I intend to add my PIXY color tracking code as a function to be turned on and off using another button. When on, that code will take over driving the bot to go to a predefined colored object. The pixy code is at post 27 in:
http://forums.parallax.com/showthread.php/155501-Pixy-for-Propeller?p=1279736&highlight=pixy#post1279736
The comments in the code below explain the hardware connections and the BT commander data format. More info is available at the links on the app page on googleplay.
I hope that you find this interesting and something you can expand on.
Tom
/* C code for use with Propeller ActivityBot and Joystick BT Commander android App by Kas - (c) T. Montemarano 2014-08-01, MIT License Tested with Samsung Tablet 4 2014-08-13 Deleted & from function name in cog_run statement, added 'flgping' flag to show when ping is running. 2014-08-12 Made global declaration of *cogping, increased cog stack sizes, fixed call to do_ping 2014-08-09 used 'volatile' in global declarations. Written for BT Commander V5 - Changed protocol -- need to do data TX to android coded BT button 6 as 'end' to terminate program coded BT button 5 as E-stop -- moving Joystick restarts movement coded BT button 2 to turn ping on and off Uncomment print statements and Run with terminal to debug or see command execution. App options setup Joystick Props -- behavior - deselect auto return to center constraint - box Buttons Props -- display 6 labels -- 1, 2 ping, 3, 4, - optional. 5 - E-stop, 6 - Quit (ends program) Advanced -- auto connect - on Refresh Interval - 100ms (works, but I am going to check out other values) 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. Try to tap the joystick position you want, since dragging results in a lot of data being sent to the ABot. (The app sends data when the position of the Joystick is changed) 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. This can be played with to get a good range Ping)) has signal connected to pin 5 with 2kohm resistor in series common cathode rbg led has red to pin 6 with 100 ohm resistor, green to pin 7 with 120 ohm resistor, cathode to gnd. To do: add pixy color tracking (use BT button 3) when active pixy tracking takes control and drives aBot to defined color object. The BT 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 nbytes; volatile int joydata; int flgping; int xval; int yval; int flgbt; int dist; int *cogping; fdserial *blut; void getbtjoy(); void do_ping(); int main() { freqout(4, 1000, 2000); // Speaker tone: 1 s, 2 kHz int x2; int y2; int xy; int yspd = 0; int xspd = 0; flgping = 0; // ping cog is not running cog_run(getbtjoy, 220); drive_ramp(0, 0); while(c0) { if(nbytes == 8 ) { pause(50); // try to get rid of pause xy = joydata; y2 = (xy & 511) - 200; x2 = (xy >> 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(nbytes == 3) { nbytes = 0; printi(" button = %d\n\n", c1[2]); if(c1[2]=='C') // Button 2, on turns on ping { cogping = cog_run(do_ping,120); printi(" ping cog = %d\n\n", *cogping); nbytes = 0; flgping = 1; // set flgping -- ping cog is running } if(c1[2]=='D' && flgping) // Button 2, off turns off ping, don't try to stop if not running { cog_end(cogping); nbytes = 0; flgping = 0; // clear flgping -- ping cog is stopped } } } // end while c0 drive_ramp(0, 0); // stop movement at end of program // printi(" end \n\n"); if(flgping) cog_end(cogping); // 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 { nbytes = 0; int i = 1; flgbt= 1; c1[1] = fdserial_rxChar(blut); // read first byte from blut if(c1[1] == 2) // if STX read next 7 bytes { flgbt = 1; while(flgbt) { i++; c1[i] = fdserial_rxChar(blut); if((c1[i]==3) && (i==3 || i==8)) flgbt=0; } // end while flgbt, android string i = 2 => button, i = 7 => x,y values if(i==8) { nbytes = 8; xval = (c1[2] - 48) * 100 + (c1[3] - 48) * 10 + (c1[4] - 48); yval = (c1[5] - 48) * 100 + (c1[6] - 48) * 10 + (c1[7] - 48); joydata=(xval << 10) | yval; } // end if i= 8 if(i==3) { nbytes = 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
Thanks for the code. I am starting a project right now that has to do with Bluetooth and using a mobile device/PC to talk to my Arlo, and it is not easy to do with Java. Hopefully this will lead me in the right direction.
Please keep me posted!
Andy,
I'm not sure, but I think it will if the EasyBT Din and Dout are connected to the pins noted in the comments in the code in my first post. The only other thing is that I use 115,200 baud in the beginning of the getbtjoy() function:
I don't know if the easyBT module can use that baud. If not just change the value in the fdserial_open statement.
(115,200 was the default baud for the RN42 module, and I didn't feel like changing it.)
Please let me know if it works.
Tom
In the code below, turning on soft button #3 turns off the ping LED function, disables joystick control, and turns Pixy control on.
The way I use it is to teach Pixy the color of the object I want it to find. Drive the ActivityBot to a location where the object can be seen by the Pixy, although not in the field of view of the lens. Then I press soft button #3 until it lights (if already lit I press 2xs). The ABot beeps and then starts to search for the object. When it locates it, the Bot will travel towards it, correcting its approach as it gets closer. When it gets within a couple of inches, the Bot will beep 3xs and stop. Turning button 3 off will reenable the joystick and the Bot can again be manually driven. Pressing button will end he program.
I have Ping mounted at the front of my bot on the pring backet and the Pixy on top of the Ping bracket using a small piece of stiff plastic sheet. To rebalance the Bot, I've added the Speaker to the back, but some weights hangingoff the rear standoffs also works.
All of the standard Pixy issues remain - I've found it best to train Pixy using the push-button method under the same lighting as will be used for tracking. It uses Pixy interface mode 3 -- voltage corresponding to x-position of largest object
Pixypin 1 -- abot adc0, Ppin2 -- +5v, Ppin3 -- adc1, Ppin6 -- gnd.
Color needs to be unique and large enough to see at a distance. Laser pointer dot is too small.
I've got some more optimizations to do, but this works. The code follows:
Tom
Would you mind if I borrowed snippets of your code for my project?
collect2: ld returned 1 exit statusDone. Build Failed!
Check source for bad function call or global variable name `_printi'
C:\Users\ANDYN~1.NWU\AppData\Local\Temp\cc131wmG.o: In function `.L39':
(.text+0x1ca):
I am using SimpleIDE.
You can use the code as you want.
Tom
Andy,
I'm not sure I understand what the error is. Is it the 'printi' function or the '} // end while' ?
I just started using printi after Steve (Jazzed) told me it used less memory than 'print'. It actually saves about 5k.
The ' } // end while ' is just the closing brace for the while(1) statement and a comment to help me keep track of braces.
I copied the code from post #1 and pasted it into a SimpleIDE new project (first deleting all of the stuff that SimpleIDE loads into a new project), and built the program on a PC that has SimpleIDE installed (no prop board attached.) It built without any errors.
I am using the latest version of the Learn Libraries.
Clicking on the icon in the lower left corner of the SimpleIDE screen, I have:
Project Options:
Board Type: Activity Board
Compiler: C
Memory Model CMM Main Ram Compact
Optimization Os-Size
Compiler:
Checked: 32bit doubles
Other compiler options: -std=c99
Linker:
Checked: math lib
I hope this helps.
Tom
http://learn.parallax.com/propeller-c-set-simpleide/update-simpleide-workspace
Andy
- cleaned up some code and comments
- changed the adc function I used to the one that returns raw values - everything integer and saved about 1k memory.
- Added a second movement control function to the Pixy code. The original (control1()) just uses a constant rotation increment - small enough to minimize overshoot. The new one (control2()) uses proportional control with larger rotation when further away from center. The control method defaults to control1(), but button 4 turns control2() on or off. The control method can be changed anytime, including when pixy is searching. The p26 and p27 LEDs light when the Pixy functions are running to show which method is being used:
Both OFF = object out of FOV and findsig() is running, One one = control1, Both on = control2.
- The control2() constants are set up as #define vales at the beginning of the program so the user can try different values. To get more granularity, I might change that code to floating point, but for now it is integer. The values in the program work.
- added code at the start to send a string to the android device to set all buttons to off.
- moved the starting 'beep' so that when it sounds, the joystick is active (no more delay after the beep).
The latest version of the BT app has a zero button which centers the joystick, and essentially acts as an emergency stop. I'm trying to come up with a method to use the remaining buttons (once I get rid of the E-stop code) and the joystick to change the proportion control constants. The idea is to be able to change them without recompiling and loading the prop. Not sure how yet.
The revised program follows.
Tom
The new version uses the Pixy UART mode. This mode sends all defined signatures as a series of 2 byte values. It sends lowest byte of each word first. Pixy sends serial data as a Frame made up of Blocks of data.
Each Block is a detected object. The format of a block is the start word 0x55, 0xAA (or AA55 when made into one 16 bitword); the next word is a checksum = the sum of the next 10 bytes. The 3rd word is the signature number. (Pixy can be taught up to 7 colors, signatures are numbered 1 to 7). The 4th word is the x value (horizontal location in the field of view); the 5th is the y value; the 6th is the horizontal size, and 7th is the vertical size.
The start of a new Frame is an additional start word 0xAA55. So to determine the start of a frame the program has to look for the serial sequence 0x55, 0xAA, 0x55, 0xAA.
The biggest difficulty using Pixy data is that it is continuously sending data, and every 20ms it starts a new Frame (even if part way through a Block -- it just discards the remaining data from that block). If the user program could tell Pixy to start sending a Frame, or if the Frame start word was different from the Block start word, it wold be much less complicated.
Along with changing to use the Pixy UART, the program has added the ability to move one of 3 defined colors (signatures 1, 2, or 3). The target signature can be changed at any time (even while the Bot is chasing a color) by pressing soft button 1 on the android device. Each press cycles the number 1, 2, 3, 1, etc. The active signature number is shown in the data display in the lower left of the screen.
Other changes are the button lights on the android screen are cleared (made dim) at the start of the program, and are updated to show what is on and what is off.
I'm going to post the beginning comments in this post and the actual program in the following post because it is large.
Tom
Tom
I assume you are asking about the blue tooth to Activity board (not the Pixy to Activity Board). The Sparkfun RN 42 module uses the designations DO and DI. It also defaults to 115200 baud.
"Uses RN42 Blutooth module. I'm using Sparkfun part that has same form as X-Bee socket. Connect Bluetooth DO to Activity Board pin 9 (will be Propeller Rx), Bluetooth DI to Prop pin 8 (will be Prop Tx)"
I use this command to start the communication:
If you want to use different pins, just change the values in: fdserial_open(9, 8, 0, 115200);
Hope this helps
Tom
Mine did. I wrote my code in Spin which can be found in this thread:
-- http://forums.parallax.com/showthread.php/159920-Android-Control-of-Propeller-using-Joystick-BT-Commander-App-Spin-Code
Note that my code is not driving an ActivityBot yet -- will do that while watching the Super Bowl. As I like to take things in steps, I wrote program that has the core functionality to deal with JBTC. For the time being, it reports data to the screen, sends data back, and controls the LEDs on the PAB using buttons from JBTC. I think it proves that everything works
Your app from Post #1 is really nice! I just showed some of our techs and education staff, and they all really liked it.
Sheesh, I can't believe this has been gathering dust tucked away in a forum post for more than a year. Mind if we publish an ActivityBot project with a paired down version of the code? Attribution to your forum handle or elsewhere? Please send me a PM with any specifics.
For anyone using the RN-42 Bluetooth module, make sure to enable Auto Discovery with a jumper over position-2 (2nd from right). The other three configuration settings should have no jumpers.
Andy
Andy,
I just want to clarify, the C code is mine, and you can use it as you like. One of the things I was doing with that code was learning how to start, stop, and restart cogs.
The author of the android app is 'Kas'; he has an account on these forums and did some projects with the Basic Stamp. Since then he is an arduino user and has a long thread regarding his app at:
http://forum.arduino.cc/index.php?PHPSESSID=oshm7d4o43o9vh1f3f70jo7l76&topic=173246.285
He gave me a lot of help to understand his code. I'm sure he would be very happy to have more exposure for his app.
The detailed information on the data formats sent from the android to the micro-controller and from the micro to the android is shown in his post here:
http://forum.arduino.cc/index.php?topic=173246.msg1766491#msg1766491
Note that in posts 14 and 15 of this thread, I added code to send data (button status and data) from the Propeller to the android device. It sets the buttons to lit or grey and lists simple data on the android device. You might want to add code like that to a later segment of your project.
(In posts 14-15 the major complication is the code to get data that controls the ActivityBot from the CMUCAM5 (Pixy) color tracking device. I've used Prop to Pixy interfacing via the ActivityBot ADC and using a UART connection, I'm slowly working on code to use Pixy's SPI interface with the SPI PASM library you helped me develop. -- the problem with that is the Pixy developers keep updating their protocols -- Removing the pixy functions simplifies the code a lot.)
Tom
I would like gige to you Thanks for all your Effors to do this wonderful project i have used it .
I appressiate you shows it in Parallax Forums.
Thanks Very Much. my Respects an my aknowlements to you.
my best regards.
Eng. Jesus Perez Carreño (Mexico)
P.D. Very sorry for my poor English