Kevin Viet Le
Published

Scout Robot Car

A proof of concept robot car that can be used for basic scenario scouting.

IntermediateWork in progress10 hours3,780
Scout Robot Car

Things used in this project

Hardware components

Makerfire 4-wheel Robot Smart Car Chassis Kits Car Model with Speed Encoder for Arduino
×1
Ultra Sonic Sensors
×1
Walabot
Walabot
×1
Bluetooth Sensor
×1
Infrared Remote Control Module IR Receiver Module
×1
Skywolfeye 2PCS 5800mAh Li-ion 18650 3.7V Rechargeable Battery + Dual Charger(NOT AA)
×1
DC Speed Motor
×1
Line Tracking Module
×1
Arduino UNO & Genuino UNO
Arduino UNO & Genuino UNO
×1
Arduino Expansion Shield
×1
Battery Box
×1
9g Steering Engine
×1
Ultrasonic Sensor Holder
×1
L298 Motor Driving Board
×1
Arduino 101 & Genuino 101
Arduino 101 & Genuino 101
×1
DHT22 Temperature Sensor
DHT22 Temperature Sensor
×1
Humidity and Temperature Sensor
Adafruit Humidity and Temperature Sensor
×1

Software apps and online services

Arduino IDE
Arduino IDE
BlueSPP

Hand tools and fabrication machines

Screwdriver
Allen Wrench
OpenBuilds Allen Wrench
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Code

Walabot

Python
A work in progress (needs more fixing) for the Walabot module to detect objects - figure out the distance between the robot and that object and record it on a plot plus confirming that it has seen that object before.
from __future__
import print_function, division
from math
import sin, cos, radians
import WalabotAPI
try: #for Python 2
import Tkinter as tk
except ImportError: #for Python 3
import tkinter as tk
try: #for Python 2
range = xrange
except NameError:
    pass


class GUI(tk.Tk):

    def __init__(self):
    tk.Tk.__init__(self)
self.title('Walabot SeeThroughDemo')# window title
self.option_add("*Font", "TkFixedFont")# default monospace font
self.mainFrame = MainFrame(self)# init window conponents
self.mainFrame.pack()


class Walabot:

    def __init__(self):
    self.wlbt = WalabotAPI
self.WalabotError = self.wlbt.WalabotError
self.wlbt.Init()
self.wlbt.SetSettingsFolder()

def Connect(self):
    self.wlbt.ConnectAny()
self.isConnected = True
self.wlbt.SetProfile(self.wlbt.PROF_SHORT_RANGE_IMAGING)
self.wlbt.SetDynamicImageFilter(self.wlbt.FILTER_TYPE_NONE)
self.wlbt.SetArenaX(-4, 4, 0.8)
self.wlbt.SetArenaY(-6, 4, 0.8)
self.wlbt.SetArenaZ(3, 8, 0.5)
self.wlbt.SetThreshold(50)
self.wlbt.Start()
except self.wlbt.WalabotError as err:
    if err.code != 19: #'WALABOT_INSTRUMENT_NOT_FOUND'
raise err

def Calibrate(self):
    self.wlbt.StartCalibration()
while self.wlbt.GetStatus()[0] == self.wlbt.STATUS_CALIBRATING:
    self.wlbt.Trigger()

def isTargets(self):
    self.wlbt.Trigger()
return True
if self.wlbt.GetImagingTargets()
else False

def stopAndDisconnect(self):
    self.wlbt.Stop()
self.wlbt.Disconnect()

def print_targets(targets):
    system("cls"
        if platform == "win32"
        else "clear")# clear the screen
if not targets:
    print("No targets")
return
d_min = min(targets, key = lambda t: t[2])[2]# closest target
d_amp = max(targets, key = lambda t: t[3])[2]#
"strongest"
target
if d_min == d_amp:
    print("THE DISTANCE IS {:3.0f}\n".format(d_min))
else :
    print("CALCULATING...\n")

def main():
    wlbt = Walabot()
wlbt.connect()
if not wlbt.isConnected:
    print("Not Connected")
else :
    print("Connected")
wlbt.start()
while True:
    print_targets(wlbt.get_targets())

