Marcio Tamagushi
Published © GPL3+

2WD Voice Controlled Robot with Arduino and BitVoicer Server

Shows how to build a 2WD (two-wheel drive) voice-controlled robot using an Arduino and BitVoicer Server.

IntermediateFull instructions provided10 hours22,405
2WD Voice Controlled Robot with Arduino and BitVoicer Server

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Pololu Dual MC33926 Motor Driver Shield
×1
SparkFun XBee Shield
SparkFun XBee Shield
×1
Microchip RN171VX Module
×1
SparkFun Electret Microphone Breakout
×1
2WD Robot Car Chassis
×1
Texas Instruments LM1117 (TO-220) Voltage Regulator
×1
Capacitor 10 µF
Capacitor 10 µF
×1
LED (generic)
LED (generic)
×4
Resistor 330 ohm
Resistor 330 ohm
×4
AA Batteries
AA Batteries
×4
9V battery (generic)
9V battery (generic)
×1
9V to Barrel Jack Adapter
×1
Jumper wires (generic)
Jumper wires (generic)
×17
Regular Copper Wire
×1
Screws and flexible plastic clamp for fixing
×1

Software apps and online services

BitVoicer Server 1.0

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Pliers
Screwdriver

Story

Read more

Schematics

Robot Schematics

Code

WiFi Module Setup

Arduino
Configures the Microchip WiFi RN171VX module using the Arduino serial port.
void setup() 
{ 
  Serial.begin(115200); 
  pinMode(13, OUTPUT); 
  delay(5000); 
  Serial.print("$$$"); 
  delay(1000); 
  Serial.println("set wlan auth 4"); 
  delay(1000); 
  Serial.println("set wlan phrase XXXXXX"); 
  delay(1000); 
  Serial.println("set wlan ssid XXXXXX"); 
  delay(1000); 
  Serial.println("set wlan channel 0"); 
  delay(1000); 
  Serial.println("set wlan join 1"); 
  delay(1000); 
  Serial.println("set wlan tx 0"); 
  delay(1000); 
  Serial.println("set ip dhcp 0");
  delay(1000); 
  Serial.println("set ip address XXXXXX"); 
  delay(1000); 
  Serial.println("set comm remote 0"); 
  delay(1000); 
  Serial.println("set comm close 0"); 
  delay(1000); 
  Serial.println("set comm open 0"); 
  delay(1000); 
  Serial.println("set comm size 500"); 
  delay(1000); 
  Serial.println("set comm time 50"); 
  delay(1000); 
  Serial.println("set uart baud 115200"); 
  delay(1000); 
  Serial.println("set uart flow 0"); 
  delay(1000); 
  Serial.println("save"); 
  delay(1000); 
  Serial.println("exit"); 
  delay(1000); 
  digitalWrite(13, LOW);
}

void loop() { }

Robot Source Code

Arduino
Controls the robot movements, captures audio, manages the TCP/IP connection and communicates with BitVoicer Server.
#include <BVSP.h>
#include <BVSMic.h>
#include <DualMC33926MotorShield.h>

// Defines the Arduino pins that will be used to control
// LEDs and capture audio
#define BVS_RUNNING       2
#define BVS_SRE           5
#define BVS_DATA_FWD      3
#define BVS_ACT_PERIOD    6
#define BVSM_AUDIO_INPUT  3

// Defines the constants that will be passed as parameters to 
// the BVSP.begin function
const unsigned long STATUS_REQUEST_INTERVAL = 2000;
const unsigned long STATUS_REQUEST_TIMEOUT = 1000;

// Defines the size of the mic buffer
const int MIC_BUFFER_SIZE = 64;

// Initializes a new global instance of the BVSP class
BVSP bvsp = BVSP();

// Initializes a new global instance of the BVSMic class
BVSMic bvsm = BVSMic();

// Initializes a new global instance of the 
// DualMC33926MotorShield class
DualMC33926MotorShield ms = DualMC33926MotorShield();

// Creates a buffer that will be used to read recorded samples 
// from the BVSMic class
byte micBuffer[MIC_BUFFER_SIZE];

// Creates a global variable that indicates whether the 
// Arduino is connected to BitVoicer Server
boolean connected = false;

