Sunday, February 28, 2010

Arduino Robot 3 - Line Follower (Goals & Notes)

Work has begun on my third Arduino Robot. I decided that after some comments I read in various forums, that making a line following robot would probably be a proper increase in challenge. With research in hand, I placed my orders for parts and began looking into creating a test track. Here are the goals for Arduino Robot 3 - Line Following Tank:
  1. Conform to Robo Games Line Following Rules (2010) 
  2. Use only a single sensor.
  3. Robot should move in a smooth motion (no twitching about the line)
I have begun the physical build, but I'm still looking into a 'practice arena'; I may end up taping together printer paper...

Full report, code and video upon completion (so check back here).

Edit: The reason for the single sensor goal is because someone trying to do similar with a Lego robotics set would only have one sensor. I do not want to be putting more money/hardware into any of the robots. They should be a challenge; and with my programming background I think that even two sensors (let alone an array!) would make this too easy. This is because two or more would allow a basic edge following; three or more would allow the robot to distinguish line direction (veering).  The robot may be improved to have multiple sensors; but I feel I can defeat the challenge with one.

Tuesday, February 09, 2010

Arduino Robot 2 - Wandering Tank

My second robot was a bit more complex and ended up taking twice as long to build as originally intended. The budget changed, the designed changed, and my understanding of Robotics in general changed. The second robot is an attempt to make an obstacle avoidance robot that isn't overly simple. I will be outlining the goals, budget, build and code for Wandering Tank.

The goals for Wandering Tank were simple:
  • Should be able to scan an area in front of itself.
  • Should be able to avoid not only walls, but obstacles.
  • Avoid random decision making; the robot should use information when avoiding.
Wandering tank meets these goals, and also looks pretty cool doing it. The code for the robot will show how the third goal is met and the other two will be obvious in the video.

The budget for Wandering Tank was quite cheap. Since I started with Robot 1, the only additional cost for Wandering was the sensor and the servo.
 So Wandering Tank has an estimated cost of $120.00 to build.

Building Wandering Tank was pretty quick. The chassis was modified to hold a servo and the wiring for the motors was improved. Originally the original continuous servo was used, which you will see in the previous post about scanning. Eventually a real servo was purchased and replaced the scanning mechanism. The first thing I did, was improve the motor shield by adding headers for the Arduino ports that it wasn't using. You can see here on the lower right and upper right the additional headers:

 The next step was to modify the chassis to hold a standard size servo. The servo was lined up and used as a tracing template, I then cut out the area to make room. You will also notice in the first picture the improved running of the motor wires, and that the gear box is moved out slightly. This made the treads tighter and the robot moved better! Finally, the battery for the Arduino (9V DC) now fit underneath with room for the servo. In the middle on top is the velcro for the motor battery pack.

 Next the servo was mounted with the Velcro piece in place to hold the sensor. In the picture, the motor shield battery is in place as a test fitting.
 

Finally, everything is assembled and you have Wandering Tank (that does nothing):

With the bot built, it was time to write code to do the actual logic. The code for the scanner from the previous post couldn't be used and I ended up starting over. The code would work life this:
  1. Update Sensor Angle
  2. Scan with Sensor
  3. Move
Each of these steps is much more complicated than it is described. To update the sensor angle requires checking bounds and reversing the direction as necessary. When the sensor is checked, if there is a collision it records the sensor angle during collision (but lets the sensor angle continue to update!), and then records the collision. Movement works by checking for collision and sensor collision angle. If the robot sees something, it moves backwards until vision is clear; it then turns away from the object based on which side of the robot it saw the object. The robot then continues forward, scanning and avoiding as necessary. Here is the source code with comments:

/*
 * George Frick (george.frick@gmail.com)
 * Jan/Feb 2010.
 * Arduino Robot 2 - Wandering Tank
 * This robot will wander around, scanning with a very short range forward IR.
 * When an object is detected, the robot will turn based on the position of the IR sensor
 * during the detection. The robot will move backwards, then turn away from the detected object
 * and continue. The robot runs continuously.
 */
#include <AFMotor.h>
#include <Servo.h>

// Two motors, a servo, and an IR sensor.
AF_DCMotor motor1(1, MOTOR12_64KHZ); // create motor #1, 64KHz pwm
AF_DCMotor motor2(2, MOTOR12_64KHZ); // create motor #2, 64KHz pwm
Servo sensorServo;
const int irPin = 19; // pin 5 as digital is pin 19

// Timing. I don't like using delay.
unsigned long tCnt = 0;
unsigned long tStart = 0;
unsigned long tDelta = 0;
unsigned long tTurn = 0;

int state;               // Current Robot State
int lastState;           // Previous Robot State
int servoPos;            // Position to send servo
int servoDirection;      // Direction servo is turning
int lastDetectionAngle;  // Position of servo at last IR detect.

// Constants for state of tank tracks.
const int STATE_FORWARD = 1;
const int STATE_TURN_RIGHT = 2;
const int STATE_BACKWARD = 3;
const int STATE_TURN_LEFT = 4;

// Constants for Servo.
const int DIR_LEFT = 0;
const int DIR_RIGHT = 1;
const int MIN_DEGREE = 40;
const int MAX_DEGREE = 140;

/*
 * Initializes everything. Is run once.
 */