class MainFrame(tk.Frame):

    def __init__(self, master):
    tk.Frame.__init__(self, master)
self.statusPanel = StatusPanel(self)
self.ctrlPanel = ControlPanel(self)
self.statusPanel.pack()
self.ctrlPanel.pack(expand = True, fill = "both")

def initLoop(self):
    try:
    self.ctrlPanel.connLabel.config(text = "CONNECTING")
wlbt.Connect()
self.ctrlPanel.connLabel.config(text = "CALIBRATING")
wlbt.Calibrate()
self.ctrlPanel.connLabel.config(text = "CONNECTED")
self.loopId = self.after_idle(self.loop)
except wlbt.WalabotError:
    self.stopLoop()

def loop(self):
    try:
    if wlbt.isTargets():
    self.statusPanel.statusLabel.config(
        text = "Treasure Found!", bg = "gold"
    )
else :
    self.statusPanel.statusLabel.config(
        text = "Scanning", bg = "snow1"
    )
self.loopId = self.after_idle(self.loop)
except wlbt.WalabotError:
    self.stopLoop()

def stopLoop(self):
    wlbt.stopAndDisconnect()
self.statusPanel.statusLabel.config(text = "")
self.ctrlPanel.connLabel.config(text = "DISCONNECTED")
self.after_cancel(self.loopId)


class StatusPanel(tk.Frame):

    def __init__(self, master):
    tk.Frame.__init__(self, master)
self.statusLabel = tk.Label(self, width = 30, height = 5, bg = "snow1")
self.statusLabel.pack()


class ControlPanel(tk.Frame):

    def __init__(self, master):
    tk.Frame.__init__(self, master)
self.strtBtn = tk.Button(
    self, text = "Start", width = 6, command = self.master.initLoop
)
self.stopBtn = tk.Button(
    self, text = "Stop", width = 6, command = self.master.stopLoop
)
self.connLabel = tk.Label(self, text = "DISCONNECTED")
self.strtBtn.pack(side = "left")
self.stopBtn.pack(side = "left")
self.connLabel.pack(side = "right")



if __name__ == '__main__':
    wlbt = Walabot()
guiApp = GUI()
guiApp.mainloop()

Remote Monitoring with Azure

JavaScript
As I start to move away from the arduino INO language, I'll be using Johnny five JS to make this robot car more advanced. This file along with my .json file will be stored in a local directory and run so it can call Microsoft Azure services and authenticate to receive sensor data from my temperature/humidity sensors. Code credits to authors of BLE Bot 9000 project on Hackster.io and Microsoft.
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

'use strict';

// Azure IoT packages
var Protocol = require('azure-iot-device-http').Http;
var Client = require('azure-iot-device').Client;
var ConnectionString = require('azure-iot-device').ConnectionString;
var Message = require('azure-iot-device').Message;

var keypress = require('keypress');
var five = require("johnny-five"),
  board, motor, led;
var BLESerialPort = require('ble-serial').SerialPort;
var bleSerial = new BLESerialPort();
var board = new five.Board({port: bleSerial, repl: false});

var hostName        = '<IOTHUB_HOST_NAME>';
var deviceId        = '<DEVICE_ID>';
var sharedAccessKey = '<SHARED_ACCESS_KEY>';

// String containing Hostname, Device Id & Device Key in the following formats:
//  "HostName=<iothub_host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"
var connectionString = 'HostName=' + hostName + ';DeviceId=' + deviceId + ';SharedAccessKey=' + sharedAccessKey;

// Sensor data
var temperature = 0;
var humidity = 0;
var externalTemperature = 0;

// Create IoT Hub client
var client = Client.fromConnectionString(connectionString, Protocol);

// Helper function to print results for an operation
function printErrorFor(op) {
  return function printError(err) {
    if (err) console.log(op + ' error: ' + err.toString());
  };
}

