Hello All
I have just started getting into the Arduino. So far I very much enjoy working with the device, more so than the Pi. The Pi is great, dont get me wrong but the Arduino is much better I think for maker projects. Mainly because the Arduino is given one program to run that is for your DIY project. Less mucking around with getting python code to start at boot up etc…
I found the Zumo robot (the arduino shield model) on Core Electronics and thought I have to get that, so I did. I have an IT background and good skills in scripting and application development, so the programming side of things is not such a challenge. Putting together components and making circuits is a challenge for me. I purchased the assembled version of the Zumo robot because I have never soldered before and I did not want to ruin the robot on assembly. I do admit that not putting together the robot myslef kinda rules me out of DIY.
But I have started putting together a PCB board with an ultrasonic sensor for the Zumo.
The program for the Robot without the Ultrasonic Sensor
So I initially started programming the Robot for use in a Sumo ring. The program has the following characteristics
- Line detection to ensure the Robot stays in the ring
- Search mode for locating other robots
I used code from the examples that come with the library’s as a template. My main goal in this development is to not use any delay functions. You will notice that I have used delays but the delays are in the “avoid line” function. The reason why I have done this is to ensure that the robot avoids the line and nothing can interrupt this.
The search mode function does not use delays, which means that if the robot crosses a line whilst searching then the search can be interrupted so the line can be avoided. The reasoning for this is because in a Sumo fight crossing the line will mean your robot looses the battle. So avoiding the line is of the highest importance.
Here is the code for the initial program, I have structured this so I can add the ultrasonic sensor later. So some code is commented out waiting for the sensor.
#include <Wire.h>
#include <ZumoShield.h>
#include <NewPing.h>
// on-board LED
#define LED 13
// this might need to be tuned for different lighting conditions, surfaces, etc.
#define QTR_THRESHOLD 1500 // microseconds
#define NUM_SENSORS 6
// these might need to be tuned for different motor types
#define REVERSE_SPEED -200 // 0 is stopped, 400 is full speed
#define TURN_SPEED 300
#define SCAN_SPEED 150
#define FORWARD_SPEED 400
#define SEARCH_SPEED 125
#define REVERSE_DURATION 300 // ms
#define TURN_DURATION 400 // ms
#define SCAN_DURATION 3000 //ms
#define SEARCH_DURATION 4000 //ms
// pins for the ultrason sensor
#define ECHO_PIN 9 // Arduino pin tied to echo pin on the ultrasonic sensor.
#define TRIGGER_PIN 10 // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define MAX_DISTANCE 500 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
#define LOWDIST 10
// define enums
enum modeStates
{
FORWARD,
REVERSE,
STOP,
AVOIDLINE,
SEARCH
};
enum modeLED
{
ON = HIGH,
OFF = LOW
};
enum lineDirection
{
LEFT,
RIGHT
};
// declare some objects
ZumoReflectanceSensorArray reflectanceSensors(QTR_NO_EMITTER_PIN);
ZumoBuzzer buzzer;
ZumoMotors motors;
Pushbutton button(ZUMO_BUTTON);
//NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
// global variables
int searchTime = SEARCH_DURATION;
int scanTime = SCAN_DURATION;
enum modeStates currentMode;
enum modeStates previousMode;
enum modeLED onBoardLEDState;
enum lineDirection lDirection = LEFT;
unsigned int sensor_values[NUM_SENSORS];
unsigned long currentMillis;
unsigned long searchMillis;
unsigned long scanMillis;
void setup()
{
// set onboard LED to on
toggleLED(ON);
// Play a little welcome song
buzzer.play(">g32>>c32");
// set motors to stop
setMotorSpeed(0);
// Initialize the reflectance sensors module
reflectanceSensors.init();
// wait for button press before starting
//waitForButtonAndCountDown(false);
// initialise the sensor array
//initSensorArray();
// wait for button press before starting
waitForButtonAndCountDown(true);
// set search timer
searchMillis = millis();
// set current mode
currentMode = SEARCH;
}
void loop()
{
// increment the main timer
currentMillis = millis();
// first check if we are over a line, or the outer ring
if (checkForLine())
{
// set mode to avoid the line
currentMode = AVOIDLINE;
}
else
{
// once we get a ultra sonic sensor will check for object
if (objectDetected())
{
currentMode = FORWARD;
}
else
{
currentMode = SEARCH;
}
}
// check what mode we are in
switch (currentMode)
{
case FORWARD:
goForward();
break;
case REVERSE:
goBackwards();
break;
case STOP:
goStop();
break;
case AVOIDLINE:
avoidLine();
break;
case SEARCH:
searchMode();
break;
default:
goStop();
break;
}
}
void goForward()
{
toggleLED(ON);
setMotorSpeed(FORWARD_SPEED);
}
void goBackwards()
{
toggleLED(ON);
setMotorSpeed(REVERSE_SPEED);
}
void goStop()
{
toggleLED(OFF);
setMotorSpeed(0);
}
bool objectDetected()
{
// if(sonar.ping_cm() > LOWDIST || sonar.ping_cm() == 0)
// {
// return false;
// }
//
// if(sonar.ping_cm() <= LOWDIST && sonar.ping_cm())
// {
// return true;
// }
return false;
}
void avoidLine()
{
// stop the motors
setMotorSpeed(0);
// while we can still detect the edge
while (checkForLine())
{
// reverse
setMotorSpeeds(REVERSE_SPEED, REVERSE_SPEED);
}
// if line detected on left
if (lDirection == LEFT)
{
setMotorSpeeds(TURN_SPEED, -TURN_SPEED);
}
// else if line detected on right
else if (lDirection == RIGHT)
{
setMotorSpeeds(-TURN_SPEED, TURN_SPEED);
}
// delay for turn duration
delay(TURN_DURATION);
// set mode to search
currentMode = SEARCH;
}
void searchMode()
{
// check if move forward time has expired
if (currentMillis - searchMillis >= searchTime)
{
// check if the spin time has expired
if (currentMillis - scanMillis <= scanTime)
{
// make the zumo spin
if (lDirection == LEFT)
{
//setMotorSpeeds(SEARCH_SCAN, -SEARCH_SCAN);
setMotorSpeeds(SCAN_SPEED, SCAN_SPEED - (SCAN_SPEED * 0.8));
}
// else if line detected on right
else if (lDirection == RIGHT)
{
//setMotorSpeeds(-SEARCH_SCAN, SEARCH_SCAN);
setMotorSpeeds(SCAN_SPEED - (SCAN_SPEED * 0.8), SCAN_SPEED);
}
}
else
{
// reset search timer
searchMillis = millis();
}
}
else
{
// set search speed forward
setMotorSpeed(SEARCH_SPEED);
// reset the scan timer
scanMillis = millis();
}
}
void setMotorSpeed(int speedint)
{
motors.setSpeeds(speedint, speedint);
}
void setMotorSpeeds(int leftSpeed, int rightSpeed)
{
motors.setSpeeds(leftSpeed, rightSpeed);
}
bool checkForLine()
{
// read the sensors
reflectanceSensors.read(sensor_values);
// detect black, we do this by seeing if the sensor value is greater than threshold
if (sensor_values[0] > QTR_THRESHOLD)
{
lDirection = LEFT;
return true;
}
// detect black, we do this by seeing if the sensor value is greater than threshold
else if (sensor_values[5] > QTR_THRESHOLD)
{
lDirection = RIGHT;
return true;
}
return false;
}
void toggleLED(modeLED ledState)
{
digitalWrite(LED, ledState);
}
void waitForButtonAndCountDown(bool countDown)
{
toggleLED(ON);
button.waitForButton();
toggleLED(OFF);
if (countDown)
{
// play audible countdown
for (int i = 0; i < 3; i++)
{
delay(1000);
buzzer.playNote(NOTE_G(3), 200, 15);
}
delay(1000);
buzzer.playNote(NOTE_G(4), 500, 15);
delay(1000);
}
}
void initSensorArray()
{
// Turn on LED to indicate we are in calibration mode
toggleLED(ON);
// Wait 1 second and then begin automatic sensor calibration
// by rotating in place to sweep the sensors over the line
delay(1000);
int i;
for(i = 0; i < 80; i++)
{
if ((i > 10 && i <= 30) || (i > 50 && i <= 70))
motors.setSpeeds(-200, 200);
else
motors.setSpeeds(200, -200);
reflectanceSensors.calibrate();
// Since our counter runs to 80, the total delay will be
// 80*20 = 1600 ms.
delay(20);
}
motors.setSpeeds(0,0);
// Turn off LED to indicate we are through with calibration
toggleLED(OFF);
buzzer.play(">g32>>c32");
}