Bluetooth RC Car – Mechanum wheel platform (Part 1 of 4)

Introduction

This is the part one from a series of four blogs. By the end of this series, I want to built an Arduino based kit car with “mechanum” wheels and which can be controlled in following ways:

  1. Program (for preprogrammed actions)
  2. Android App
    • Voice commands
    • Orientation sensor controlled
    • Button tap or type commands
  3. Magic Wand using gestures

Additionally, I want to secure the magic wand with a secret spell or gesture.

This touches many interesting areas like motor control, bluetooth to bluetooth communication, building an android app, machine learning inference on microcontrollers and many more. Let’s get started.

Mechanum Wheel

First, what the heck is a mechanum wheel? It’s a tireless wheel invented by a Swedish inventor Bengt Erland Ilon, while working for a company named Mechanum AB. It has a pair of right handed and left handed wheels as shown below.

When controlled in a certain patterns, it can not only rotate on a dime like a battle tank, but also gets almost magical powers to move sideways like a crab or even diagonally. It can even pivot on any of its wheels or any of its axels. Take a look. I do not know of anything else with a wheel, that is capable of doing this.

https://commons.wikimedia.org/wiki/File:Aircraft_container_and_pallet_loader_Mecanum_wheels.jpg

This enables any platform with a mechanum wheel, to move in any direction on a flat surface, also called “omni directional” capability. This is extremely useful for movement in tight spaces for example on aircraft carriers, airports, warehouses etc.

If you have ever noticed and wondered how your luggage containers move sideways or forward on the same platform while being loaded on the airplane, well, now you know.

Building the prototype car

Following are the components needed:

  • Acrylic Car kit – typically comes with standard wheels, TT motors etc.
  • 2 pairs – Right handed and Left handed Mechanum wheels
  • 4# – of TT Geared 3V-6V DC motors
  • Arduino Uno
  • HM-10 bluetooth module
  • 2# – L298N motor control module
  • 2# – LiPO battery greater than 7.4V
  • 3# – 1K Ohm resistors connect in 2:1 (or a 10K Ohm and a 4.7K Ohm)
  • Breadboard
  • Jumper wires

Connections are as shown below.

Words of Caution:

  1. HM-10 module needs to use level shifter or voltage divider for its Rx receiving line which is connected to TX line of Arduino Uno. This is because logic level of Arduino is 5V while HM-10 is only 3.3V logic level tolerant. I have not shown it in the circuit diagram below. (You can read more on Tx Rx connections in my other blog here)
  2. Although I have taken every care to show the connection correctly, mistakes happen. Please test your connection carefully. Voltage and current involved is sufficient to ruin the modules or even start fires.

Truth be told, I have so far fried a bluetooth module, caused smoke and melted wires due to incorrect connections and learned some very valuable lessons.

Code

Next, upload the below code on Arduino. This program will demo the various patterns of motion that a mechanum wheel car can perform. The code has various functions corresponding to each of those motions. In each function, specific motors are switched on or off and also the direction of those motors are controlled to get the desired motion. The program also has code related to bluetooth and calling various functions based on the codes received over bluetooth. This will be used in the part two of this blog series.

Refer the following image to understand how mechanum wheels achieve the magic tricks.

// Control all 4 wheels independantly
// For mechanum wheels
// All turns need change as only 2 motors are used and turns are straight line instead of curve of typical turn
// 2 more motions - glideright, glideleft are enabled by mechanum
// No change needed for forward, back, rotateright, rotateleft
// 

// motor 1
#define ENA 10
#define IN1 9
#define IN2 8

// motor 2
#define ENB 11
#define IN3 13
#define IN4 12

// motor 3
#define ENC 5
#define IN5 7
#define IN6 6

// motor 4
#define END 3
#define IN7 4
#define IN8 2

// LED lights
//#define LED 13

//// LED Boolean
//bool Mode = 0;

// for gesture received from bluetooth
char getstr = 'D'; //initialized to stop all

////For voice vontrol using AMR_Voice bluetooth app
//String  voice;
//char    c;


// car speed default @ 80 %, if not provided at the start of the communication
int carSpeed = 150; // 80 % 200 = ((80*100)/255)

// relative speed divider for motor A, B, C, D
int relA = 1;
int relB = 1;
int relC = 1;
int relD = 1;

//counter
int i;

// delay
int wait = 1000;