// Send device meta data
var deviceMetaData = {
  'ObjectType': 'DeviceInfo',
  'IsSimulatedDevice': 0,
  'Version': '1.0',
  'DeviceProperties': {
    'DeviceID': deviceId,
    'HubEnabledState': 1,
    'CreatedTime': '2015-09-21T20:28:55.5448990Z',
    'DeviceState': 'normal',
    'UpdatedTime': null,
    'Manufacturer': 'Intel',
    'ModelNumber': 'Edison',
    'SerialNumber': '12345678',
    'FirmwareVersion': '159',
    'Platform': 'node.js',
    'Processor': 'Intel',
    'InstalledRAM': '64 MB',
    'Latitude': 47.617025,
    'Longitude': -122.191285
  },
  'Commands': [{
    'Name': 'SetTemperature',
    'Parameters': [{
      'Name': 'Temperature',
      'Type': 'double'
    }]
  },
    {
      'Name': 'SetHumidity',
      'Parameters': [{
        'Name': 'Humidity',
        'Type': 'double'
      }]
    }]
};


board.on("ready", function() {
  var temp = new five.Temperature({
    pin: "A0",
    controller: "GROVE"
  });
  
  // --------------CONTROL.JS PART --------------------
  
   //load atafruit motor shield configs
  var configs = five.Motor.SHIELD_CONFIGS.ADAFRUIT_V2;
  //create each motor
  var motor1 = new five.Motor(configs.M1);
  var motor2 = new five.Motor(configs.M2);
  var motor3 = new five.Motor(configs.M3);
  var motor4 = new five.Motor(configs.M4);

  //set high level drive functions
  function forward(speed){
    motor1.reverse(speed);
    motor2.forward(speed);
    motor3.forward(speed);
    motor4.reverse(speed);
    }

  function reverse(speed){
    motor1.forward(speed);
    motor2.reverse(speed);
    motor3.reverse(speed);
    motor4.forward(speed);
    }

  function left(speed){
    motor1.forward(speed);
    motor2.forward(speed);
    motor3.forward(speed);
    motor4.forward(speed);
    }

  function right(speed){
    motor1.reverse(speed);
    motor2.reverse(speed);
    motor3.reverse(speed);
    motor4.reverse(speed);
    }

    function stop(){
      motor1.stop();
      motor2.stop();
      motor3.stop();
      motor4.stop();
      }

  // make `process.stdin` begin emitting "keypress" events
    keypress(process.stdin);

    // listen for the "keypress" event
  process.stdin.on('keypress', function (ch, key) {
    console.log('got "keypress"', key);

    //make it so you can close the process with ctrl-c...
    if (key && key.ctrl && key.name == 'c') {
          process.exit();
        }

    if (key && key.name == 'w') {
      forward(255);
      console.log('forward command');

    }

    if (key && key.name == 's') {
      reverse(255);
      console.log('reverse command');

    }

    if (key && key.name == 'a') {
      left(255);
      console.log('left command');

    }

    if (key && key.name == 'd') {
      right(255);
      console.log('right command');

    }

    if (key && key.name == 'q') {
      stop();
      console.log('stop');

    }

  });

  process.stdin.setRawMode(true);

// ------------------- End Control.js ----------------------

  client.open(function (err, result) {
    if (err) {
      printErrorFor('open')(err);
    } else {
      console.log('Sending device metadata:\n' + JSON.stringify(deviceMetaData));
      client.sendEvent(new Message(JSON.stringify(deviceMetaData)), printErrorFor('send metadata'));

      client.on('message', function (msg) {
        console.log('receive data: ' + msg.getData());

        try {
          var command = JSON.parse(msg.getData());

          switch (command.Name) {
            case 'SetTemperature':
              temperature = command.Parameters.Temperature;
              console.log('New temperature set to :' + temperature + 'F');
              client.complete(msg, printErrorFor('complete'));
              break;
            case 'SetHumidity':
              humidity = command.Parameters.Humidity;
              console.log('New humidity set to :' + humidity + '%');
              client.complete(msg, printErrorFor('complete'));
              break;
            default:
              console.error('Unknown command: ' + command.Name);
              client.reject(msg, printErrorFor('complete'));
              break;
          }
        }
        catch (err) {
          printErrorFor('parse received message')(err);
          client.reject(msg, printErrorFor('reject'));
        }
      });

      // start event data send routing
      var sendInterval = setInterval(function () {
        temperature = temp.celsius;
        var data = JSON.stringify({
          'DeviceID': deviceId,
          'Temperature': temperature,
          'Humidity': humidity,
          'ExternalTemperature': externalTemperature
        });

        console.log('Sending device event data:\n' + data);
        client.sendEvent(new Message(data), printErrorFor('send event'));
      }, 1000);

      client.on('error', function (err) {
        printErrorFor('client')(err);
        if (sendInterval) clearInterval(sendInterval);
        client.close();
      });
    }
  });
});

