Project tutorial
Arduino101 BLE Autonomous Rover

Arduino101 BLE Autonomous Rover © CC BY-SA

Augmenting the Arduino101 BLE Rover with sensors for autonomous driving.

  • 13,718 views
  • 2 comments
  • 31 respects

Components and supplies

Necessary tools and machines

Velcro Tape
Small screwdrivers

Apps and online services

About this project

This project is an extension of the Arudino101 BLE Rover, where I had supplied some Seeedstudio Skeleton Bot 4WD mobile robotic platform kits to a team conducting a Maker experience for Oakland, CA High School students. The intent of this tutorial is to show how by adding sensors you can create a platform to explore how to program an autonomous self driving vehicle.

The high level sections for this tutorial are:

1. Assemble the basic rover

2. Programming the basic rover

3. Troubleshooting

4. Adding autonomous mode

5. Final comments on further enhancements

Detailed Hardware Bill of Materials:

1. Arduino 101 board

2. Grove Starter Kit for Arduino

  • Grove Base Shield v2.0
  • Grove Proximity Sensor
  • Grove LED Socket v1.3 with Blue LED
  • Grove Cables (4 ea.)

3. Skeleton Bot – 4WD Mobile Robotic Platform

  • Aluminum chassis and drilled acrylic plates - part of
  • 25GA-370 DC motor (4 ea.) with wires for + and -
  • Grove I2C Motor Driver Board with 0.25” standoffs, screws (2 ea.)
  • 85mm Wheels, axels, screws (4 ea.)
  • 1” Aluminum standoffs, screws for mounting Arduino
  • Dean’s male pigtail for connecting to motor driver
  • Dean’s “T” – 2 female connectors tied to one male connector
  • Dean’s male with Arduino barrel jack
  • Dean’s female to Traxxas connector
  • Traxxas Li-Po 30C 5000mAh 2S 7.4V Battery

Section 1: Assemble the basic rover

This project is based on the Arduino 101 BLE rover, so you can review the Assemble the Rover and Electrical Assembly Steps. I have added detailed directions, as I have changed the orientation of the Arduino101 mount point, and use a second motor controller to reduce likely hood of loose wires after collisions.

Mount the Arduino101 and Motor Controllers – Mount the Arduino101 onto the acrylic mounting plate and secure it with the metal screws. Mount the motor controller onto the acrylic mounting plate and secure it with the small metal screws. Set the motor controller so that the one mounted in the middle is 1, and the one in the front is 2 (see figure 1).

Assemble the power cables – The battery pack splits the output between the motors and other devices. Assemble the power cables as shown in the picture (see figure 2).

Power cables and motor wires – Pass the power cables and motor wires through the acrylic mounting plate. Note the location of the motor controller terminals; try to route the motor wires closer to them (see figure 3).

Wire motors to motor controllers – There are a total of 8 wires (2 per motor) color coded in pairs. Connect each motor to the motor controllers based on the following: right side motor wires go to the motor controller terminals in the middle of the chassis; left side motor wires go to the motor controller terminals in the front of the chassis (see figure 4).

Wire power cables – Wire the power cables to the motor controllers (red is positive, black is negative). Make sure to tighten all terminals to prevent wires from disconnecting (see figure 5).

Installing the Grove Shield – Insert the Grove shield onto the Arduino breakout board. Connect the motor controllers to the Grove Shield in any I2C labeled port using the Grove cables (see figure 6).

Mounting the Acrylic Plate and Add Sensors – Secure the acrylic plate to the main chassis using the four brass connectors. Connect the Grove LED to Grove Shield port D2 (see figure 7).

Mounting the Aluminum Plate – Secure the aluminum mounting plate on top of the acrylic mounting plate using the screws (see figure 8).

Installing the wheels – Install the 4 wheels onto the drive shafts (see figure 9).

Section 2: Programming the basic rover

Connect the DC barrel jack to the Arduino 101. Connect the Li-Po battery to the Dean’s male Traxxas connection. Connect a USB programming cable to the Arduino 101 and to your computer.

You'll need the Arduino IDE installed on your computer, with the Intel Curie Core (see Arduino 101 getting started.) If you are new to Arduino, it’s a good idea to run in the Arduino IDE File -> Examples -> 01.Basics -> Blink to verify that everything is working. The blinking on board LED can be seen from the side of the rover under the Grove Shield. Once that is verified you can load the code, which is in the project code section.

