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!

Wednesday, January 20, 2010

Arduino Robot 1 - The Basic Tank

What you see below is the result of my first attempt at building a robot. The goal was to build something Arduino based. It would move forward, turn around, come back; and then turn around again to be in its original position. Finally, I wanted to try multiple part selling web sites, to get experience with who to buy from. Fortunately; they were all better than expected experiences. My Arduino was a Christmas present; but I will be factoring 32.00 into the cost of the project to account for it.

The first phase was an order from SuperDroidRobots.com. Tank treads, a double motored gear box, and some plastic to build a chassis came in at $40.00. The second order was from Adafruit.com, for a continuous rotation servo and an Arduino Motor Shield. The Adafruit order also came in at $40.00. Subtracting the cost of the unused Servo, this robot is built for just under $100.00. You can see the initial parts order below.


I started by building the motor shield, this is the motor shield kit when taken out of the anti-static bag.


This is the completed Arduino Motor Shield after soldering everything into the board. The pins coming out of the bottom are the interface to the Arduino. You will notice two jumpers near the bottom middle of the picture. This is the motor power jumper, and is used in conjunction with the external power supply input; which is the block of two screw terminals just to the left of the jumper. You can see it says "EXT_PWR".


I moved on to building the "tank", this would be the chassis to hold the gearbox and Arduino + Motor Shield. I would later realize it had to hold two battery packs; one for the Arduino and one to power the motors via EXT_PWR. Getting the little plastic treads together wasn't fun, but everything came together.


 I had to solder two lines to the motors for them to work, then wire everything up. The wiring is supplying 6V from a battery pack to the motors, and there is the standard Arduino 9V battery pack powering it. Both packs are held to the chassis by velcro. You can see the Motor Shield stacked on the Arduino. Here is the final bot with source.


#include <AFMotor.h>

AF_DCMotor motor1(1, MOTOR12_64KHZ); // create motor #2, 64KHz pwm
AF_DCMotor motor2(2, MOTOR12_64KHZ); // create motor #2, 64KHz pwm

unsigned long tCnt = 0;
unsigned long tStart = 0;
unsigned long tDelta = 0;

void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps  
  motor1.setSpeed(255);     // set the speed to 200/255
  motor2.setSpeed(255);     // set the speed to 200/255
  tStart = millis();
}

void loop() {
   tDelta = millis() - tStart;
   tCnt += tDelta;
   tStart += tDelta;
   // run motors for 5 seconds.
   if( tCnt <= 5000) {
   motor1.run(FORWARD);      // turn it on going forward
   motor2.run(BACKWARD);      // turn it on going forward
      return;
   } else if ( tCnt <= 6300 ) {
   motor1.run(BACKWARD);      // turn it on going forward
   motor2.run(BACKWARD);      // turn it on going forward
      return;
   } else if ( tCnt <= 11300 ) {
   motor1.run(FORWARD);      // turn it on going forward
   motor2.run(BACKWARD);      // turn it on going forward
      return;
   } else if ( tCnt <= 12600 ) {
   motor1.run(FORWARD);      // turn it on going forward
   motor2.run(FORWARD);      // turn it on going forward
      return;
   } 
      motor1.run(RELEASE);      // stopped
      motor2.run(RELEASE);      // stopped
}

Finally, it all gets put into motion. I made some mistakes that others should watch out for. The motors that come with the Tamiya gearbox don't work well with the Motor Shield. Their stall rating is too high. If not for this, the code above would simply use a 'delay'; but with the Tamiya motors; the delay keeps the motors from ever getting past stall. Also, the battery pack isn't needed. In this simple case the 9V + setting the jumper would power the two motors just fine. It was fun! I have ordered my first sensor; so I'll be starting Robot 2 - Wandering Tank. Here is Robot 1 in action:

Sunday, January 17, 2010

Fixing a dead Sansa MP3 player (Versions e200 e260 e280)

First, here is the player we are discussing, or at least your average version:


Although if you are here, you probably don't see the nice shiny interface above. That's a shame, but we'll try to fix it. This all started for me when a friend got a bag of crap from Woot! Among the loot, were quite a few dead Sansa e2XX players. You have to use the e200 tool to reflash them, it works better under Linux, and I run Linux (Ubuntu if you must know). So I ended up in a deal where I would try to fix all three. They were all fixed, and below I share how I eventually got all three working.

There are many posts on the web about how to fix these. They involve going into factory mode and flashing the firmware. Unfortunately a measurable percentage of people find that to be completely useless because if you can't get the device into factory mode then you can't update the firmware.

Let's troubleshoot a Sansa MP3 e2XX player. Keep following these steps, if you make it to the end, your player is beyond my help.

  1. Is it simply locked up? Hold the power button 30 seconds. The player should reboot.
  2. That didn't work, your player turns on, but isn't responsive. Remove the cover and take out the battery for 30 minutes.
  3. You removed the battery, and it didn't help. Now we'll try to get into factory/recovery mode. There are a couple ways of doing this depending on your version. They all start by turning the hold button on so you see orange. You then either hold the middle button, or the record button (and keep holding) while turning the player on. If you can get into factory mode, cool; go here: Fixing a Sansa in Recovery Mode 
  4. You can't get into recovery mode, the player turns on; but all you get is a blue ring. This is the ridiculous problem happening to a lot of people. They end up throwing away the player if it is too late to return it. The short answer is; your memory probably came loose. Here is an illustration of the problem: 


It makes me upset with Sansa that the memory for their MP3 players is attached with no locking mechanism at all. Here is what this should look like:


Fixing this is simple, and NO; you don't have to take the player apart as in the above pictures. I took a player apart, and had the memory fall on the floor; and here we are! Simply remove the battery cover (4 screws), remove the battery; and then find the big black square of plastic:

 You are going to need to remove that, it is easiest to push in the middle; forcing an edge to pop up, and then removing it. It's just lightly glued in place. You should then see your memory:

 Give the memory a firm push; if you hear a 'click', you probably just fixed your player. I know, this whole blog for that?!?! I spent hours reading forum after forum telling me to just 'be persistent trying to put it into recovery mode'. No; your memory may have come loose. I fixed two different players this way, and one other by flashing it. If this didn't help; you may be out of luck. Keep googling!

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...