How to build a microcontroller robot

This tutorial is designed to help those looking to build a basic microcontroller robot using off the shelf components. Learn how to build and program an MSP430™ MCU LaunchPad™ development kit plus Sub-1 GHz RF CC110L BoosterPack  plug-in module and the Educational BoosterPack module MK II to create a wireless remote control bot. This project is accessible for students to build on their own or for faculty to implement for freshman intro to advanced mechatronics style courses for simple to advanced robotics development in the classroom and lab.


Hardware Components

Software Apps & Online Services

STEP 1: Select Racerbot Chassis

When selecting a chassis that will be attractive for stocking a class with robotics we need to consider effectiveness and affordability.

Magician Chassis


This classic two wheel, dual level chassis is assembled using screws and standoffs (screwdriver included), and many options for mounting hardware to the platform. This is a solid chassis for classroom robotics. While Sparkfun no longer carries this chassis, it is available through other online retailers for $20-$30.

STEP 2: Select Motor Driver

Because we can't drive the motor(s) directly from a microcontroller (they draw far too much current), we'll need some type of motor controller/driver. This is a device that takes the low power signals from the microcontroller and turns them into high power signals that can be used to drive the motors. They also typically provide some protection circuitry so we don't destroy things if we make a mistake.

A preferred motor control IC for small robots like this is the TI DRV8830. Each DRV8830 can drive one motor at up to 6.8V and 1A. The real beauty of this device is that it is controlled by I2C. So instead of needing 4 PWM pins to drive a motor you only need a single I2C bus to control both speed and direction. This also makes it extremely easy to add additional motor controllers as they can all reside on the same I2C bus.

For this workshop we recommend using the Mini I2C motor driver from Seeed Studio. This board includes a Grove connector, two DRV8830's (i.e. drives two motors), and includes LEDs to show the direction each of the motors is going.


 

STEP 3: Build Robot Chassis

Disassembled parts out of the kit.

  
Attach the motor mount pieces to the main chassis plane.

Screw in the motors making sure the shaft is aligned with the wheel bay using the long screws.

Note that the wire orientation can affect your software. You will either have black wires facing up or red wires facing up. This will change which way is forward and reverse. You can add the red gears to the interior shaft if you would like – but these are only cosmetic.

Attach the bearing standoffs (long) facing up with the included short screws.

Attach the bearing to the standoffs with the included short screws.

Attach the wheels, and thread the motor wires through the center hole.
Attach the standoffs (long) to the 4 edges of the chassis using the included short screws.

Screw together the top chassis plane using the included short screws.

The next step is optional. In order to plug into the Grove I2C Mini Motor Driver we need female connectors. The motors ship with male leads. You can either snip and replace the leads or find a way to adapt the motor driver for male leads.

Snip the ends of the wires and replace with female leads. Use wirestrippers to expose the copper leads and then attach the female connectors.

Attach the motor driver to the bottom layer of the chassis using double sided tape to save time.

Connect the female motor leads to the Grove Mini Motor Driver connectors.

Get your MSP430 LaunchPad kit, CC110L BoosterPack plug-in and Grove Base BoosterPack plug-in ready.

Replace the top of the chassis and use double sided tape to mount the electronics. You can mount the hardware wherever you’d like, but the “front” will give room for the battery pack later.

Add the MSP430 LaunchPad kit to the top of the Grove Base BoosterPack plug-in.

Add the CC110L BoosterPack plug-in to finish the stack. Be sure the pins are all aligned correctly.

Note the 4x AA battery pack ships with a barrel connector which isn't supported on the LaunchPad kit. You can either modify the wire or use another type of power source such as a battery BoosterPack plug-in.

Lastly stick on the battery pack. You likely need to modify the wire connection to female leads. Now you have a solid and modular robotic vehicle prototype.

 

STEP 4: Build Remote Controller

Take out your CC110L BoosterPack plug-in and make sure it is oriented with the blue module on the right side.

Take out your Battery Fueltank BoosterPack plug-in. Place the Battery BoosterPack plug-in on top of the CC110L BoosterPack plug-in and align the connectors.

Take out your MSP430 LaunchPad kit and place it on top of the stack, aligning the connectors.
Finally, stack the Educational BoosterPack plug-in MKII on top. 
Now you have a functional remote controller.

 

STEP 5: Program Robot

Open up Energia and copy the code into a blank sketch. You can save it as MSP430Racerbot.ino.

