Yet Another DIY Bluetooth RC Car

Got a cool robotic project you've been working on that you want the rest of the world to know about? Post pictures, descriptions and links here, and let us see. :)

Yet Another DIY Bluetooth RC Car

Postby el_es » Sat Feb 07, 2015 3:38 pm

Hi,
bought the Dagu Mini Driver and Bluetooth Module recently,
to turn an old 27MHz analog receiver RC car into a 21st century toy :) after the original control board (or the rc transmitter) broke...

I went as far as having Arduino IDE installed, I (ab)used the serial-event example program (erm sorry I'm old-fashioned, i write programs, not sketches...) and I got it going ! on usb serial AND on Bluetooth through PuTTY :)

Currently my program uses the 2 PWM motor controls to control the 2 motors: one propulsion motor, driving rear wheels, one direction motor, directly attached to the steering rack (which was a bit of my downfall but that'll come later...)

It's fun to control my car now : just write f0...ff or b0..bf to serial port for forward/backward motion (first character is direction, second is controlling the PWM in 1/16 increments ;) ) or l0..lf and r0..rf for left/right accordingly :)

Plan is to have an Android app that will do it (and use my tablet/phone accelerometer/gyroscope) to actually act as a steering wheel.
OH Yes I know there are tons of such projects on the appstore... in fact one such project actually inspired me to do this :)

So more is to come (hopefully) :) only now I need to get myself ISP programmer (or buy another mini-driver, or send the current board back to DR... for bootloader refresh) : one of the motors drew so much current in stall condition, that supply (car has space for 4xAAA cells only...) dropped and the bootloader botched itself. Oddly the arduino program still works, but cannot be reprogrammed any more :( fails verification.
For the arduino program I still need to implement safety features (like, automatic stop when lost serial contact) and un-n00b it a bit (chartoint function anybody? :) )
I'll post more when I have more :)
el_es
 
Posts: 22
Joined: Sat Feb 07, 2015 3:12 pm

Re: Yet Another DIY Bluetooth RC Car

Postby Alan » Tue Feb 10, 2015 6:35 pm

Hi there,

Welcome to the forum. :) Your project sounds cool, any chance of some pictures?

Sorry to hear that your bootloader has got corrupted. If you can get access to another Arduino, then that's probably the easiest way to fix it. Alternatively you can also fix it with a Raspberry Pi.

Regards

Alan
Alan
Site Admin
 
Posts: 311
Joined: Fri Jun 14, 2013 10:09 am

Re: Yet Another DIY Bluetooth RC Car

Postby el_es » Wed Feb 11, 2015 12:11 am

Got myself this instead:
Code: Select all
http://www.amazon.co.uk/gp/product/B00S4AO6W6?psc=1&redirect=true&ref_=oh_aui_detailpage_o00_s00
(usage of code tag intentional) ;) because I don't have a RaspberryPI on hand unfortunately.

Pictures are in the making :)
el_es
 
Posts: 22
Joined: Sat Feb 07, 2015 3:12 pm

PICS!

Postby el_es » Wed Feb 11, 2015 8:16 pm

Image
the donor car, with A4 paper for scale.

Image
with the mini-driver also for scale

Image
bonnet off, the mindriver on cables

Image
close-up on cavity where minidriver will be eventually fitted - the plastic nuts are from it's package, very helpful.