Json File that goes along with the .js file

JavaScript
Code credits to Microsoft
{
  "name": "azure-samples-node-edison-rm",
  "version": "0.0.1",
  "private": true,
  "description": "Remote monitoring sample demonstrating how to use the Azure IoT device SDK for Node.js on the Intel Edison",
  "author": "Microsoft Corp.",
  "license": "MIT",
  "dependencies": {
    "azure-iot-common": "1.0.2",
    "azure-iot-device": "1.0.2",
    "azure-iot-device-amqp": "1.0.2",
    "azure-iot-device-http": "1.0.2",
    "azure-iot-device-mqtt": "1.0.2",
    "edison-io": "^0.9.4",
    "johnny-five": "^0.9.33"
  },
  "devDependencies": {
    "jshint": "^2.8.0"
  },
  "scripts": {
    "lint": "jshint --show-non-errors .",
    "test": "npm -s run lint"
  }
}

Old Arduino code for obstacle avoidance

Arduino
Utilizing the ultrasonic sensor to move the robot around based on obstacles. Code credits to Elegoo
#include <Servo.h> //servo library
Servo myservo; // create servo object to control servo
int Echo = A4;  
int Trig = A5; 
int in1 = 6;
int in2 = 7;
int in3 = 8;
int in4 = 9;
int ENA = 5;
int ENB = 10;
int ABS = 110;
int rightDistance = 0,leftDistance = 0,middleDistance = 0 ;
void _mForward()
{
 analogWrite(ENA,ABS);
 analogWrite(ENB,ABS);
 digitalWrite(in1,LOW);
 digitalWrite(in2,HIGH);
 digitalWrite(in3,LOW);
 digitalWrite(in4,HIGH);
 Serial.println("go forward!");
}

void _mBack()
{
 analogWrite(ENA,ABS);
 analogWrite(ENB,ABS);
 digitalWrite(in1,HIGH);
 digitalWrite(in2,LOW);
 digitalWrite(in3,HIGH);
 digitalWrite(in4,LOW);
 Serial.println("go back!");
}

void _mleft()
{
 analogWrite(ENA,ABS);
 analogWrite(ENB,ABS);
 digitalWrite(in1,LOW);
 digitalWrite(in2,HIGH);
 digitalWrite(in3,HIGH);
 digitalWrite(in4,LOW);
 Serial.println("go left!");
}

void _mright()
{
 analogWrite(ENA,ABS);
 analogWrite(ENB,ABS);
 digitalWrite(in1,HIGH);
 digitalWrite(in2,LOW);
 digitalWrite(in3,LOW);
 digitalWrite(in4,HIGH);
 Serial.println("go right!");
} 
void _mStop()
{
  digitalWrite(ENA,LOW);
  digitalWrite(ENB,LOW);
  Serial.println("Stop!");
} 
 /*Ultrasonic distance measurement Sub function*/
int Distance_test()   
{
  digitalWrite(Trig, LOW);   
  delayMicroseconds(2);
  digitalWrite(Trig, HIGH);  
  delayMicroseconds(20);
  digitalWrite(Trig, LOW);   
  float Fdistance = pulseIn(Echo, HIGH);  
  Fdistance= Fdistance/58;       
  return (int)Fdistance;
}  

void setup() 
{ 
  myservo.attach(3);// attach servo on pin 3 to servo object
  Serial.begin(9600);     
  pinMode(Echo, INPUT);    
  pinMode(Trig, OUTPUT);  
  pinMode(in1,OUTPUT);
  pinMode(in2,OUTPUT);
  pinMode(in3,OUTPUT);
  pinMode(in4,OUTPUT);
  pinMode(ENA,OUTPUT);
  pinMode(ENB,OUTPUT);
  _mStop();
} 