I use the same Arduino101 and Grove Motor Controller as the Programming the Arduino101 for a basic rover so check it out for an overview of how BLE is setup, and the motors are controlled using the Grove Motor Controller. Since the original base model code used one motor controller, and two are used here, there are some basic changes that I had to make.

However, the first major extension that I added was to process the whole UART transmitted string instead just the first character. This allows the commands between the rover and the BLE mobile device to be more human readable. For example, “a” go forward became: “Auto:Up” and “b” turn left became: “Auto:Left”.

This also means that the BLE Mobile control interface using nRF toolbox UART needs to send different strings than that of the original project, which used single characters for movement. In this project:

  • Auto:Up” Moves the rover - Forward
  • Auto:Left” Moves the rover - Left
  • Auto:Right” Moves the rover - Right
  • Auto:Back” Moves the rover - Reverse
  • Auto:Stop” Stops the rover

You can configure nRF toolbox to act as a mobile BLE interface, by following these steps:

1. Install nRF Toolbox for your mobile device in either the iOS or Android app store.

2. Launch the nRF Toolbox on your mobile device.

3. Select the UART icon. There are nine user definable buttons in a 3x3 grid. If this is the first time, the default layout is called UART and blank.

4. Press the ‘EDIT’ button in the upper right corner.

The grid color will turn orange indicating it is in ‘Edit’ model. Touching an individual button in the grid brings up a setup screen where you can pick an icon for that button, and enter the appropriate string. Do this for all 5 rover commands. You can save this to another name (see figures 10-12).

5. Select the ‘DONE’ button to run.

6. Select ‘CONNECT’.

7. Select the BLE name from your Arduino sketch, 4WDUART for example.

8. Press the defined buttons to move the rover.

9. Press ‘DISCONNECT’.

10. Exit the app.

Section 3: Basic troubleshooting

If the motors do not turn at all, the I2C Grove Motor Drivers my need to be reset via a small button on the board (see figure 13).

To verify that the wiring was done correctly, sample code for the motor drivers can be used. Please reference the Testing Motor Control step of Arduino101 BLE Rover project this is based on for more details.

To verify BLE connectivity, nRF Connect for mobile can be used. Please reference the Arduino101 BLE Rover Remote Control for more details.

Section 4: Adding autonomous mode

I added a Grove 80cm Infrared Proximity Sensor to the front of the rover to detect oncoming obstacles. It is attached to the Grove shield at port A0 by a Grove cable. By using the code snippet on the sensor’s wiki, I found that I could detect obstacles with enough time to react when the analog voltage was >1. With the second major extension of the base rover code, I added support for an autonomous mode, where when the UART sends a string “Auto:Auto” the rover drives forward until an obstacle is detected, and then the rover will alternate turning left and right for avoidance.

To modify the nRF Toolbox to support the autonomous mode, follow these steps:

1. Launch the nRF Toolbox on your mobile device.

2. Select the UART icon. Select the UART layout that you had configured for the basic rover.

3. Press the ‘EDIT’ button in the upper right corner. The grid color will turn orange indicating it is in ‘Edit’ model. Touching an individual button in the grid brings up a setup screen where you can pick an icon for that button, and enter the appropriate string. Touch an unused button, and set the icon to play and set the string to “Auto:Auto”.

4. Select the ‘DONE’ button to run.

5. Select ‘CONNECT.

6. Select the BLE name from your Arduino sketch, 4WDUART for example.

7. Press the defined buttons to move the rover.

8. Press ‘DISCONNECT

9. Exit the app.

Section 5: Final comments and further enhancements

This project builds on top of the original Arduino101 BLE rover by using sensors to create a platform where developers can try their hands at programming an autonomous vehicle. Things to explore further on the rover code are: more sophisticated obstacle avoidance, multiple proximity sensors to allow the rover to detect and react to different types of collisions, different types of sensors to optimize for lighting conditions. Things to explore further on the BLE device are: interfaces beyond the simple digital 3x3 button grid like an analog joystick, or steering wheel and an accelerator pedal, and controlling multiple rovers from the same BLE central device at the same time. Things to explore further on use cases are: real world implementation of a go-cart video game with sensors detecting powers ups, robotics challenges like line following.