(gosh I wish I resized them to forum size :(
EDIT: I Have Resized them now...)
el_es
 
Posts: 22
Joined: Sat Feb 07, 2015 3:12 pm

Re: Yet Another DIY Bluetooth RC Car

Postby el_es » Fri Feb 13, 2015 11:36 pm

SerialEventDrivenCar.ino :
Code: Select all
/*
   Heavily Based on the Serial Event Arduino example
   (I took the example and heavily extended it)
   Is usable but lacks safety features (like fast stop or runaway prevention,
   or voltage measurements or... )
   Use at your own risk!
   Apply reason when copying!
   This code is public domain as the original was.
 
   Car has a rear drive motor and NO SERVO,
   steering motor is directly driving the steering rack,
   against the steering spring,
   which /could/ make it work for granularity of angle;
  (only it needs at least 5 AAA batteries supply to prevent voltage from falling below 5V regulator threshold
   when either motor is stalled)   
  (car only has space for 4)
  (or maybe just a nano size boost-mode UBEC to replace linear 5v reg  on board?)
  (like the one for RasPI)

   receives 2 char command
   commands are:
   F0 - FF = forward motion, in 16 steps 0-f
   B0 - BF = backward motion, in 16 steps 0-f
   L0 - LF = left turn in 16 steps 0-f
   R0 - RF = right turn in 16 steps 0-f
   S + any char = stop propulsion
   SN = stop propulsion and turn off direction motor
   Program accumulates 2 characters in a string, then passes them over to the
   command recognition = no need for /n
   commands can also be given in lower case (f0-ff,b0-bf,r0-rf, l0-lf, s_, sn)
   Program echoes to serial what it has received so sender can catch if the
   commands happen to desync.
   (it could be happening when the command string is handled and another starts
    being received, there is a window for this and I've seen it happening)
 */

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is received complete

int led = 13;  // leftovers from tryouts
int ledstate = 0; // led initially off

int DirMotorSpeedPin = 9;   // on DAGU Mini-driver DG-0813, ML PWM pin
int DirMotorDirecPin = 7;   // on DAGU Mini-driver DG-0813, ML h-bridge direction

int PropMotorSpeedPin = 10;   // on DAGU Mini-driver DG-0813, MR PWM pin
int PropMotorDirecPin = 8;    // on DAGU Mini-driver DG-0813, MR h-bridge direction

int firstrun = 0;

//variables to hold selected PWM pin, the selected PWM's direction,
int CommandingPWM = 0;
int CommandingDir = 0;
// and what actually to write to them
int DirectionCommand = 0;
int SpeedCommand = 0;

void setup() {
  pinMode(led, OUTPUT);
  pinMode(DirMotorSpeedPin, OUTPUT);
  pinMode(DirMotorDirecPin, OUTPUT);
  pinMode(PropMotorSpeedPin, OUTPUT);
  pinMode(PropMotorDirecPin, OUTPUT);
  // initialize serial:
  Serial.begin(9600);
  // reserve 10 bytes for the inputString: // original was 200 bytes, no need for that much
  inputString.reserve(10);
 
}

void toggle_LED() {
 if (ledstate == 0) ledstate = 1; else ledstate = 0;
 digitalWrite(led,ledstate);
}

int letterToPWM(char inputChar) {
      // TODO : replace with 'return hexchartoint(upcase(inputChar))*17' ;
      // but this may actually be quicker as it's just a lookup
      switch (inputChar){
      case '0' : return 0; break;
      case '1' : return 17; break;
      case '2' : return 34; break;
      case '3' : return 51; break;
      case '4' : return 68; break;
      case '5' : return 85; break;
      case '6' : return 102; break;
      case '7' : return 119; break;
      case '8' : return 136; break;
      case '9' : return 153; break;
      case 'a' :
      case 'A' : return 170; break;
      case 'b' :
      case 'B' : return 187; break;
      case 'c' :
      case 'C' : return 204; break;
      case 'd' :
      case 'D' : return 221; break;
      case 'e' :
      case 'E' : return 238; break;
      case 'f' :
      case 'F' : return 255; break;
    }
}

int inputstringlen = 0;

void loop() {
  // when program runs first time, tell the other side we are here
  // TODO: actually output 'firmware' version
  if (firstrun ==0 ) {
    Serial.println("Car ready");
    firstrun = 1;
  }
  if (stringComplete) {
    // echo out the captured string
    Serial.println(inputString);
       
    // look up the first character and
    // select pin and speed to be changed
    // the DirectionCommand in either propulsion or direction case
    // here has been established experimentally :)
    switch(inputString.charAt(0)) {
      case 'F' :
      case 'f' : { // forward propulsion
        CommandingPWM = PropMotorSpeedPin;
        CommandingDir = PropMotorDirecPin;
        DirectionCommand = 1;
        SpeedCommand = letterToPWM(inputString.charAt(1));
      }
      break;
     
      case 'B' :
      case 'b' : { // backward propulsion
        CommandingPWM = PropMotorSpeedPin;
        CommandingDir = PropMotorDirecPin;
        DirectionCommand = 0;
        SpeedCommand = letterToPWM(inputString.charAt(1));
      }
      break;
     
     
      case 'R' :
      case 'r' : { // right direction
        CommandingPWM = DirMotorSpeedPin;
        CommandingDir = DirMotorDirecPin;
        DirectionCommand = 0;
        SpeedCommand = letterToPWM(inputString.charAt(1));
      }
      break;
   
      case 'L' :
      case 'l' : {  // left direction
        CommandingPWM = DirMotorSpeedPin;
        CommandingDir = DirMotorDirecPin;
        DirectionCommand = 1;
        SpeedCommand = letterToPWM(inputString.charAt(1));
      } 
     
      break;       
     
      // this has compiled but bootloader refused to work all of a sudden
      case 'S':
      case 's':{
        CommandingPWM = PropMotorSpeedPin;
        CommandingDir = PropMotorDirecPin;
        DirectionCommand = 0;
        SpeedCommand = 0;
        // TODO: enable the below to catch 'sn' case where both direction and propulsion are off
        //if (inputString.charAt(1) == 'n' || inputString.charAt(1) == 'N'){
          // special case, turn direction motor off
        //  analogWrite(DirMotorSpeedPin,0);
        //  digitalWrite(DirMotorDirecPin,0);
        //}
       
      } 
      break;
    }
    // use the CommandingDir pin to select the right direction output,
    // and change it
    digitalWrite(CommandingDir, DirectionCommand);
    // use the CommandingPWM pin to select desired speed,
    // and set it accordingly
    analogWrite(CommandingPWM, letterToPWM(inputString.charAt(1)));
   
    // echo the captured string out again
    Serial.println(inputString);
    // clear the string:
    inputString = "";
    inputstringlen = 0;
    stringComplete = false;
   
  }
}

/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
 


void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // increase length counter
    inputstringlen += 1;
 
    // if we accumulated 2 characters in the string,
    // tell the main loop it's ready
    if (inputstringlen == 2) stringComplete = true;
   
  }
}