//void led()
//{
//  Mode = !Mode; // toggle mode
//  digitalWrite(LED, Mode);
//
//  }
//

void test()
{
  // Relative speed divider 
  relA = 1;
  relB = 1;
  relC = 1;
  relD = 1;
  
  // motor A
  analogWrite(ENA, carSpeed / relA);
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  delay(wait);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  delay(wait);
  analogWrite(ENA, LOW);
  
  // motor B
  analogWrite(ENB, carSpeed / relB);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  delay(wait);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  delay(wait);
  analogWrite(ENB, LOW);

  // motor C
  analogWrite(ENC, carSpeed / relC);
  digitalWrite(IN5, HIGH);
  digitalWrite(IN6, LOW);
  delay(wait);
  digitalWrite(IN5, LOW);
  digitalWrite(IN6, HIGH);
  delay(wait);
  analogWrite(ENC, LOW);
  
  // motor D
  analogWrite(END, carSpeed / relD);
  digitalWrite(IN7, HIGH);
  digitalWrite(IN8, LOW);
  delay(wait);
  digitalWrite(IN7, LOW);
  digitalWrite(IN8, HIGH);
  delay(wait);
  analogWrite(END, LOW);
  
  Serial.println("TESTING");
}

void forward()
{
  // Relative speed divider 
  relA = 1;
  relB = 1;
  relC = 1;
  relD = 1;
  
  // motor A
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, carSpeed / relA);
  
  // motor B
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENB, carSpeed / relB);

  // motor C
  digitalWrite(IN5, HIGH);
  digitalWrite(IN6, LOW);
  analogWrite(ENC, carSpeed / relC);
  
  // motor D
  digitalWrite(IN7, HIGH);
  digitalWrite(IN8, LOW);
  analogWrite(END, carSpeed / relD);
  
  Serial.println("Forward");
  delay(wait);
}

void back()
{
  // Relative speed divider 
  relA = 1;
  relB = 1;
  relC = 1;
  relD = 1;
  
  // motor A
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(ENA, carSpeed / relA);
  
  // motor B
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(ENB, carSpeed / relB);

  // motor C
  digitalWrite(IN5, LOW);
  digitalWrite(IN6, HIGH);
  analogWrite(ENC, carSpeed / relC);
  
  // motor D
  digitalWrite(IN7, LOW);
  digitalWrite(IN8, HIGH);
  analogWrite(END, carSpeed / relD);

  Serial.println("Back");
  delay(wait);
}

void rotateright()
{
  // Relative speed divider 
  relA = 1;
  relB = 1;
  relC = 1;
  relD = 1;
  
  // motor A
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, carSpeed / relA);
  
  // motor B
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(ENB, carSpeed / relB);

  // motor C
  digitalWrite(IN5, LOW);
  digitalWrite(IN6, HIGH);
  analogWrite(ENC, carSpeed / relC);
  
  // motor D
  digitalWrite(IN7, HIGH);
  digitalWrite(IN8, LOW);
  analogWrite(END, carSpeed / relD);

  Serial.println("RotateRight");
  delay(wait);
}

void rotateleft()
{
  // Relative speed divider 
  relA = 1;
  relB = 1;
  relC = 1;
  relD = 1;
  
  // motor A
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(ENA, carSpeed / relA);
  
  // motor B
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENB, carSpeed / relB);

  // motor C
  digitalWrite(IN5, HIGH);
  digitalWrite(IN6, LOW);
  analogWrite(ENC, carSpeed / relC);
  
  // motor D
  digitalWrite(IN7, LOW);
  digitalWrite(IN8, HIGH);
  analogWrite(END, carSpeed / relD);

  Serial.println("RotateLeft");
  delay(wait);
}

void mforwardrightturn()
{
  // Relative speed divider 
  relA = 1;
  relC = 1;
  
  // motor A
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, carSpeed / relA);
  
  // motor C
  digitalWrite(IN5, HIGH);
  digitalWrite(IN6, LOW);
  analogWrite(ENC, carSpeed / relC);
  
  Serial.println("MechanumForwardRightTurn");
  delay(wait);
}

void mbackrightturn()
{
  // Relative speed divider 
  relB = 1;
  relD = 1;
  
  // motor B
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(ENB, carSpeed / relB);

  // motor D
  digitalWrite(IN7, LOW);
  digitalWrite(IN8, HIGH);
  analogWrite(END, carSpeed / relD);

  Serial.println("MechanumBackRightTurn");
  delay(wait);
}

