Programming Arduino to control DC Motors - School Project

Hi,

I am a part of a group of students who are attempting to build an Arduino remote controlled car as a school project. However we have run into some trouble with the programming. I am going to try to explain everything as thoroughly as possible and provide as much information as I can.

First things first, we are using an Arduino Uno R3 Board.

Our goal is to be able to control the car using an app on my Android phone. We planned to do that by connecting a motor shield and a bluetooth module to the Arduino.

Here are the other components that we are using as well as links to them:

SainSmart L293D Motor Drive Shield
KEDSUM Arduino Wireless Bluetooth Transceiver Module
Chasis and Motors'

Now, here is the code that I am attempting to use as well as the link to the website where I found it:

Website

// CxemCAR 1.0 (06.01.2013)
// Project Page: http://english.cxem.net/mcu/mcu3.php
 
#include "EEPROM.h"
 
#define D1 2          // direction of motor rotation 1
#define M1 3          // PWM left motor
#define D2 4          // direction of motor rotation 2
#define M2 5          // PWM right motor
#define HORN 13       // additional channel 1
//#define autoOFF 2500  // milliseconds after which the robot stops when the connection
 
#define cmdL 'L'      // UART-command for left motor
#define cmdR 'R'      // UART-command for right motor
#define cmdH 'H'      // UART-command for additional channel (for example Horn)
#define cmdF 'F'      // UART-command for EEPROM operation
#define cmdr 'r'      // UART-command for EEPROM operation (read)
#define cmdw 'w'      // UART-command for EEPROM operation (write)
 
char incomingByte;    // incoming data
 
char L_Data[4];       // array data for left motor
byte L_index = 0;     // index of array L
char R_Data[4];       // array data for right motor
byte R_index = 0;     // index of array R
char H_Data[1];       // array data for additional channel
byte H_index = 0;     // index of array H
char F_Data[8];       // array data for  EEPROM
byte F_index = 0;     // index of array F
char command;         // command
 
unsigned long currentTime, lastTimeCommand, autoOFF;
 
void setup() {
  Serial.begin(9600);       // initialization UART
  pinMode(HORN, OUTPUT);    // additional channel
  pinMode(D1, OUTPUT);      // output for motor rotation
  pinMode(D2, OUTPUT);      // output for motor rotation
  /*EEPROM.write(0,255);
  EEPROM.write(1,255);
  EEPROM.write(2,255);
  EEPROM.write(3,255);*/
  timer_init();             // initialization software timer
}
 
void timer_init() {
  uint8_t sw_autoOFF = EEPROM.read(0);   // read EEPROM "is activated or not stopping the car when losing connection"
  if(sw_autoOFF == '1'){                 // if activated
    char var_Data[3];
    var_Data[0] = EEPROM.read(1);
    var_Data[1] = EEPROM.read(2);
    var_Data[2] = EEPROM.read(3);
    autoOFF = atoi(var_Data)*100;        // variable autoOFF ms
  }
  else if(sw_autoOFF == '0'){         
    autoOFF = 999999;
  } 
  else if(sw_autoOFF == 255){ 
    autoOFF = 2500;                      // if the EEPROM is blank, dafault value is 2.5 sec
  } 
  currentTime = millis();                // read the time elapsed since application start
}
  
void loop() {
  if (Serial.available() > 0) {          // if received UART data
    incomingByte = Serial.read();        // raed byte
    if(incomingByte == cmdL) {           // if received data for left motor L
      command = cmdL;                    // current command
      memset(L_Data,0,sizeof(L_Data));   // clear array
      L_index = 0;                       // resetting array index
    }
    else if(incomingByte == cmdR) {      // if received data for left motor R
      command = cmdR;
      memset(R_Data,0,sizeof(R_Data));
      R_index = 0;
    }
    else if(incomingByte == cmdH) {      // if received data for additional channel
      command = cmdH;
      memset(H_Data,0,sizeof(H_Data));
      H_index = 0;
    }    
    else if(incomingByte == cmdF) {      // if received data for EEPROM op
      command = cmdF;
      memset(F_Data,0,sizeof(F_Data));
      F_index = 0;
    }
    else if(incomingByte == '\r') command = 'e';   // end of line
    else if(incomingByte == '\t') command = 't';   // end of line for EEPROM op
     
    if(command == cmdL && incomingByte != cmdL){
      L_Data[L_index] = incomingByte;              // store each byte in the array
      L_index++;                                   // increment array index
    }
    else if(command == cmdR && incomingByte != cmdR){
      R_Data[R_index] = incomingByte;
      R_index++;
    }
    else if(command == cmdH && incomingByte != cmdH){
      H_Data[H_index] = incomingByte;
      H_index++;
    }    
    else if(command == cmdF && incomingByte != cmdF){
      F_Data[F_index] = incomingByte;
      F_index++;
    }    
    else if(command == 'e'){                       // if we take the line end
      Control4WD(atoi(L_Data),atoi(R_Data),atoi(H_Data));
      delay(10);
    }
    else if(command == 't'){                       // if we take the EEPROM line end
      Flash_Op(F_Data[0],F_Data[1],F_Data[2],F_Data[3],F_Data[4]);
    }
    lastTimeCommand = millis();                    // read the time elapsed since application start
  }
  if(millis() >= (lastTimeCommand + autoOFF)){     // compare the current timer with variable lastTimeCommand + autoOFF
    Control4WD(0,0,0);                             // stop the car
  }
}
 