el_es
 
Posts: 22
Joined: Sat Feb 07, 2015 3:12 pm

Re: Yet Another DIY Bluetooth RC Car

Postby Alan » Sun Feb 15, 2015 12:47 pm

Wow,

Just logged onto the forum for the first time in 4 days and seen this. Thanks for the pictures, and code, it looks great, and I'm now quite tempted to get hold of an RC car to try it for myself. :) It's a pity that time is in such short supply...

Alan
Alan
Site Admin
 
Posts: 311
Joined: Fri Jun 14, 2013 10:09 am

Re: Yet Another DIY Bluetooth RC Car

Postby el_es » Sun Feb 15, 2015 6:01 pm

Yeah time is what I don't have much either ;)

Still todo (when I receive my isp programmer):

- test the immediate stop, enable & compile & test the stop&neutrum command
- implement&test anti-runaway & proper handling of reset condition
- write android app to control :)
el_es
 
Posts: 22
Joined: Sat Feb 07, 2015 3:12 pm

Re: Yet Another DIY Bluetooth RC Car

Postby el_es » Fri Feb 20, 2015 1:51 am

New version : SerialEventDrivenCar2.ino
Code: Select all
/*
   Heavily Based on the Serial Event example
   (Public domain as the original was.)
   (Apply reason when copying, use at your own risk !)
   Changes from version 1 :
   - fix command queuing : now the serialEvent only adds characters to the end of string
     and the loop() only removes them from the beginning of string
     so we have primitive FIFO command buffer / queue
   - use more constant declarations
   - split subroutines into self-contained functions
   - changed forward/backward char codes to P and T instead of F and B
     (because both f and b are in the hex characters range)
   - implement s as single char command
   - implement v as single char command
TODO still :
   - implement auto-stop / anti runaway protection
   

  *                       *                                 *
   Car has a rear drive motor and NO SERVO,
   forward motor is directly diving the steering rack,
   the steering motor works against the steering spring,
   which could make it work for granularity of angle;
   
   receives command of 1 or 2 characters
   commands are:
   P0 - PF = forward motion, in 16 speeds 0-f
   T0 - TF = backward motion, in 16 speeds 0-f
   L0 - LF = left turn
   R0 - RF = right turn
         for turning command, 0-f sets steering motor speed / stall force
   S = put all motions to a stop / turn both motors off
   V = return version and supported commands;
        here '1.0-PTRLsv' indicates fw 1.0 and PTRL commands using 2 chars, s and v using 1 char
   Either Command and Speed characters can also be lower-case.
 */

