Zumo Robot Ultrasonic Sensor

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

  1. Line detection to ensure the Robot stays in the ring
  2. 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");
}

Robert, awesome work! Have you already ordered the ultrasonic sensor? We’d love to get an update when you can test the 'bot’s behavior with the sensor.
Do you have a sumo comp to enter it into? Wondering if there will be a video at some stage … :wink:

  • Chris

Hello Chris

Yes I have got the sensor, its the HR-SR04. I have soldered this sensor and some LED’s to a PCB board. I just need to attach it to the Robot and also work out which pins on the Zumo Shield I can use or will use for the sensor and LED’s.

I am not aware of any competitions but yes I do want to enter some once the Robot is finished.

Video is a great idea. And I should also take some pics of my PCB board once it is mounted,

Thanks Chris
Cheers
Robert

1 Like

So I have made my PCB board for my Zumo Robot. I placed the HR-SR04 sensor on the board and two LED’s. The LED’s are to give status feedback such as green light when nothing detected and red light when something is. The mistake I made was to have a seperate ground pin for each component. I will fix this in the next version so that all components share one ground.
20180510_181721

3 Likes

The next stage is to solder a female header pin on the side of the Zumo shield so that I can get access to the analogue pins. I have chosen the analogue pins because I can re-allocate more analogue pins from the relective sensor than I can digital. Or at least thats how I see it after readin the Zumo users guide.

I will be using the reflective sensor but only the two outside sensors, which use digital pins 4 and 5 from memory. These sensors will detect the border of the ring.

3 Likes

Thanks for the update Robert, keep them coming!

How would you change this code if you were not using the IR sensor? So you are not scanning and are just using the ultrasonic sensor to avoid objects? Which parts of the code could you leave out?