void Control4WD(int mLeft, int mRight, uint8_t Horn){
 
  bool directionL, directionR;      // direction of motor rotation L298N
  byte valueL, valueR;              // PWM M1, M2 (0-255)
   
  if(mLeft > 0){
    valueL = mLeft;
    directionL = 0;
  }
  else if(mLeft < 0){
    valueL = 255 - abs(mLeft);
    directionL = 1;
  }
  else {
    directionL = 0;
    valueL = 0;
  }
  
  if(mRight > 0){
    valueR = mRight;
    directionR = 0;
  }
  else if(mRight < 0){
    valueR = 255 - abs(mRight);
    directionR = 1;
  }
  else {
    directionR = 0;
    valueR = 0;
  }
    
  analogWrite(M1, valueL);            // set speed for left motor
  analogWrite(M2, valueR);            // set speed for right motor
  digitalWrite(D1, directionL);       // set direction of left motor rotation
  digitalWrite(D2, directionR);       // set direction of right motor rotation
   
  digitalWrite(HORN, Horn);           // additional channel
}
 
void Flash_Op(char FCMD, uint8_t z1, uint8_t z2, uint8_t z3, uint8_t z4){
 
  if(FCMD == cmdr){           // if EEPROM data read command
    Serial.print("FData:");       // send EEPROM data
    Serial.write(EEPROM.read(0));     // read value from the memory with 0 address and print it to UART
    Serial.write(EEPROM.read(1));
    Serial.write(EEPROM.read(2));
    Serial.write(EEPROM.read(3));
    Serial.print("\r\n");         // mark the end of the transmission of data EEPROM
  }
  else if(FCMD == cmdw){          // if EEPROM data write command
    EEPROM.write(0,z1);               // z1 record to a memory with 0 address
    EEPROM.write(1,z2);
    EEPROM.write(2,z3);
    EEPROM.write(3,z4);
    timer_init();             // reinitialize the timer
    Serial.print("FWOK\r\n");         // send a message that the data is successfully written to EEPROM
  }
}

So far, I have been able to pair my phone with the bluetooth module using the app that was available to download through the website where I got the code. However, when I tried using the app to drive the car I was only able to get the motor connected to M2 to move. Furthermore, it only went forward, not reverse.

After taking a look at the website again, I have noticed that the motor shield that was being used for the project was very different from the one we have. So, I tried using a different guide.

Here is the link to the website for the second guide as well as the code:
Website

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <SoftwareSerial.h>

int bluetoothTx = 2;
int bluetoothRx = 3;

SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *backMotor = AFMS.getMotor(1);
Adafruit_DCMotor *frontMotor = AFMS.getMotor(3);

void setup()
{
  //Setup usb serial connection to computer
  Serial.begin(9600);

  //Setup Bluetooth serial connection to android
  bluetooth.begin(115200);
  bluetooth.print("$$");
  delay(100);
  bluetooth.println("U,9600,N");
  bluetooth.begin(9600);


  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz

  // Set the speed to start, from 0 (off) to 255 (max speed)
  backMotor->setSpeed(255);
  backMotor->run(FORWARD);
  // turn on motor
  backMotor->run(RELEASE);

  frontMotor->setSpeed(255);
  frontMotor->run(FORWARD);
  // turn on motor
  frontMotor->run(RELEASE);

}


Now we're a step closer to being able to receive messages from our android device. Firstly to start reading the message send via bluetooth and writing to usb serial and it looks a something like this