String inputString = "";         // a string to hold incoming data

const int DirMotorSpeedPin = 9;   // on DAGU Mini-driver DG-0813, ML PWM pin
const int DirMotorDirecPin = 7;   // on DAGU Mini-driver DG-0813, ML h-bridge direction

const int PropMotorSpeedPin = 10;   // on DAGU Mini-driver DG-0813, MR PWM pin
const int PropMotorDirecPin = 8;    // on DAGU Mini-driver DG-0813, MR h-bridge direction

boolean firstrun = true;

int CommandingPWM = 0;
int CommandingDir = 0;
int DirectionCommand = 0;
int SpeedCommand = 0;

void setup() {

  pinMode(DirMotorSpeedPin, OUTPUT);
  pinMode(DirMotorDirecPin, OUTPUT);
  pinMode(PropMotorSpeedPin, OUTPUT);
  pinMode(PropMotorDirecPin, OUTPUT);
  // initialize serial:
  Serial.begin(9600);
  // reserve 10 bytes for the inputString: // original was 200 bytes, no need for that much
  inputString.reserve(10);
 
}

int letterToPWM(char inputChar) {
      // TODO : replace with 'return hexchartoint(upcase(inputChar))*17' ;
      if (((inputChar >= 'a') && (inputChar <= 'f'))) {
          inputChar &= 0xdf; // so upcase only letters not numbers...
      }
      switch (inputChar) {
      case '0' : return 0; break;
      case '1' : return 17; break;
      case '2' : return 34; break;
      case '3' : return 51; break;
      case '4' : return 68; break;
      case '5' : return 85; break;
      case '6' : return 102; break;
      case '7' : return 119; break;
      case '8' : return 136; break;
      case '9' : return 153; break;
      case 'A' : return 170; break;
      case 'B' : return 187; break;
      case 'C' : return 204; break;
      case 'D' : return 221; break;
      case 'E' : return 238; break;
      case 'F' : return 255; break;
      default : return -1; break; // unrecognized character
    }
}

// pull out some large functions
void fullStop()  {
    analogWrite(DirMotorSpeedPin,0);
    digitalWrite(DirMotorDirecPin,0);
    analogWrite(PropMotorSpeedPin,0);
    digitalWrite(PropMotorDirecPin,0);
}