Code

Arduino101 4wd UART AutoArduino
Arduino code to control Arduino101 4wd Rover using UART BLE mobile device or autonomous mode with proximity sensor
/* Authors: Oliver Chen, Raad Hashim, Prashant Lalwani and Purval Sule
   
   Autonomous Arduino 101 based 4WD Rover code.
   This code drives an Arduino101 microcontroller board
   using the builtin Bluetooth Low Energy (BLE) functonality
   , 4 sets of motor on the SEEDstudio Skeleton Bot chassis
   driven by 2 grove I2C motor control drivers.
   Additional components included from SEEDstudio include:
   Grove LED Socket, Green LED, Grove 80cm proximity sensor

   Motor driver example code found at:
   https://github.com/Seeed-Studio/Grove_I2C_Motor_Driver

   Initial UART BLE from Dave Shade's Arduino101 BLE Rover

   This demo code is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.
 
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.
 
   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 

*/

// Tested on Ubuntu 16.04, Arduino 1.6.13, and corelibs 1.0.7

////////////////
// Libraries //
//////////////

// Curie Bluetooth Library
#include <CurieBLE.h>
// I2C Library
#include <Wire.h>

//////////////
// Defines //
////////////

// defines required by motor driver functions
#define MotorSpeedSet             0x82
#define PWMFrequenceSet           0x84
#define DirectionSet              0xaa
#define MotorSetA                 0xa1
#define MotorSetB                 0xa5
#define Nothing                   0x01
// Note: each I2C motor driver has a unique address (selectable on board)
#define I2CMotorDriver_right_Addr 0x01   // Set the address of the I2CMotorDriver - right
#define I2CMotorDriver_left_Addr  0x02   // Set the address of the I2CMotorDriver - left
#define IR_PROXIMITY_SENSOR A1 // Analog input pin that  is attached to the sensor
#define ADC_REF 5//reference voltage of ADC is 5v.If the Vcc switch on the Seeeduino
                     //board switches to 3V3, the ADC_REF should be 3.3
float voltage;//the sensor voltage, you can calculate or find the distance
                    // to the reflective object according to the figures
                    //on page 4 or page 5 of the datasheet of the GP2Y0A21YK.


///////////////
// Pin list //
/////////////

const int connect_led_pin = 2;  // pin used for connect status LED. Doubles up as Calibration failed

//////////////////////////////////////
// Motor Speed  and direction task //
////////////////////////////////////

// Function to set Motor A and B speed as well as direction for a specific motor driver (address)
// Note: 1001 indicates M1 in forward and M2 in reverse direction
// Note: Bit 0 and 1 should be a complement and Bit 1 and 2 should be complement
void Set_MotorSpeed_and_direction(unsigned char MotorSpeedA, unsigned char MotorSpeedB, unsigned char Direction, unsigned char I2C_MotorDriver_Addr)
{
  //Convert 0-100% to analog values 0-255
  MotorSpeedA = map(MotorSpeedA, 0, 100, 0, 255);
  MotorSpeedB = map(MotorSpeedB, 0, 100, 0, 255);

  // Speed
  Wire.beginTransmission(I2C_MotorDriver_Addr); // transmit to specified address
  Wire.write(MotorSpeedSet);                    // set pwm header
  Wire.write(MotorSpeedA);                      // send pwma
  Wire.write(MotorSpeedB);                      // send pwmb
  Wire.endTransmission();               	      // stop transmitting

  // Direction
  Wire.beginTransmission(I2C_MotorDriver_Addr); // transmit to device I2CMotorDriverAdd
  Wire.write(DirectionSet);                     // Direction control header
  Wire.write(Direction);                        // send direction control information
  Wire.write(Nothing);                          // need to send this byte as the third byte(no meaning)
  Wire.endTransmission();                       // stop transmitting
}

///////////////////////
// Global Variables //
/////////////////////
String cmdInput; // Command received from BLE- Auto:Stop, Auto:Up, Auto:Right, Auto:Left, Auto:Back, Auto:Auto
String lastCmd="";
int lastTurn=0;
int turnTime=1000;

/////////////////////////////////
// BLE handle and definitions //
///////////////////////////////