void loop()
{
  //Read from bluetooth and write to usb serial
  if(bluetooth.available())
  {
    char toSend = (char)bluetooth.read();
    Serial.print(toSend);
  }

// Only really used to test to see if the Arduino is receiving the correct message
//Read from usb serial to bluetooth
if(Serial.available())
  {
    char toSend = (char)Serial.read();
    bluetooth.print(toSend);

  }
}
if(bluetooth.available())
  {
    char toSend = (char)bluetooth.read();
    Serial.print(toSend);


    // After the android device sends the data the arduino takes the information and reads it as a char,
    // This code is here to read that data and turn it into actions for the motors.
    if(toSend == 'f'){
      backMotor->run(FORWARD);
    }

    if(toSend == 'b'){
      backMotor->run(BACKWARD);
    }

    if(toSend == 'l'){
      frontMotor->run(FORWARD);
    }

    if(toSend == 'r'){
      frontMotor->run(BACKWARD);
    }

    if(toSend == 'rf'){
      frontMotor->run(BACKWARD);
      backMotor->run(FORWARD);
    }

    if(toSend == 'lf'){
      frontMotor->run(FORWARD);
      backMotor->run(FORWARD);
    }

    if(toSend == 'rb'){
      frontMotor->run(BACKWARD);
      backMotor->run(BACKWARD);
    }

    if(toSend == 'lb'){
      frontMotor->run(FORWARD);
      backMotor->run(BACKWARD);
    }

    if (toSend == 's'){
      frontMotor->run(RELEASE);
      backMotor->run(RELEASE);
    }

  }

This guide uses a motor shield that is more similar to the one we have, as well as the same exact bluetooth module. However, it states that I should plug my TXD and RXD jumper cables into the 2nd and 3rd digital pins. This doesn't seem right. After having uploaded the code and installed the app on my phone, I cannot get any of the motors to move.

I would really appreciate it if someone could guide me in the right direction. I have been scouring various forums looking for a code that would work with our parts. I have not had any luck yet with this. Honestly I do not know code very well yet so I can't tell what about these codes is not compatible. I tried to be as thorough as possible but if you need any more information just let me know. Thanks in advance!

hi dylanhancock,
the first thing i see is, that the TX/RX from your BT-module use 3V3 signals but your UNO use 5V signals on the digital pins. sometimes this can be ok - but normally it is not ok and can destroy you BT-modul. so i think you have to search for a 3V3 to 5V level converter between the BT-modul and the UNO.
and before you "can drive your car with BT" you may start checking, if your UNO receive the commands from the phone via BT.
use the serial monitor to print the received commands on the screen and look if these are the commands you are waiting for...
the digital pins 2 and 3 for connecting the BT-modules TX/RX are defined in your code.

Hi,

Thanks for your reply. That may explain some things. As I said previously, I was able to control one of the motors through pairing my phone to the Bluetooth module, however it was very jittery. I assume this is because of the 3V3 and 5V signal compatibility issue?

As to whether the Arduino recieved any commands over Bluetooth, I can say that it definitely did with the first code. I'm not sure whether it did with the other codes but I will check using that method and get back to you on that.

And I see that the 2nd and 3rd pins are defined in the code. However every tutorial I've seen so far except for that one has said to plug the TX and RX from the Bluetooth into the RX and TX of the Uno. I was just worried that plugging them into the next 2 digital pins instead could cause an electrical short or something like that. Is this a valid concern or are the 2nd and 3rd digital pins open to use to transmit data just like the 0 and 1?

Thanks again for your reply!

hi,
you use the digital pins 2+3 for a software TX/RX, digi pins 0+1 are the hardware TX/RX-pins
see here for more info: http://arduino.cc/en/Reference/SoftwareSerial

you can try a voltage divider 1k/2k for the TX output from your UNO like here:

ore here:
http://www.epanorama.net/newepa/2014/06/23/arduino-controlling-with-bluetooth/
(there are the hardware pins TX/RX used)

the used RX pin (hard- or software) from the UNO is normally tolerant to 3V3 inputs

a drawing and/or photo of the connections and parts and power supply would also helpfull.

m.

Hi,

I'm currently looking into the voltage divider. Before I got your response, I started playing with some code trying to determine whether my Arduino was receiving the messages sent from my phone. I found a simple code that was made to do this using the hardware Rx and Tx pins and tried altering it to work with the 2nd and 3rd digi pins. Unfortunately this didn't work. When i send characters from my phone to the bluetooth module, nothing shows up on the serial monitor. Could you take a look at the code and see if I did something wrong or if my idea is even possible?

#include <SoftwareSerial.h>

int bluetoothTx = 2;
int bluetoothRx = 3;

SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
String message; //string that stores the incoming message

void setup()
{
  Serial.begin(9600); //set baud rate
}

void loop()
{
  while(Serial.available())
  {//while there is data available on the serial monitor
    message+=char(Serial.read());//store string from serial command
  }
  if(!Serial.available())
  {
    if(message!="")
    {//if data is available
      Serial.println(message); //show the data
      message=""; //clear the data
    }
  }
  delay(5000); //delay
}