void loop() 
{ 
    myservo.write(90);//setservo position according to scaled value
    delay(500); 
    middleDistance = Distance_test();
    #ifdef send
    Serial.print("middleDistance=");
    Serial.println(middleDistance);
    #endif

    if(middleDistance<=20)
    {     
      _mStop();
      delay(500);                         
      myservo.write(5);          
      delay(1000);      
      rightDistance = Distance_test();

      #ifdef send
      Serial.print("rightDistance=");
      Serial.println(rightDistance);
      #endif

      delay(500);
       myservo.write(90);              
      delay(1000);                                                  
      myservo.write(180);              
      delay(1000); 
      leftDistance = Distance_test();

      #ifdef send
      Serial.print("leftDistance=");
      Serial.println(leftDistance);
      #endif

      delay(500);
      myservo.write(90);              
      delay(1000);
      if(rightDistance>leftDistance)  
      {
        _mright();
        delay(180);
       }
       else if(rightDistance<leftDistance)
       {
        _mleft();
        delay(180);
       }
       else if((rightDistance<=20)||(leftDistance<=20))
       {
        _mBack();
        delay(180);
       }
       else
       {
        _mForward();
       }
    }  
    else
        _mForward();                     
}

Old Arduino code for Bluetooth mode

Arduino
Credits to elegoo
int LED=13;
volatile int state = LOW;
char getstr;
int in1=6;
int in2=7;
int in3=8;
int in4=9;
int ENA=5;
int ENB=10;
int ABS=135;
void _mForward()
{ 

    digitalWrite(ENA,HIGH);
  digitalWrite(ENB,HIGH);
  digitalWrite(in1,HIGH);
  digitalWrite(in2,LOW);
  digitalWrite(in3,HIGH);
  digitalWrite(in4,LOW);
  Serial.println("go back!");
  

}
void _mBack()
{
  digitalWrite(ENA,HIGH);
  digitalWrite(ENB,HIGH);
  digitalWrite(in1,LOW);
  digitalWrite(in2,HIGH);
  digitalWrite(in3,LOW);
  digitalWrite(in4,HIGH);
  Serial.println("go forward!");
}
void _mleft()
{
  analogWrite(ENA,ABS);
  analogWrite(ENB,ABS);
  digitalWrite(in1,HIGH);
  digitalWrite(in2,LOW);
  digitalWrite(in3,LOW);
  digitalWrite(in4,HIGH);
  Serial.println("go left!");
}
void _mright()
{
  analogWrite(ENA,ABS);
  analogWrite(ENB,ABS);
  digitalWrite(in1,LOW);
  digitalWrite(in2,HIGH);
  digitalWrite(in3,HIGH);
  digitalWrite(in4,LOW);
  Serial.println("go right!");
}
void _mStop()
{
  digitalWrite(ENA,LOW);
  digitalWrite(ENB,LOW);
  Serial.println("Stop!");
}
void stateChange()
{
  state = !state;
  digitalWrite(LED, state);  
}
void setup()
{ 
  pinMode(LED, OUTPUT);
  Serial.begin(9600);
  pinMode(in1,OUTPUT);
  pinMode(in2,OUTPUT);
  pinMode(in3,OUTPUT);
  pinMode(in4,OUTPUT);
  pinMode(ENA,OUTPUT);
  pinMode(ENB,OUTPUT);
  _mStop();
}
void loop()
  { 
  getstr=Serial.read();
 if(getstr=='f')
  {
    _mForward();
  }
  else if(getstr=='b')
  {
    _mBack();
    delay(200);
  }
  else if(getstr=='l')
  {
    _mleft();
    delay(200);
  }
  else if(getstr=='r')
  {
    _mright();
    delay(200);
  }
  else if(getstr=='s')
  {
     _mStop();     
  }
  else if(getstr=='A')
  {
  stateChange();
  }
}

Credits

Kevin Viet Le

Kevin Viet Le

6 projects • 6 followers
Former 2-year ambassador for Hackster.io

Comments