BLEPeripheral blePeripheral;
BLEService uartService = BLEService("6E400001B5A3F393E0A9E50E24DCCA9E");
// create characteristics
BLECharacteristic rxCharacteristic = BLECharacteristic("6E400002B5A3F393E0A9E50E24DCCA9E", BLEWriteWithoutResponse, 20);  // == TX on central (central control app)
BLECharacteristic txCharacteristic = BLECharacteristic("6E400003B5A3F393E0A9E50E24DCCA9E", BLENotify , 20); // == RX on central (central control app)

bool connectionStatus = false;

void roverStop(){
  // Turn off all Motors (to be safe)
  Set_MotorSpeed_and_direction(0, 0, 0b1010, I2CMotorDriver_right_Addr);
  Set_MotorSpeed_and_direction(0, 0, 0b0101, I2CMotorDriver_left_Addr);
  Serial.println("Rover Stop");
}

void roverUp(){
  Set_MotorSpeed_and_direction(40, 40, 0b1010, I2CMotorDriver_right_Addr);
  Set_MotorSpeed_and_direction(40, 40, 0b0101, I2CMotorDriver_left_Addr);
  Serial.println("Rover Up");
}

void roverBack(){
  Set_MotorSpeed_and_direction(40, 40, 0b0101, I2CMotorDriver_right_Addr);
  Set_MotorSpeed_and_direction(40, 40, 0b1010, I2CMotorDriver_left_Addr);
  Serial.println("Rover Up");
}

void roverLeft(){
  Set_MotorSpeed_and_direction(100, 100, 0b1010, I2CMotorDriver_right_Addr);
  Set_MotorSpeed_and_direction(1, 1, 0b0101, I2CMotorDriver_left_Addr);
  Serial.println("Rover Left");
}

void roverRight(){
  Set_MotorSpeed_and_direction(1, 1, 0b1010, I2CMotorDriver_right_Addr);
  Set_MotorSpeed_and_direction(100, 100, 0b0101, I2CMotorDriver_left_Addr);
  Serial.println("Rover Right");
}

void roverAvoidLeft(){
  Set_MotorSpeed_and_direction(100, 100, 0b1010, I2CMotorDriver_right_Addr);
  Set_MotorSpeed_and_direction(50, 50, 0b1010, I2CMotorDriver_left_Addr);
  Serial.println("Rover Avoid Left");
  delay(turnTime);
}

void roverAvoidRight(){
  Set_MotorSpeed_and_direction(50, 50, 0b0101, I2CMotorDriver_right_Addr);
  Set_MotorSpeed_and_direction(100, 100, 0b0101, I2CMotorDriver_left_Addr);
  Serial.println("Rover Avoid Right");
  delay(turnTime);
}

void roverAuto(){
  lastCmd=cmdInput;
  Serial.println("Rover Auto");
  if (voltage < 1) {
    roverUp();
  } else if (lastTurn==0) {
    roverAvoidRight();
    lastTurn=1;

  } else {
    roverAvoidLeft();
    lastTurn=0;
  }

}
void fullStop(){
  roverStop();
}

/////////////////
// Setup Loop //
///////////////

void setup()
{
  // Setting up serial connection
  Serial.begin(9600);

  // join i2c bus (address optional for master)
  Wire.begin();

  // wait to make sure I2C is initialized
  delayMicroseconds(10000);

  // specifying connection LED pin as output
  pinMode(connect_led_pin, OUTPUT);

  blePeripheral.setLocalName("4WDUART");
  blePeripheral.setAdvertisedServiceUuid(uartService.uuid());
  // add service, rx and tx characteristics:
  blePeripheral.addAttribute(uartService);
  blePeripheral.addAttribute(rxCharacteristic);
  blePeripheral.addAttribute(txCharacteristic);
  // assign event handlers for connected, disconnected to peripheral
  blePeripheral.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  blePeripheral.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
  rxCharacteristic.setEventHandler(BLEWritten, rxCharacteristicWritten);
  blePeripheral.begin();
  delay(5000);
  Serial.println("BLE UART Peripheral");
}

////////////////
// Main loop //
//////////////

