Spring 2016 Pathfinder: Software Design
By:
Juan Acosta (Electronics & Control – MCU Subsystem and Firmware)
Table of Contents
Software System Block Diagram:
The figure above depicts the software side of the Pathfinder. First, commands will be sent through Bluetooth and received through Serial communication ports on the Arduino Mega. Then the Command Handler will decode the telemetry packets being sent and appropriate an action unique to each packet ID. The VHN5019 Motor shield will implement the movement of the Pathfinder. The PCA9685 Servo driver will control the pan and tilt servos. Additionally, the use of ultrasonic sensors will provide feedback for obstacle detection or collision. Lastly, we will create a custom Arxterra command to control our L.E.D. headlights.
Arduino Code for controlling servos through Coolterm:
The following code snippet was used to test the functionality of the PCA9685 Servo Driver and how to gain a better understanding for servo control. For testing purposes, we used the Coolterm application on a laptop to demonstrate wireless bluetooth control of the servos. The code provided will help future projects in the process of initializing bluetooth communication, transmission of data, and later the creation of custom Arxterra commands.
///////////////////////////////////////////////////////////////////////////////
// The following code was written, tested and debugged by Juan Acosta for
// testing pan and tilt servo control through two wire communication (I2C)
// using the HC-06 to implement commands being sent from the COOLTERM application
// from a laptop or phone to the arduino.
// Group: Pathfinder Spring 2016
// Electronics and Control: Juan Acosta (MCU Subsystem and Control Firmware)
///////////////////////////////////////////////////////////////////////////////
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
///////////////////////////////////////////////////////////////////////////////
// following are connections required for HC06 module:
// connect BT module TX to RX0
// connect BT module RX to TX0
// connect BT Vcc to 5V, GND to GND
///////////////////////////////////////////////////////////////////////////////
// following are connections required for PCA9685 Servo Driver:
// connect V+ to 5V, GND to GND (servo power terminals)
// connect Vcc to 5V, GND to GND
// connect SDA to analog pin A4 (required for I2C bus control on arduino UNO)
// if using arduino MEGA SDA has dedicated pin on PIN20
// connect SCL to analog pin A5 (required for I2C bus control on arduino UNO)
// if using arduino MEGA SCL has dedicated pin on PIN21
// connect pan servo plug to 9
// connect tilt servo plug to 11
///////////////////////////////////////////////////////////////////////////////
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN 0 // this is the ‘minimum’ pulse length count
// (for Pan = facing left)(for tilt = facing down)
#define SERVOMAX 500 // this is the ‘maximum’ pulse length count
// (for Pan = facing right)(for tilt = facing up)
// The limits for the pan will be from 0 degrees to 180 degrees of view in steps
// of 45
// The limits for the tilt will be from 45 degrees to 135 degrees of view in
// steps of 45
void setup() {
Serial2.begin(9600); // set the data rate for the Serial Port
pwm.begin();
pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates
yield();
}
// Character commands list:
// (“Send ‘0’ pan facing left (180 degrees)”);
// (“Send ‘1’ pan facing diagonal left (135 degrees)”);
// (“Send ‘2’ pan facing center (90′ degrees)”);
// (“Send ‘3’ pan facing diagonal right (45′ degrees)”);
// (“Send ‘4’ pan facing right (0′ degrees)”);
// (“Send ‘5’ tilt facing down (-45 degrees)”);
// (“Send ‘6’ tilt facing center (0 degrees)”);
// (“Send ‘7’ tilt facing up (45 degrees)”);
char a; // stores incoming character from other device (phone, tablet, or laptop)
void loop()
{
if (Serial2.available()) // if text arrived in from hardware serial…
{
a=(Serial2.read());
if (a==’4′) // face right
{
Serial.println(” pan facing right (0′ degrees)”);
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm.setPWM(9, 0, pulselen);
}
delay(1000);
}
if (a==’3′) // face right at an angle (diagonal right)
{
Serial.println(“pan facing diagonal right (45′ degrees)”);
for (uint16_t pulselen = SERVOMIN; pulselen < 375; pulselen++) {
pwm.setPWM(9, 0, pulselen);
}
delay(1000);
}
if (a==’2′) // face straight (centered)
{
Serial.println(“pan facing center (90′ degrees)”);
for (uint16_t pulselen = SERVOMIN; pulselen < 250; pulselen++) {
pwm.setPWM(9,0,pulselen);
}
delay(1000);
}
if (a==’0′) // face left
{
Serial.println(“pan facing left (180 degrees)”);
for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen–) {
pwm.setPWM(9, 0, pulselen);
}
delay(1000);
}
if (a==’1′) // face left at an angle (diagonal left)
{
Serial.println(” pan facing diagonal left (135 degrees)”);
for (uint16_t pulselen = SERVOMAX; pulselen > 125; pulselen–) {
pwm.setPWM(9, 0, pulselen);
}
delay(1000);
}
if (a==’5′) // face down (-45 degrees)
{
Serial.println(“tilt facing down (-45 degrees)”);
for (uint16_t pulselen = SERVOMAX; pulselen > 125; pulselen–) {
pwm.setPWM(11, 0, pulselen);
}
delay(1000);
}
if (a==’6′) // face straight (centered)
{
Serial.println(“tilt facing center (0 degrees)”);
for (uint16_t pulselen = SERVOMIN; pulselen < 250; pulselen++) {
pwm.setPWM(11,0,pulselen);
}
delay(1000);
}
if (a==’7′) // face right at an angle (diagonal right)
{
Serial.println(“tilt facing up (45 degrees)”);
for (uint16_t pulselen = SERVOMIN; pulselen < 375; pulselen++) {
pwm.setPWM(11, 0, pulselen);
}
delay(1000);
}
if (a==’?’) // commands list
{
Serial.println(“Send ‘0’ pan facing left (180 degrees)”);
Serial.println(“Send ‘1’ pan facing diagonal left (135 degrees)”);
Serial.println(“Send ‘2’ pan facing center (90′ degrees)”);
Serial.println(“Send ‘3’ pan facing diagonal right (45′ degrees)”);
Serial.println(“Send ‘4’ pan facing right (0′ degrees)”);
Serial.println(“Send ‘5’ tilt facing down (-45 degrees)”);
Serial.println(“Send ‘6’ tilt facing center (0 degrees)”);
Serial.println(“Send ‘7’ tilt facing up (45 degrees)”);
}
// you can add more “if” statements with other characters to add more commands
}
}
Arduino code for controlling Motors through Coolterm
The following code snippet was used to demonstrate the functionality of the VHN5019 Motor shield and how to gain a better understanding of DC motor control. For testing purposes, we used the Coolterm application on a laptop or cell phone to demonstrate wireless bluetooth control of the pathfinder’s movements. The code provided will help future projects in the process of initializing bluetooth communication, transmission of data, and later the creation of custom Arxterra commands.
///////////////////////////////////////////////////////////////////////////////
// The following code was written, tested and debugged by Juan Acosta for
// testing the functionality of the VHN5019 Motor Shield and how the six motors
// rotate will dictate which way the rover moves.
// using the HC-06 to implement commands being sent from the COOLTERM application
// from a laptop or phone to the arduino.
// Group: Pathfinder Spring 2016
// Electronics and Control: Juan Acosta (MCU Subsystem and Control Firmware)
///////////////////////////////////////////////////////////////////////////////
#include “DualVNH5019MotorShield.h”
DualVNH5019MotorShield md;
void stopIfFault()
{
if (md.getM1Fault())
{
Serial.println(“M1 fault”);
while(1);
}
if (md.getM2Fault())
{
Serial.println(“M2 fault”);
while(1);
}
}
void setup()
{
Serial.begin(115200);
Serial.println(“Dual VNH5019 Motor Shield”);
md.init();
Serial.begin(9600);
}
char a; // stores incoming command from device into variable a
void loop()
{
if (Serial.available())
// if text arrived in from hardware serial…
{
a=(Serial.read());
if (a==’?’)//////// send commands list
Serial.print(“Send a 1 to move the pathfinder forward”);
Serial.print(“Send a 2 to stop the pathfinder”);
Serial.print(“Send a 3 to rotate the pathfinder by 180 degrees”);
Serial.print(“Send a 4 to make the pathfinder reverse”);
if (a==’1′)/////// move the pathfinder forward by sending a 1
{
int o=0; /////// stop the rover before moving forward
md.setM1Speed(o);
md.setM2Speed(o);
for (int p = 0; p <= 300; p++)
{
md.setM1Speed(p);
md.setM2Speed(p);
Serial.print(“Moving the Pathfinder forward “);
}
}
if (a==’2′)///////////////// stop the wheels by sending a 2
{
int i=0;
md.setM1Speed(i);
md.setM2Speed(i);
Serial.print(“Stop the Pathfinder: “);
}
if (a==’3′)///////////////// rotate 180 degrees
{
Serial.print(“Rotating 180 degrees “);
int c=0;////////////////// stop rover before rotating
md.setM1Speed(c);
md.setM2Speed(c);
for (int m = 0; m <= 300; m++) //////// rotate rover 180 degrees
{
md.setM1Speed(m);
md.setM2Speed(m-300);
delay(2.3);
int k=0;
md.setM1Speed(k);
md.setM2Speed(k);
}
}
if (a==’4′)/////// make the pathfinder reverse by sending a 4
{
Serial.print(“The pathfinder will reverse”);
int l=0; /////// stop the rover before reversing
md.setM1Speed(l);
md.setM2Speed(l);
for (int j = 0; j <= 300; j++)
{
md.setM1Speed(j-600);
md.setM2Speed(j-600);
}
}
}
}
Conclusion:
Applying what we now have learned, we are ready for software implementation through Arxterra including custom commands. Once we had each module working separately, putting them all together to form the pathfinders software system design will require a reasonable amount of testing and debugging since we now have most of it done working without Arxterra. All that is left is the custom command encoding.
Source Materials:
– Coolterm:
http://freeware.the-meiers.org
– Spring 2016 Pathfinder: Subsystem Design
http://arxterra.com/spring-2016-pathfinder-subsystem-design/
– Arxterra Custom Commands