boolean letterToCommand(char inputChar) {
    // returns true for 2 char command, false for 1 char command
    // select pin and speed to be changed
    // the DirectionCommand in either propulsion or direction case
    // here has been established experimentally :)
    // {
    boolean ret = true;
   
    switch (inputChar & 0xdf) {  // mask the 5th bit off so we get upper case char as result
      case 'P' :  { // forward propulsion
        CommandingPWM = PropMotorSpeedPin;
        CommandingDir = PropMotorDirecPin;
        DirectionCommand = 1;
      } 
      break;
     
      case 'T' : { // backward propulsion
        CommandingPWM = PropMotorSpeedPin;
        CommandingDir = PropMotorDirecPin;
        DirectionCommand = 0;
      }
      break;
     
      case 'R' :
      { // right direction
        CommandingPWM = DirMotorSpeedPin;
        CommandingDir = DirMotorDirecPin;
        DirectionCommand = 0;
      }
      break;
   
      case 'L' :
      {  // left direction
        CommandingPWM = DirMotorSpeedPin;
        CommandingDir = DirMotorDirecPin;
        DirectionCommand = 1;
      } 
      break;       
     
      case 'S' :
      {
       fullStop();
       return false;
      }
      break;
     
      case 'V' :
      {
        Serial.println("1.0-PTRLsv");
        return false;
      }
      break;
     
      default: {
          // when the first char was not recognized, crop it
        return false;                   // cut the main loop early
      }
     } // switch inputString.charAt(0)
     // if we went through all that without returning earlier, return true
     return ret;
}

int inputstringlen = 0;

void loop() {
  // when program runs first time, tell the other side we are here
  // TODO: actually output 'firmware' version
  if (firstrun) {
    Serial.println("Car ready");
    firstrun = false;
  }
  if (inputString.length() >= 1) {
   
    if (!letterToCommand( inputString.charAt(0))) {
      inputstringlen = 1;
      goto PRINTINPUTSTRING;  // single char commands don't control motor speed
    }
    else inputstringlen = 2;
   
    // having processed 1 character, have we got another in buffer?
    if (inputString.length() < 2)
      return;    // if not, loop until it appears
   
    // common occurence
    SpeedCommand = letterToPWM(inputString.charAt(1));
   
    if (SpeedCommand >= 0) {  // speed character recognized
             
      // use the CommandingDir pin to select the desired PWM direction output,
      // and change it
      digitalWrite(CommandingDir, DirectionCommand);
      // use the CommandingPWM pin to select desired speed,
      // and set it accordingly
      analogWrite(CommandingPWM, SpeedCommand);
    }  // if speedcommand > 0
   
PRINTINPUTSTRING:
    // echo the captured string out after processing
    Serial.println(inputString);
    // remove first inputstringlen chars
    inputString.remove(0,inputstringlen);
   
   
  } // if inputString.length > 1
  // todo runaway protection
 
   
  // todo detect no-serial
 
} // main loop

/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
 


void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    if (inputString.length() < 10)
      inputString += inChar;
    // the idea is, if we have too much in the queue, no point queuing more 
    // and this part of program is only ever adding characters to the string
    // and the reader is only removing them at the beginning
    // this could allow us to queue the commands
  }
}
el_es
 
Posts: 22
Joined: Sat Feb 07, 2015 3:12 pm

Re: Yet Another DIY Bluetooth RC Car

Postby el_es » Wed Mar 04, 2015 8:00 pm

Code: Select all
/*
   Heavily Based on the Serial Event example
   Apply Reason When Copying for yourself!
   Public domain as the original was.

   Changes from previous version :

   - implement 'k' command that car needs to receive in order to not stop in 2 seconds
   - change v output to "2.0-PTRLksv"
 
   Car has a rear drive motor and NO SERVO,
   front mounted motor is directly diving the steering rack,
   the steering motor works against the steering spring,
   which c[sh]ould make it work for granularity of angle;
   Reality seems to hint, that the stall current is too high for the batteries to handle it all the time.
   Either another battery is needed, or might end up buying a servo ;)
   
   Expects ASCII characters 0..9 a-z in 9600-n-1 serial mode; Accepts them straight off the
   add-on bluetooth module. So far tested with the control stream supplied by PuTTY from a laptop.

   Supported commands are:
   P0 - PF = forward motion, in 16 steps 0-f
   T0 - TF = backward motion, in 16 steps 0-f
   L0 - LF = left turn in 16 steps 0-f
   R0 - RF = right turn in 16 steps 0-f
   K = continue driving - resets the canary timer (2s by default) if timer expires, all outputs are turned off.
   S = put all motions to a stop / turn both motors off immediately
   V = output version, 2.0-PTRLksv to serial port
   The version string gives a hint about expected usage: letters printed upcase (P,T,L,R)
    hint that the command expects a hexadecimal character immediately after the first one.
   If the command is not recognized, the parser does nothing, resets its state and just expects
   that next command will be well formed.
 */

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