void mforwardleftturn()
{
  // Relative speed divider 
  relB = 1;
  relD = 1;
    
  // motor B
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENB, carSpeed / relB);

  // motor D
  digitalWrite(IN7, HIGH);
  digitalWrite(IN8, LOW);
  analogWrite(END, carSpeed / relD);

  Serial.println("MechanumForwardLeftTurn");
  delay(wait);
}

void mbackleftturn()
{
  // Relative speed divider 
  relA = 1;
  relC = 1;
  
  // motor A
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(ENA, carSpeed / relA);
  
  // motor C
  digitalWrite(IN5, LOW);
  digitalWrite(IN6, HIGH);
  analogWrite(ENC, carSpeed / relC);
  
  Serial.println("MechanumBackLeftTurn");
  delay(wait);
}

void glideright()
{
  // Relative speed divider 
  relA = 1;
  relB = 1;
  relC = 1;
  relD = 1;
  
  // motor A
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, carSpeed / relA);
  
  // motor B
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(ENB, carSpeed / relB);

  // motor C
  digitalWrite(IN5, HIGH);
  digitalWrite(IN6, LOW);
  analogWrite(ENC, carSpeed / relC);
  
  // motor D
  digitalWrite(IN7, LOW);
  digitalWrite(IN8, HIGH);
  analogWrite(END, carSpeed / relD);

  Serial.println("MechanumGlideRight");
  delay(wait);
}

void glideleft()
{
  // Relative speed divider 
  relA = 1;
  relB = 1;
  relC = 1;
  relD = 1;
  
  // motor A
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(ENA, carSpeed / relA);
  
  // motor B
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENB, carSpeed / relB);

  // motor C
  digitalWrite(IN5, LOW);
  digitalWrite(IN6, HIGH);
  analogWrite(ENC, carSpeed / relC);
  
  // motor D
  digitalWrite(IN7, HIGH);
  digitalWrite(IN8, LOW);
  analogWrite(END, carSpeed / relD);

  Serial.println("MechanumGlideRight");
  delay(wait);
}

void forwardrightturn()
{
  // Relative speed divider 
  relA = 1;
  relB = 2;
  relC = 2;
  relD = 1;
  
  // motor A
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, carSpeed / relA);
  
  // motor B
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENB, carSpeed / relB);

  // motor C
  digitalWrite(IN5, HIGH);
  digitalWrite(IN6, LOW);
  analogWrite(ENC, carSpeed / relC);
  
  // motor D
  digitalWrite(IN7, HIGH);
  digitalWrite(IN8, LOW);
  analogWrite(END, carSpeed / relD);

  Serial.println("ForwardRightTurn");
  delay(wait);
}

void backrightturn()
{
  // Relative speed divider 
  relA = 1;
  relB = 2;
  relC = 2;
  relD = 1;
  
  // motor A
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(ENA, carSpeed / relA);
  
  // motor B
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(ENB, carSpeed / relB);

  // motor C
  digitalWrite(IN5, LOW);
  digitalWrite(IN6, HIGH);
  analogWrite(ENC, carSpeed / relC);
  
  // motor D
  digitalWrite(IN7, LOW);
  digitalWrite(IN8, HIGH);
  analogWrite(END, carSpeed / relD);

  Serial.println("BackRightTurn");
  delay(wait);
}

void forwardleftturn()
{
  // Relative speed divider 
  relA = 2;
  relB = 1;
  relC = 1;
  relD = 2;
  
  // motor A
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, carSpeed / relA);
  
  // motor B
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENB, carSpeed / relB);

  // motor C
  digitalWrite(IN5, HIGH);
  digitalWrite(IN6, LOW);
  analogWrite(ENC, carSpeed / relC);
  
  // motor D
  digitalWrite(IN7, HIGH);
  digitalWrite(IN8, LOW);
  analogWrite(END, carSpeed / relD);

  Serial.println("ForwardLeftTurn");
  delay(wait);
}

void backleftturn()
{
  // Relative speed divider 
  relA = 2;
  relB = 1;
  relC = 1;
  relD = 2;
  
  // motor A
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(ENA, carSpeed / relA);
  
  // motor B
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(ENB, carSpeed / relB);

  // motor C
  digitalWrite(IN5, LOW);
  digitalWrite(IN6, HIGH);
  analogWrite(ENC, carSpeed / relC);
  
  // motor D
  digitalWrite(IN7, LOW);
  digitalWrite(IN8, HIGH);
  analogWrite(END, carSpeed / relD);

  Serial.println("BackLeftTurn");
  delay(wait);
}