void loop()
{
  // Keep polling over the Peripheral
  blePeripheral.poll();

  // Check BLE connection before executing any code
  if (connectionStatus)
  {
    // Turn on connection LED
    digitalWrite(connect_led_pin, HIGH);
   
    Serial.print(String(cmdInput));
    voltage = getVoltage();
    Serial.print(" sensor voltage  = " );                       
    Serial.println(voltage);

    if (String(cmdInput) == "Auto:Stop") {    
        roverStop();
    } else if ((String(cmdInput) == "Auto:Auto") or (String(lastCmd) == "Auto:Auto")){
        roverAuto();
    } else if (String(cmdInput) == "Auto:Up"){
        roverUp();
    } else if (String(cmdInput) == "Auto:Left"){
        roverLeft();
    } else if (String(cmdInput) == "Auto:Right"){
        roverRight();
    } else if (String(cmdInput) == "Auto:Back"){
        roverBack();
    } else {
        fullStop();
    }
    lastCmd=cmdInput;
  }
  else
  {
     Serial.println("not connected");
    // Turn off connection LED
    digitalWrite(connect_led_pin, LOW);
    
    // Turn off everything to be safe
    fullStop();
  }
} // void loop()

void blePeripheralConnectHandler(BLECentral& central) {
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
  digitalWrite(connect_led_pin, HIGH);
  connectionStatus = true;
}

void blePeripheralDisconnectHandler(BLECentral& central) {
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
  digitalWrite(connect_led_pin, LOW);
  connectionStatus = false;
}

void rxCharacteristicWritten(BLECentral& central, BLECharacteristic& characteristic) {
  // central wrote new value to characteristic, update LED
  Serial.print("Characteristic event, written: ");
  if (characteristic.value()) {       //null pointer check
    int len = characteristic.valueLength(); //get size 
    if (cmdInput) {
      lastCmd=cmdInput;
    }
    cmdInput= "";
    for(int i=0; i<len; i++){
      cmdInput+= (char)*(characteristic.value()+i);
    }
    Serial.println(cmdInput);
  } 
}

//////////////////////////////////////////////////////////
//Get voltage from the sensor connected to analog pin A0//
//Parameter:-void                                       //
//Return:   -float,the voltage of the analog pin        //
//////////////////////////////////////////////////////////
float getVoltage()
{
    int sensor_value;
    int sum;  
    // read the analog in value:
    for (int i = 0;i < 20;i ++)//Continuous sampling 20 times
    {
        sensor_value = analogRead(IR_PROXIMITY_SENSOR); 
        sum += sensor_value;
    }
    sensor_value = sum / 20;
    float voltage;
    voltage = (float)sensor_value*ADC_REF/1024;
    return voltage;
}

Schematics

Base Rover Schematic
How to connect major hardware components for base rover
Ojtwgxki1xtnrjqhdq6w
Autonomous Rover Schematic
How to add proximity sensor
7osuqjvp3gwuh5wr4mmh

Comments

Team members

Owchen
Oliver Chen
  • 1 project
  • 2 followers
Shadeydave
shadeydave
  • 3 projects
  • 12 followers
Default
Prashant Lalwani
  • 1 project
  • 1 follower
Default
Purval Sule
  • 1 project
  • 2 followers

Additional contributors

  • Base obstacle avoidance code by Raad Hashim
  • Base grove motor control code by Prashant Lalwani
  • Base grove motor control code by Purval Sule
  • Uart ble mobile interface by Nordic Semiconductor
  • Arduino101 board and curieble examples by Arduino.cc

Published on

December 5, 2016

Members who respect this project

DefaultDefaultGovknPowerbot0zy8hrvpglybowb4icgaDrieweMerlin arch 4fnrmpnf6jDefault

and 24 others

See similar projects
you might like

Similar projects you might like

Arduino 101 BLE Rover

Project tutorial by shadeydave

  • 3,463 views
  • 0 comments
  • 13 respects

BLE Bot 9000

Project tutorial by 5 developers

  • 24,454 views
  • 7 comments
  • 73 respects

Probability | Autonomous Rover

Project in progress by colepurtzer

  • 8,136 views
  • 19 comments
  • 50 respects

Arduino 101 BLE Rover Remote Control

Project tutorial by shadeydave

  • 4,675 views
  • 4 comments
  • 12 respects

Rocky Rover: Robotic Vision System PixyCam & Arduino 101

Project tutorial by Ron Dagdag

  • 15,082 views
  • 7 comments
  • 104 respects
Add projectSign up / Login