//const int led = 13;
// int ledstate = 0; // led initially off

const int DIRMOTORSPEEDPIN = 9;   // on DAGU Mini-driver DG-0813, ML PWM pin
const int DIRMOTORDIRECPIN = 7;   // on DAGU Mini-driver DG-0813, ML h-bridge direction

const int PROPMOTORSPEEDPIN = 10;   // on DAGU Mini-driver DG-0813, MR PWM pin
const int PROPMOTORDIRECPIN = 8;    // on DAGU Mini-driver DG-0813, MR h-bridge direction

boolean firstrun = true;

int CommandingPWM = 0;
int CommandingDir = 0;
int DirectionCommand = 0;
int SpeedCommand = 0;

int Canary = 0;

void setup() {
  // pinMode(led, OUTPUT);
  pinMode(DIRMOTORSPEEDPIN, OUTPUT);
  pinMode(DIRMOTORDIRECPIN, OUTPUT);
  pinMode(PROPMOTORSPEEDPIN, OUTPUT);
  pinMode(PROPMOTORDIRECPIN, OUTPUT);
  // initialize serial:
  Serial.begin(9600);
  // reserve 10 bytes for the inputString: // original was 200 bytes, no need for that much
  inputString.reserve(10);
 
}

int letterToPWM(char inputChar) {
      // TODO : replace with 'return hexchartoint(upcase(inputChar))*17' ;
      if ((inputChar >= 'a') && (inputChar <= 'f')) { // only recognize hex code letters
          inputChar &= 0xdf; // upcase only letters not numbers...
      }
      switch (inputChar) {
      case '0' : return 0; break;
      case '1' : return 17; break;
      case '2' : return 34; break;
      case '3' : return 51; break;
      case '4' : return 68; break;
      case '5' : return 85; break;
      case '6' : return 102; break;
      case '7' : return 119; break;
      case '8' : return 136; break;
      case '9' : return 153; break;
      case 'A' : return 170; break;
      case 'B' : return 187; break;
      case 'C' : return 204; break;
      case 'D' : return 221; break;
      case 'E' : return 238; break;
      case 'F' : return 255; break;
      default : return -1; break; // unrecognized character
    }
}

// pull out some large functions
void fullStop()  {
    analogWrite(DIRMOTORSPEEDPIN,0);
    digitalWrite(DIRMOTORDIRECPIN,0);
    analogWrite(PROPMOTORSPEEDPIN,0);
    digitalWrite(PROPMOTORDIRECPIN,0);
}