void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps
  sensorServo.attach(10);  // attaches the servo on pin 10
  pinMode(irPin, INPUT);
  motor1.setSpeed(255);     // set the speed to 200/255
  motor2.setSpeed(255);     // set the speed to 200/255
  tStart = millis();
  lastState = state = STATE_FORWARD;
  servoPos = 90;
  servoDirection = DIR_RIGHT;
  sensorServo.write(servoPos);
  //state = 0; // Uncomment to have robot not move tank tracks.
}

/*
 * Runs continuously.
 * 1. Update Servo.
 * 2. Check IR sensor.
 * 3. Move Robot
 */
void loop() {
  tDelta = millis() - tStart;
  tCnt += tDelta;
  tStart += tDelta;

  // Tell the servo to move 2 degrees every 25 ticks.
  if( tCnt > 25 ) {
    tCnt = 0;
    if( servoDirection == DIR_LEFT ) {
      servoPos -= 2;
    } else if( servoDirection == DIR_RIGHT) {
      servoPos += 2;
    }

    // Servo position will be beyond desired angles, turn around.
    if( servoPos >= MAX_DEGREE ) {
      servoDirection = DIR_LEFT;
    } else if( servoPos <= MIN_DEGREE ) {
      servoDirection = DIR_RIGHT;
    }
    sensorServo.write(servoPos);
  }

  // Allows disabling of tracks by setting state to 0.
  if(state == 0) {
    moveRobot();
    return;
  }

  // Double read the pin, @see forums.adafruit.com
  digitalRead(irPin);
  delay(5);
  if( digitalRead(irPin) == 0 ) {
    lastDetectionAngle = servoPos;
    state = STATE_BACKWARD;
  } else {
    if( state == STATE_BACKWARD ) {
      if( lastDetectionAngle > 105 ) { // right
        state = STATE_TURN_LEFT;
        tTurn = 1000; // turn for ~1 seconds
      } else if( lastDetectionAngle < 75 ) { // left
        state = STATE_TURN_RIGHT;
        tTurn = 1000; // turn for ~1 seconds
      } else { // center
        state = STATE_TURN_RIGHT; // for now, turn right by default.
        tTurn = 1500; // turn for ~1 seconds
      }
    } else if ( state == STATE_TURN_RIGHT || state == STATE_TURN_LEFT ) {
      tTurn -= tDelta;
      if( tTurn <= 10 ) {
        state = STATE_FORWARD;
      }
    } else {
      state = STATE_FORWARD;
    }
  }

  moveRobot();
}

/*
 * Uses the state of the robot to move tank treads accordingly
 */
void moveRobot() {

  // The motors seemed to respond better if they receive a stop before a switch in direction.
  if( state != lastState ) {
    motor1.run(RELEASE);      // stopped
    motor2.run(RELEASE);      // stopped
  }

  switch( state ) {
    default:
      return; // helps test, state 0 = dont move.
    case STATE_FORWARD: {
      motor1.run(FORWARD);      // turn it on going forward
      motor2.run(FORWARD);      // turn it on going forward
      break;
    }
    case STATE_BACKWARD: {
      motor1.run(BACKWARD);      // turn it on going forward
      motor2.run(BACKWARD);      // turn it on going forward
      break;
    }
    case STATE_TURN_RIGHT: {
      motor1.run(FORWARD);      // turn it on going forward
      motor2.run(BACKWARD);      // turn it on going forward
      break;
    }
    case STATE_TURN_LEFT: {
      motor1.run(BACKWARD);      // turn it on going forward
      motor2.run(FORWARD);      // turn it on going forward
      break;
    }
  }

  lastState = state;
}

/* EOF */

And finally, here is Wandering Tank in action:

Tuesday, February 02, 2010

Arduino Robot 2 - Part 1 - Forward Scanner

Work has been coming along well on the development of the second version of Arduino Robot. There have been multiple set backs; the biggest of which is my purchase of a continuous rotation servo instead of a normal one. Otherwise the bot is constructed and mostly works in tests.

The goals for Robot 2 were a step up from Robot 1:
  • Ability to continually scan in front of itself.
  • Ability to back and turn to avoid obstacles.
  • Smoother movement.
Basically Robot 2 is a wandering avoidance robot; called Arduino Robot 2 - Wandering Tank. For this to work, I needed some type of affordable sensor to place at the front of the robot; and from there the ability to look around with it. My solution was to mount a sensor on a servo. The servo would be used to sweep across a selected field of vision looking for possible collisions. So Wandering Tank has to do the following:
  • Move Forward
  • Scan left to right
  • Move backwards while object detected
  • Turn after object no longer detected 
  • Repeat 
Because only a continuous rotation servo was available without spending more money; the design was changed so that instead of targeting a degree; the servo would have some way to trigger moving back and forth. The eventual solution was to mount a light sensor just behind the servo. A disk was then cut with a slot cut out defining the open degrees of movement. The scanner would scan back and forth, reversing direction each time the light sensor met darkness. It didn't work out this simple, and I'm still perfecting the code. It does perfectly scan back and forth in normal light conditions however.

To fix the problem, a led will be added with the purpose of providing a continually known light source. The problem being that when moved from the work bench to any other area, the relative light/dark changes and the servo starts to just spin and rip wires asunder.

Until part 2, where the complete Wandering Tank project will be shared, here is the scanning servo. Any ideas on doing this better are welcome!

Create a "GG Button" With an IOT Button on Discord

I was having some fun with my internet button (found here: https://store.particle.io/collections/shields-and-kits), and also working on some...