// Defines some constants for the motor settings
const int SPEED_STOP = 0;
const int SPEED_SLOW = 100;
const int SPEED_NORMAL = 250;
const int SPEED_FAST = 400;
const int DIRECTION_FRONT = -1;
const int DIRECTION_BACK = 1;

// Declares a global variables to hold the current motor speed.
// The default is SPEED_NORMAL, but there are voice 
// commands that change this setting.
int motorSpeed = SPEED_NORMAL;

// Stores the command duration in milliseconds
unsigned long cmdDuration = 0;

// Stores the time the command started running
unsigned long cmdStartTime = 0;

// Stores whether a command is running or not
bool cmdRunning = false;

// Stores the last MOVE_FORWARD command. This variable 
// is used only for the COME_BACK command.
byte lastFwdCmd = 0;

// Defines some constants for command names/values
// Just to make the code more readable
const byte CMD_STOP = 0;
const byte CMD_MOVE_FORWARD = 1;
const byte CMD_MOVE_FORWARD_1_CM = 2;
const byte CMD_MOVE_FORWARD_2_CM = 3;
const byte CMD_MOVE_FORWARD_5_CM = 4;
const byte CMD_MOVE_FORWARD_10_CM = 5;
const byte CMD_MOVE_FORWARD_25_CM = 6;
const byte CMD_MOVE_FORWARD_50_CM = 7;
const byte CMD_MOVE_FORWARD_1_M = 8;
const byte CMD_MOVE_BACKWARD = 9;
const byte CMD_MOVE_BACKWARD_1_CM = 10;
const byte CMD_MOVE_BACKWARD_2_CM = 11;
const byte CMD_MOVE_BACKWARD_5_CM = 12;
const byte CMD_MOVE_BACKWARD_10_CM = 13;
const byte CMD_MOVE_BACKWARD_25_CM = 14;
const byte CMD_MOVE_BACKWARD_50_CM = 15;
const byte CMD_MOVE_BACKWARD_1_M = 16;
const byte CMD_TURN_AROUND = 17;
const byte CMD_TURN_AROUND_RIGHT = 18;
const byte CMD_TURN_AROUND_LEFT = 19;
const byte CMD_DO_360 = 20;
const byte CMD_TURN_RIGHT = 21;
const byte CMD_TURN_RIGHT_10 = 22;
const byte CMD_TURN_RIGHT_25 = 23;
const byte CMD_TURN_RIGHT_45 = 24;
const byte CMD_TURN_LEFT = 25;
const byte CMD_TURN_LEFT_10 = 26;
const byte CMD_TURN_LEFT_25 = 27;
const byte CMD_TURN_LEFT_45 = 28;
const byte CMD_DO_CIRCLE = 29;
const byte CMD_COME_BACK = 30;
const byte CMD_MOVE_FORWARD_2_M = 31;
const byte CMD_MOVE_FORWARD_3_M = 32;
const byte CMD_MOVE_BACKWARD_2_M = 33;
const byte CMD_MOVE_BACKWARD_3_M = 34;
const byte CMD_SET_SPEED_SLOW = 35;
const byte CMD_SET_SPEED_NORMAL = 36;
const byte CMD_SET_SPEED_FAST = 37;
const byte CMD_TURN_LEFT_45_BACKWARD = 38;
const byte CMD_TURN_RIGHT_45_BACKWARD = 39;

void setup()
{
  // Starts serial communication at 115200 bps
  Serial.begin(115200);
  
  // Sets the Arduino pin modes
  pinMode(BVS_RUNNING, OUTPUT);
  pinMode(BVS_SRE, OUTPUT);
  pinMode(BVS_DATA_FWD, OUTPUT);
  pinMode(BVS_ACT_PERIOD, OUTPUT);
  AllLEDsOff();

  // Sets the Arduino serial port that will be used for 
  // communication, how long it will take before a status request 
  // times out and how often status requests should be sent to 
  // BitVoicer Server
  bvsp.begin(Serial, STATUS_REQUEST_TIMEOUT, 
    STATUS_REQUEST_INTERVAL);
    
  // Sets the function that will handle the frameReceived 
  // event
  bvsp.frameReceived = BVSP_frameReceived;

  // Prepares the BVSMic class timer
  bvsm.begin();

  // Prepares the motor shield class (pins and timer1) 
  ms.init();
}