/* MSP430Racerbot.ino
*
* MSP430 LaunchPad + Grove I2C Mini Motor Driver v1.0 + CC110L BoosterPack
*
* The recommended robot chassis to use is the Adafruit Mini Robot Rover or
* Magician Chassis
*
* The default I2C address of the Grove Mini I2C Motor Driver v1.0 is 0xC4
* and 0xC0. To work with the LaunchPad we need to perform a bitwise right
* shift of one bit (ex. 0xC0 >> 1) which will make the new addresses used
* in this program 0x60 and 0x62
*/
/**
*  WirelessTest - test transceiver sketch using AIR430Boost FCC driver.
*  Copyright (C) 2012-2013 Anaren Microwave, Inc.
*
*  This library 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
*
*  This example demonstrates usage of the AIR430BoostETSI library which uses
*  the 430Boost-CC110L AIR Module BoosterPack created by Anaren Microwave, Inc.
*  and available through the TI eStore, for the European Union.
*
*  ----------------------------------------------------------------------------
*
*  Note: This file is part of AIR430Boost.
*
*  ----------------------------------------------------------------------------
*
*  Description
*  ===========
*
*  Each radio will send a message consisting of: 1 byte counter, 5 byte static
*  text. The counter will count from 0 to 9 and will rollover. Each radio will
*  wait in receive mode for approximately one second. Upon receiving data, or
*  timeout of one second, the radio receive function will return. If valid data
*  was received, the radio's receiverOn() method will return the number of bytes
*  that were received. In this example, the data can be monitored on the serial
*  port (please refer to printTxData() and printRxData() functions).
*
*  ----------------------------------------------------------------------------
*
*  This example assumes that two BoosterPacks will be used to showcase the
*  wireless radio communication functionality. This same code should be
*  programmed to both LaunchPad development kits.
*
*  This BoosterPack relies on the SPI hardware peripheral and two additional
*  GPIO lines for SPI chip-select and GDO0 for packet handling. They use pins 18
*  and 19 respectively.
*
*  In the default configuration, this BoosterPack is not compatible with an
*  external crystal oscillator. This can be changed, if necessary, and would
*  require reconfiguration of the BoosterPack hardware and changes to the
*  AIR430BoostFCC library. Refer to the BoosterPack User's Manual if necessary.
*
*  For complete information, please refer to the BoosterPack User's Manual available at:
*  https://www.anaren.com/air/cc110l-air-module-boosterpack-embedded-antenna-module-anaren
*  To purchase the 430Boost-CC110L AIR module BoosterPack kit, please visit the TI eStore at:
*  https://estore.ti.com/430BOOST-CC110L-CC110L-RF-Module-BoosterPack-P2734.aspx
*/
// The AIR430BoostFCC library uses the SPI library internally. Energia does not
// copy the library to the output folder unless it is referenced here.
// The order of includes is also important due to this fact.
#include
#include
#include
#include "SparkFunMiniMoto.h"  // Include the MiniMoto library
// -----------------------------------------------------------------------------
/**
*  Global data
*/
// Data to write to radio TX FIFO (60 bytes MAX.)
unsigned char txData[6] = { 'S', 'A', 'i', 'r', '!', '\0' };   
// Data to read from radio RX FIFO (60 bytes MAX.)
unsigned char rxData[6] = { 'S', 'S', 'S', '\0', '\0', '\0' };
// Create two MiniMoto instances, with different address settings.
MiniMoto motor0(0xC4 >> 1); // A1 = 1, A0 = clear CH1
MiniMoto motor1(0xC0 >> 1); // A1 = 1, A0 = 1 (default) CH2
int duty = 0;
// -----------------------------------------------------------------------------
// Debug print functions
void printTxData()
{
Serial.print("TX (DATA): ");
Serial.println((char*)txData);
}
void printRxData()
{
/**
*  The following illustrates various information that can be obtained when
*  receiving a message. This includes: the received data and associated
*  status information (RSSI, LQI, and CRC_OK bit).
*/
Serial.print("RX (DATA, RSSI, LQI, CRCBIT): ");
Serial.print("(");
Serial.print((char*)rxData);
Serial.print(", ");
Serial.print(Radio.getRssi());
Serial.print(", ");
Serial.print(Radio.getLqi());
Serial.print(", ");
Serial.print(Radio.getCrcBit());
Serial.println(")");
}
// -----------------------------------------------------------------------------
// Main example
void setup()
{
// The radio library uses the SPI library internally, this call initializes
// SPI/CSn and GDO0 lines. Also setup initial address, channel, and TX power.
Radio.begin(0x01, CHANNEL_4, POWER_MAX);
// Setup serial for debug printing.
Serial.begin(9600);
// join i2c bus (address optional for master)
Wire.begin();
Serial.println("Robot is listening...");
/**
*  Setup LED for example demonstration purposes.
*
*  Note: Set radio first to ensure that GDO2 line isn't being driven by the
*  MCU as it is an output from the radio.
*/
pinMode(RED_LED, OUTPUT);     // initialize the RGB LED
pinMode(GREEN_LED, OUTPUT);   // initialize the RGB LED
digitalWrite(RED_LED, LOW);   // set the LED off
digitalWrite(GREEN_LED, LOW); // set the LED off
}
void loop()
{
digitalWrite(GREEN_LED, HIGH);
delay(20);
digitalWrite(GREEN_LED, LOW);
// Turn on the receiver and listen for incoming data. Timeout after 1 seconds.
// The receiverOn() method returns the number of bytes copied to rxData.
if (Radio.receiverOn(rxData, sizeof(rxData), 1000) > 0)
{
/**
*  Data has been received and has been copied to the rxData buffer provided
*  to the receiverOn() method. At this point, rxData is available. See
*  printRxData() for more information.
*/
digitalWrite(RED_LED, HIGH);
printRxData();                  // RX debug information
if(rxData[0] == 'F'){
Serial.println("Forward!");
if(rxData[1] == 'S'){
motor0.MotoDrive(20);
motor1.MotoDrive(20);
}
else if(rxData[1] == 'F') {
motor0.MotoDrive(100);
motor1.MotoDrive(100);
}
//driveMotor(0x60); // left wheel HIGH
//driveMotor(0x62); // right wheel HIGH
}
else if(rxData[0] == 'L'){
Serial.println("Left Turn!");
if(rxData[1] == 'S'){
motor0.MotoDrive(20);
motor1.MotoStop();
}
else if(rxData[1] == 'F'){
motor0.MotoDrive(100);
motor1.MotoStop();
}
//stopMotor(0x60);  // left wheels LOW
//driveMotor(0x62);  // right wheels HIGH
}
else if(rxData[0] == 'R'){
Serial.println("Right Turn!");
if(rxData[1] == 'S'){
motor0.MotoStop();
motor1.MotoDrive(20);
}
else if(rxData[1] == 'F'){
motor0.MotoStop();
motor1.MotoDrive(100);
}
//driveMotor(0x60);  // left wheels HIGH
//stopMotor(0x62);   // right wheels LOW
}
else if(rxData[0] == 'B'){
Serial.println("Reverse!");
if(rxData[1] == 'S'){
motor0.MotoDrive(-20);
motor1.MotoDrive(-20);
}
else if(rxData[1] == 'F'){
motor0.MotoDrive(-100);
motor1.MotoDrive(-100);
}
}
else{
Serial.println("Stop!");
motor0.MotoStop();
motor1.MotoStop();
//stopMotor(0x60);  // left wheels LOW
//stopMotor(0x62);   // right wheels LOW
}
}
digitalWrite(RED_LED, LOW);
}
//This function will drive the DRV8830 motor driver
//found on
void driveMotor(byte addr)
{
Serial.println("begin drive tx");
Wire.beginTransmission(addr); // transmit to device at device i2c address
Serial.println("address");
Wire.write(0x01);             // sends first bit
Wire.write(0x80);             // sends one byte 
Serial.println("before stop");
Wire.endTransmission(addr);       // transmit to device at device i2c address
Serial.println("end of transmission");
Wire.beginTransmission(addr); // stop transmitting
Wire.write(0x00);             // sends first bit
Wire.write(0xFE);             // sends one byte
Wire.endTransmission(addr);       // stop transmitting
Serial.println("end of transmission");
delay(100);
}
// Stop the motor by providing a heavy load on it.
void brakeMotor(byte addr)
{
Serial.println("begin brake tx");
Wire.beginTransmission(addr); // transmit to device at device i2c address
Wire.write(0x00);             // sends first bit
Wire.write(0x03);             // sends one byte 
Wire.endTransmission();       // stop transmitting
Serial.println("end of transmission");
delay(100);
}
// Coast to a stop by hi-z'ing the drivers.
void stopMotor(byte addr)
{
Serial.println("begin stop tx");
Wire.beginTransmission(addr); // transmit to device at device i2c address
Wire.write(0x01);             // sends first bit
Wire.write(0x00);             // sends one byte 
Wire.endTransmission();       // stop transmitting
Serial.println("end of transmission");
delay(100);

}

 

Add a new tab for SparkFunMiniMoto.h.

Add a new tab for SparkFunMiniMoto.cpp

STEP 7: Program the controller

Open up Energia and copy the code into a blank sketch. You can save it as MSP430Racerbot.ino.

Open a new sketch in Energia and save it as RacerbotWirelessController.ino.

Conclusion

This is a very complex system but done relatively easily thanks to the modular hardware of the TI LaunchPad and intuitive software of Energia. Additionally you can add more sensors to the Racerbot to add features and capabilities that can teach important mechatronics concepts.

Have fun trying out your new racerbot!