Thanks!

hi Dylan,
i needed some more time, because i am also new in programming...

a very helpful page i found here to send something from my phone to BT RoboRemo 1 LED

i had to change the BT-baud rate to 115200 (9200 does not function)

#include <SoftwareSerial.h>

int bluetoothTx = 2; // this is the TX-pin of my BT-modul
int bluetoothRx = 3; // this is the RX-pin of my BT-modul
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

void setup()
{
  delay(500); // wait for bluetooth module to start

  Serial.begin(115200); //set baud rate for serial monitor
  bluetooth.begin(115200); // baud rate of my BT-modul

  pinMode(bluetoothTx, INPUT); // incoming from BT-modul
  pinMode(bluetoothRx, OUTPUT); // out to BT
}

void loop()
{
  char recvChar;
  if(bluetooth.available())
  {
 recvChar = bluetooth.read();
    Serial.print(recvChar); // show on Serial Monitor
  }
 
  // read from serial, send to BT - not tested now
  if (Serial.available()) {
    recvChar = Serial.read();
    bluetooth.print(recvChar); 
  }
}

and on the page RoboRemo RC-Car

you may find some more help for your project :slight_smile:

matthes

I had a pretty big breakthrough today with the project! Using the code that I'll post below, I was able to send commands through Bluetooth from my phone to the Arduino and they showed up just as I expected them to on the serial monitor.

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <SoftwareSerial.h>

int bluetoothTx = 2;
int bluetoothRx = 3;

SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *backMotor = AFMS.getMotor(1);
Adafruit_DCMotor *frontMotor = AFMS.getMotor(3);

void setup()
{
  //Setup usb serial connection to computer
  Serial.begin(9600);

  //Setup Bluetooth serial connection to android
  bluetooth.begin(115200);
  bluetooth.print("$$");
  delay(100);
  bluetooth.println("U,9600,N");
  bluetooth.begin(9600);


  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz

  // Set the speed to start, from 0 (off) to 255 (max speed)
  backMotor->setSpeed(255);
  backMotor->run(FORWARD);
  // turn on motor
  backMotor->run(RELEASE);

  frontMotor->setSpeed(255);
  frontMotor->run(FORWARD);
  // turn on motor
  frontMotor->run(RELEASE);

}

void loop()
{
  //Read from bluetooth and write to usb serial
  if(bluetooth.available())
  {
    char toSend = (char)bluetooth.read();
    Serial.print(toSend);


    // After the android device sends the data the arduino takes the information and reads it as a char,
    // This code is here to read that data and turn it into actions for the motors.
    if(toSend == 'f'){
      backMotor->run(FORWARD);
    }

    if(toSend == 'b'){
      backMotor->run(BACKWARD);
    }

    if(toSend == 'l'){
      frontMotor->run(FORWARD);
    }

    if(toSend == 'r'){
      frontMotor->run(BACKWARD);
    }

    if(toSend == 'rf'){
      frontMotor->run(BACKWARD);
      backMotor->run(FORWARD);
    }

    if(toSend == 'lf'){
      frontMotor->run(FORWARD);
      backMotor->run(FORWARD);
    }

    if(toSend == 'rb'){
      frontMotor->run(BACKWARD);
      backMotor->run(BACKWARD);
    }

    if(toSend == 'lb'){
      frontMotor->run(FORWARD);
      backMotor->run(BACKWARD);
    }

    if (toSend == 's'){
      frontMotor->run(RELEASE);
      backMotor->run(RELEASE);
    }

  }
}

While the serial monitor was recording all of the commands that were being sent by my phone, the motors were not moving. So I'm going to look into this now and see if there is anything I did wrong or any issues with the code. Do you have any suggestions on where I should look?
Dylan

So currently the bluetooth module is working but the motors do not move when the commands are sent to the Arduino. I think I've narrowed down why the code isn't working. It seems like the code is written to be used with the v2 of the Adafruit motor shield and my motor shield is based off of the v1. Is there any way that the code could be changed so that it worked with the v1? I wish I could do it myself but I don't have the programming expertise to do that. If not, I may just go ahead and order the v2.

hi Dylan,

i suggest, that you split your (a little too complex) project into smaller parts:

  • remove the BT modul
  • define some motor moves into your program and look if this is going well.
  • put some switches to digital inputs of your UNO to control the motors to left/right/off

some more info about using motor shields:

Make: Motor Shield V1.1 and Adafruit Motor Shield

there are also downloads for the matching library and examples and faq and so on

and only if you can control the motors successfully with the UNO, then try it with the BT-module.

matthes