void loop() 
{
  // If it is not connected to the server, opens a TCP/IP 
  // connection, sets connected to true and resets the BVSP 
  // class
  if (!connected)
  {
    Connect(Serial);
    connected = true;
    bvsp.reset();
  }
  
  // Checks if the status request interval has elapsed and if it 
  // has, sends a status request to BitVoicer Server
  bvsp.keepAlive();
  
  // Checks if there is data available at the serial port buffer 
  // and processes its content according to the specifications 
  // of the BitVoicer Server Protocol
  bvsp.receive();
  
  // Gets the respective status from the BVSP class and sets 
  // the LEDs on or off
  digitalWrite(BVS_RUNNING, bvsp.isBVSRunning());
  digitalWrite(BVS_DATA_FWD, bvsp.isDataFwdRunning());
  
  // Checks if there is a SRE assigned to the Arduino
  if (bvsp.isSREAvailable())
  {
    // Turns on the SRE available LED
    digitalWrite(BVS_SRE, HIGH);
    
    // If the BVSMic class is not recording, sets up the audio 
    // input and starts recording
    if (!bvsm.isRecording)
    {
      bvsm.setAudioInput(BVSM_AUDIO_INPUT, EXTERNAL);
      bvsm.startRecording();
    }
    
    // Checks if the BVSMic class has available samples
    if (bvsm.available)
    {
      // Makes sure the inbound mode is STREAM_MODE before 
      // transmitting the stream
      if (bvsp.inboundMode == FRAMED_MODE)
        bvsp.setInboundMode(STREAM_MODE);
      
      // Reads the audio samples from the BVSMic class
      int bytesRead = bvsm.read(micBuffer, MIC_BUFFER_SIZE);
      
      // Sends the audio stream to BitVoicer Server
      bvsp.sendStream(micBuffer, bytesRead);
    }
  }
  else
  {
    // There is no SRE available
    // Turns off the SRE and ACT_PERIOD LEDs
    digitalWrite(BVS_SRE, LOW);
    digitalWrite(BVS_ACT_PERIOD, LOW);
    
    // If the BVSMic class is recording, stops it
    if (bvsm.isRecording)
      bvsm.stopRecording();
  }

  // If the status has timed out, the connection is considered 
  // lost
  if (bvsp.hasStatusTimedOut())
  {
    // If the BVSMic is recording, stops it
    if (bvsm.isRecording)
      bvsm.stopRecording();
    
    // Closes the TCP/IP connection
    Disconnect(Serial);
    
    AllLEDsOff();
    connected = false;
  }

  // If a command is running, checks if its duration has 
  // expired. If it has, stop the motors.
  if (cmdRunning)
    if (millis() - cmdStartTime >= cmdDuration)
      RunCommand(CMD_STOP);
}

// Handles the frameReceived event
void BVSP_frameReceived(byte dataType, int payloadSize)
{
  // Performs the appropriate actions based on the frame 
  // data type. If the data type is byte, it is a command.
  // If the data type is int, changes the activated 
  // period LED.
  switch (dataType)
  {
    case DATA_TYPE_BYTE:
      RunCommand(bvsp.getReceivedByte());
      break;
    case DATA_TYPE_INT16:
      digitalWrite(BVS_ACT_PERIOD, bvsp.getReceivedInt16());
      break;
  }
}