boolean letterToCommand(char inputChar) {
    // returns true for 2 char command, false for 1 char command
    // select pin and speed to be changed
    // the DirectionCommand in either propulsion or direction case
    // here has been established experimentally :)
    // {
    boolean ret = true;
   
    switch (inputChar & 0xdf) {  // mask the 5th bit off so we get upper case char as result
      case 'P' :  { // forward propulsion
        CommandingPWM = PROPMOTORSPEEDPIN;
        CommandingDir = PROPMOTORDIRECPIN;
        DirectionCommand = 1;
      } 
      break;
     
      case 'T' : { // backward propulsion
        CommandingPWM = PROPMOTORSPEEDPIN;
        CommandingDir = PROPMOTORDIRECPIN;
        DirectionCommand = 0;
      }
      break;
     
      case 'R' :
      { // right direction
        CommandingPWM = DIRMOTORSPEEDPIN;
        CommandingDir = DIRMOTORDIRECPIN;
        DirectionCommand = 0;
      }
      break;
   
      case 'L' :
      {  // left direction
        CommandingPWM = DIRMOTORSPEEDPIN;
        CommandingDir = DIRMOTORDIRECPIN;
        DirectionCommand = 1;
      } 
      break;       
     
      case 'S' :
      {
       fullStop();
       return false;
      }
      break;
     
      case 'V' :
      {
        Serial.println("2.0-PTRLksv");
        return false;
      }
      break;
     
      case 'K' :
      {
        Canary = 0;
        return false;
      }
      break;
     
      default: {
          // when the first char was not recognized, ignore it
        return false;                   // cut the main loop early
      }
     } // switch inputString.charAt(0)
     // if we went through all that without returning earlier, return true
     return ret;
}

int inputstringlen = 0;
boolean got2ChCommand = false;

void loop() {
  // when program runs first time, tell the other side we are here
  // TODO: actually output 'firmware' version
  if (firstrun) {
    Serial.println("Car ready");
    firstrun = false;
  }
  if (inputString.length() >= 1) {
   
    if (!letterToCommand( inputString.charAt(0))) {
      inputstringlen = 1;
      goto PRINTINPUTSTRING;  // single char commands don't control motor speed
    }
    else inputstringlen = 2;
   
    // having processed 1 character, have we got another in buffer?
    if (inputString.length() < 2)
      return;    // if not, loop until it appears
   
    // common occurence
    SpeedCommand = letterToPWM(inputString.charAt(1));
   
    if (SpeedCommand >= 0) {  // speed character recognized
     
      // we came here meaning we recognized a 2 char command
     
      got2ChCommand = true;
         
    }  // if speedcommand > 0
   
PRINTINPUTSTRING:
    // echo the captured string out after processing
    Serial.println(inputString);
    // remove first inputstringlen chars
    inputString.remove(0,inputstringlen);
   
   
  } // if inputString.length > 1
 
  if (got2ChCommand) {
    // use the CommandingDir pin to select the desired PWM direction output,
      // and change it
    digitalWrite(CommandingDir, DirectionCommand);
      // use the CommandingPWM pin to select desired speed,
      // and set it accordingly
    analogWrite(CommandingPWM, SpeedCommand);
    got2ChCommand = false;
    Canary = 0;
  }
  else
  {
    // to receive 2 characters via 9600bps takes
    // around 2 ms
    // so let's wait 2 seconds
    if(++Canary <= 1000) {
      delay(2);
    }
    else {
      fullStop();
      Canary = 0;
      delay(10);
    }
  }
 
 
} // main loop

/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
 


void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    if (inputString.length() < 10)
      inputString += inChar;
    // the idea is, if we have too much in the queue, no point queuing more 
    // and this part of program is only ever adding characters to the string
    // and the reader is only removing them at the beginning
    // this could allow us to queue the commands
  }
}
el_es
 
Posts: 22
Joined: Sat Feb 07, 2015 3:12 pm

Re: Yet Another DIY Bluetooth RC Car

Postby el_es » Wed Apr 15, 2015 11:07 pm

It's still alive,
I was looking around various tutorials for Android programming, wishing to replicate at least the bluetooth RFCOMM examples... then maybe tie them together with 'pseudo-analog' joystick and ultimately with the angle/position sensor. Lots of loose ends to cover and very baroque (I'm talking about Android Studio...) and totally counter-intuitive naming. But yeah the project still lives.
el_es
 
Posts: 22
Joined: Sat Feb 07, 2015 3:12 pm

Next

Return to Project Showcase

Who is online

Users browsing this forum: No registered users and 1 guest