// stop all motors
 void stop()
{
  digitalWrite(ENA, LOW);
  digitalWrite(ENB, LOW);
  digitalWrite(ENC, LOW);
  digitalWrite(END, LOW);
  
  Serial.println("Stop all motors");
  }

// all pins to low
void stopall()
{
  // motor A
  digitalWrite(ENA, LOW);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  
  // motor B
  digitalWrite(ENB, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);

  // motor C
  digitalWrite(ENC, LOW);
  digitalWrite(IN5, LOW);
  digitalWrite(IN6, LOW);
  
  // motor D
  digitalWrite(END, LOW);
  digitalWrite(IN7, LOW);
  digitalWrite(IN8, LOW);

//  digitalWrite(LED, LOW);

  Serial.println("Stop!");
  delay(wait);
}

void demo()
{
//  test();
  delay(wait);
  forward();
  back();
  rotateleft();
  rotateright();

// Mechanum specific
  glideright();
  glideleft();
  mforwardrightturn();
  mbackrightturn();
  mforwardleftturn();
  mbackleftturn();

// Regular  
  forwardrightturn();
  backrightturn();
  forwardleftturn();
  backleftturn();

// Stop
  stopall();
}

void bluetooth()
{
    if (Serial.available() >0)
  {
    getstr = Serial.read();
    switch(getstr)
    {
//      case 'O': led(); break;               //LED toggle
      case 'F': forward(); break;           //Forward
      case 'B': back(); break;              //Back
      case 'L': glideleft(); break;         //Rotate Left
      case 'R': glideright(); break;        //Rotate Right
      case 'G': forwardleftturn(); break;   //Forward Left Turn
      case 'I': forwardrightturn; break;    //Forward Right Turn
      case 'H': backleftturn(); break;      //Back Left Turn
      case 'J': backrightturn(); break;     //Back Right Turn
      case 'W': rotateleft(); break;        //Rotate Left
      case 'U': rotateright(); break;        //Rotate Right
      case 'S': stop(); break;              //Stop
      case 'D': stopall(); break;           //Stop All
      case '0': carSpeed = 0; break;        //Speed 0 %
      case '1': carSpeed = 25; break;       //Speed 10 %
      case '2': carSpeed = 50; break;       //Speed 20 %
      case '3': carSpeed = 75; break;       //Speed 30 %
      case '4': carSpeed = 100; break;      //Speed 40 %
      case '5': carSpeed = 125; break;      //Speed 50 %
      case '6': carSpeed = 150; break;      //Speed 60 %
      case '7': carSpeed = 175; break;      //Speed 70 %
      case '8': carSpeed = 200; break;      //Speed 80 %
      case '9': carSpeed = 225; break;      //Speed 90 %
      case 'q': carSpeed = 255; break;      //Speed 100 %
      default: break;
      }
      Serial.println (getstr);
    }
}

void setup()
{
  Serial.begin(9600);
  // set all the motor control pins to outputs
  pinMode(ENA, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);

  pinMode(ENB, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  
  pinMode(ENC, OUTPUT);
  pinMode(IN5, OUTPUT);
  pinMode(IN6, OUTPUT);
  
  pinMode(END, OUTPUT);
  pinMode(IN7, OUTPUT);
  pinMode(IN8, OUTPUT);
  // set all the LED control pins to outputs
//  pinMode(LED, OUTPUT);

  // Initialize to stop all
  stop();
}

void loop()
{
// demo();  
 bluetooth();
}

Next step

The next part of this blog talks about building an android app which will connect with the car over bluetooth. With the app, we will be able to control the car using phone as a steering wheel and also through voice commands, touch controls etc.

Thanks for reading.

Here is the link to other parts of this series

Bluetooth RC Car – Android App (Part 2 of 4)

An android app for Arduino Bluetooth RC car projects. Control the car by voice commands, gyroscope steering & buttons. One touch connection. Full customization of connections, BLE codes & voice commands. Works out of box with BLE 4.0 HM-10 module.

Keep reading

You might also like

One thought on “Bluetooth RC Car – Mechanum wheel platform (Part 1 of 4)

Add yours

Leave a comment

Website Powered by WordPress.com.

Up ↑