// Runs the command received from the server
void RunCommand(byte cmd)
{
  switch (cmd)
  {
    case CMD_STOP:
      ms.setSpeeds(SPEED_STOP, SPEED_STOP);
      cmdRunning = false;
      return;
    case CMD_MOVE_FORWARD:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 60000;
      break;
    case CMD_MOVE_FORWARD_1_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 23;
      break;
    case CMD_MOVE_FORWARD_2_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 47;
      break;
    case CMD_MOVE_FORWARD_5_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 117;
      break;
    case CMD_MOVE_FORWARD_10_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 234;
      break;
    case CMD_MOVE_FORWARD_25_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 468;
      break;
    case CMD_MOVE_FORWARD_50_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 1170;
      break;
    case CMD_MOVE_FORWARD_1_M:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 2339;
      break;
    case CMD_MOVE_FORWARD_2_M:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 4678;
      break;
    case CMD_MOVE_FORWARD_3_M:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 7018;
      break;
    case CMD_MOVE_BACKWARD:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 60000;
      break;
    case CMD_MOVE_BACKWARD_1_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 23;
      break;
    case CMD_MOVE_BACKWARD_2_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 47;
      break;
    case CMD_MOVE_BACKWARD_5_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 117;
      break;
    case CMD_MOVE_BACKWARD_10_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 234;
      break;
    case CMD_MOVE_BACKWARD_25_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 468;
      break;
    case CMD_MOVE_BACKWARD_50_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 1170;
      break;
    case CMD_MOVE_BACKWARD_1_M:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 2339;
      break;
    case CMD_MOVE_BACKWARD_2_M:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 4678;
      break;
    case CMD_MOVE_BACKWARD_3_M:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 7017;
      break;
    case CMD_TURN_AROUND:
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 540;
      break;
    case CMD_TURN_AROUND_RIGHT:
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 540;
      break;
    case CMD_TURN_AROUND_LEFT:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 540;
      break;
    case CMD_DO_360:
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 1065;
      break;
    case CMD_TURN_RIGHT:
      ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0);
      cmdDuration = 503;
      break;
    case CMD_TURN_RIGHT_10:
      ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0);
      cmdDuration = 56;
      break;
    case CMD_TURN_RIGHT_25:
      ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0);
      cmdDuration = 140;
      break;
    case CMD_TURN_RIGHT_45:
      ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0);
      cmdDuration = 252;
      break;
    case CMD_TURN_LEFT:
      ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT);
      cmdDuration = 503;
      break;
    case CMD_TURN_LEFT_10:
      ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT);
      cmdDuration = 56;
      break;
    case CMD_TURN_LEFT_25:
      ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT);
      cmdDuration = 140;
      break;
    case CMD_TURN_LEFT_45:
      ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT);
      cmdDuration = 252;
      break;
    case CMD_DO_CIRCLE:
      ms.setSpeeds(
        SPEED_NORMAL * DIRECTION_FRONT,
        SPEED_NORMAL * DIRECTION_FRONT * 0.60);
        cmdDuration = 4587;
      break;
    case CMD_COME_BACK:
      RunCommand(lastFwdCmd);
      return;
    case CMD_SET_SPEED_SLOW:
      motorSpeed = SPEED_SLOW;
      return;
    case CMD_SET_SPEED_NORMAL:
      motorSpeed = SPEED_NORMAL;
      return;
    case CMD_SET_SPEED_FAST:
      motorSpeed = SPEED_FAST;
      return;
    case CMD_TURN_LEFT_45_BACKWARD:
      ms.setSpeeds(motorSpeed * DIRECTION_BACK, 0);
      cmdDuration = 252;
      break;
    case CMD_TURN_RIGHT_45_BACKWARD:
      ms.setSpeeds(0, motorSpeed * DIRECTION_BACK);
      cmdDuration = 252;
      break;
  }

  // Sets the command start time
  cmdStartTime = millis();

  // Sets cmdRunning to true
  cmdRunning = true;
}

// Opens a TCP/IP connection with the BitVoicer Server
void Connect(HardwareSerial &serialPort)
{
  serialPort.print("$$$");
  delay(500);
  
  // Use the IP address of the server and the TCP port set 
  // in the server properties
  serialPort.println("open 192.168.0.11 4194");
  
  delay(1000);
  serialPort.println("exit");
  delay(500);
}

// Closes the TCP/IP connection with the BitVoicer Server
void Disconnect(HardwareSerial &serialPort)
{
  serialPort.print("$$$");
  delay(500);
  serialPort.println("close");
  delay(1000);
  serialPort.println("exit");
  delay(500);
}

// Turns all LEDs off
void AllLEDsOff()
{
  digitalWrite(BVS_RUNNING, LOW);
  digitalWrite(BVS_SRE, LOW);
  digitalWrite(BVS_DATA_FWD, LOW);
  digitalWrite(BVS_ACT_PERIOD, LOW);
}

Credits

Marcio Tamagushi

Marcio Tamagushi

3 projects • 52 followers

Comments