Friday, June 29, 2012

A redesign of the lego car for Arduino


Very exciting... I tried uploading all of the code over the weekend and the car works much better.
I also did a redesign of the variable speed and it is so much better.  I still need to add smoothing to the ping sensors.  I think it will help more.  These things will hopefully happen on Tuesday this week.
----------------------------------------

On Wednesday, I finished the lego car and uploaded the code, which is posted below.  It was moderatly okay, after I fixed many issues with speed and power.  But it was not good enough so I had to ponder the power issues I was having.  The main problem was that variable speed equation ran the power from 0 to 255 as from the arduino outputs.  This however also meant that the voltage to the motor was from 0 to 12 volts.  And so, it did not work so well.

After pondering the issue for a while, I realized that I needed to set my equation so that the voltage would be between about 10 and 12 volts.  That might translate into 200 to 255 on the arduino.  I have not done this yet but will put it into the next round.

The other issue was that I was spinning my gear ratio from the motor to the wheels was a 1:1.  This is not how electric motors are meant to work.  They need high spinning speeds to low spinning wheels.   So I also put this mechanical change into the next model.

The final issue was that when having a rear wheel turning, the back end actually pushes out to one side or the other which, when close to a side wall, was enough to steer the back end into the wall.  You will see this in the video.


This is a video of the first Lego Car.  It drives with only the input from two Ping Sensors pointing right and left and one IR Sensor pointing front.

This is the new design of the Lego Car.  It has the same sensors but is now front wheel drive.  The front wheels can still turn 360 degrees as in the previous model.

-------------------------
This code is updated and better then previous versions.
Note::  You need to have the NewPing.h library which is avail from the Arduino Libraries.


// for the IR Sensor
int IRpin = 0;                                    // analog pin for reading the IR sensor
float volts = 0;   // value from sensor * (5/1024) - if running 3.3.volts then change 5 to 3.3
float forward_distance = 0;          // worked out from graph 65 = theretical distance / (1/Volts)S - luckylarry.co.uk

// for both ping sensors
  #include <NewPing.h>

  #define trig_right  8  // Arduino pin tied to trigger pin on ping sensor.
  #define echo_right  9  // Arduino pin tied to echo pin on ping sensor.
  #define max_distance_right 200 // Maximum distanceance we want to ping for (in centimeters). Maximum sensor distanceance is rated at 400-500cm.
  NewPing sonar_right(trig_right, echo_right, max_distance_right); // NewPing setup of pins and maximum distanceance.
  unsigned int pingSpeed_right = 50;  // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
  unsigned long pingTimer_right = 75; // Holds the next ping time, start at 75ms to give time for the Arduino pins to stabilize.
  int cm_right = 50;

  #define trig_left  12  // Arduino pin tied to trigger pin on ping sensor.
  #define echo_left  13  // Arduino pin tied to echo pin on ping sensor.
  #define max_distance_left 200 // Maximum distanceance we want to ping for (in centimeters). Maximum sensor distanceance is rated at 400-500cm.
  NewPing sonar_left(trig_left, echo_left, max_distance_left); // NewPing setup of pins and maximum distanceance.
  unsigned int pingSpeed_left = 50;  // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
  unsigned long pingTimer_left = 75; // Holds the next ping time, start at 75ms to give time for the Arduino pins to stabilize.
  int cm_left = 50;
  
// for the stearing servo
  #include <Servo.h>
  Servo myservo;
  int center = 75;                //the center position for the servo is 90 degrees

// for the dirve 
  int motor = 11;                 //When doing analog, you must use int and not define.
  int motor_speed = 0;
  
void IR_1(){
  volts = analogRead(IRpin)*0.0048828125;   // value from sensor * (5/1024) - if running 3.3.volts then change 5 to 3.3
  forward_distance = 65*pow(volts, -1.10);          // worked out from graph 65 = theretical distance / (1/Volts)S - luckylarry.co.uk
  if(forward_distance <= 30)                           //this is the domain of the sensor, 30 to 140 cm.
    forward_distance = 30;
  if(forward_distance >= 140)
    forward_distance = 140;
  motor_speed = 155*forward_distance/110-30*155/110+150;    //this is the equation for variable motor speed.
  if(forward_distance == 30){                              //  this 155 corrisponds to 30 cm.  I want the motor turned off!
    motor_speed = 0;
  }
//  motor_speed = (255/110)*(forward_distance-30);       //this is used for when there is an LED Test Light in Place
  Serial.print(forward_distance);                       // print the distance
  Serial.print("cm Forward Distance     ");
  Serial.print(motor_speed);
  Serial.println("mph domain is 155 to 255");
}

void Ping_Right(){
  // Notice how there's no delays in this sketch to allow you to do other processing in-line while doing distanceance pings.
  if (millis() >= pingTimer_right) {       // pingSpeed_1 milliseconds since last ping, do another ping.
    pingTimer_right += pingSpeed_right;    // Set the next ping time.
    cm_right = sonar_right.ping_cm();      // Send out the ping, get the results in centimeters.
  if(cm_right <= 15)                       //this is the domain of the sensor.  15 to 60 cm.
    cm_right = 15;
  if(cm_right >= 60)
    cm_right = 60;
    Serial.print(cm_right);          // Print the result (0 = outside the set distanceance range, no ping echo)
    Serial.println(" cm Ping Sensor RIGHT");
    delay(10);
  }
}

void Ping_Left(){
  // Notice how there's no delays in this sketch to allow you to do other processing in-line while doing distanceance pings.
  if (millis() >= pingTimer_left) {       // pingSpeed_1 milliseconds since last ping, do another ping.
    pingTimer_left += pingSpeed_left;     // Set the next ping time.
    cm_left = sonar_left.ping_cm();       // Send out the ping, get the results in centimeters.
  if(cm_left <= 15)                       //this is the domain of the sensor.  15 to 60 cm.
    cm_left = 15;
  if(cm_left >= 60)
    cm_left = 60;
    Serial.print(cm_left);          // Print the result (0 = outside the set distanceance range, no ping echo)
    Serial.println(" cm Ping Sensor LEFT");
  }
}

void setup() {
  Serial.begin(9600);                             // start the serial port
  myservo.attach(7);
  myservo.write(center);

}

void loop() {
  IR_1();
  while (forward_distance >= 70 && forward_distance <= 140){           //Variable speed, No Turns
    analogWrite(motor, motor_speed);
    myservo.write(center);
    IR_1();
    Serial.println("---#1  Variable speed, No Turns");
  }
  while (forward_distance >= 50 && forward_distance < 70){              //Variable speed, Little Turns
    analogWrite(motor, motor_speed);
    Ping_Right();
    Ping_Left();
    if (cm_right > cm_left){
      myservo.write(center - 25);
    Serial.println("---#3 Turn a Little Left");
    }
    else {
      myservo.write(center + 25);
    Serial.println("---#4 Turn a Little Right");
    }
    IR_1();
  }  
  while (forward_distance >= 30 && forward_distance < 50){              //Variable speed, big Turns
    analogWrite(motor, motor_speed);
    Ping_Right();
    Ping_Left();
    if (cm_right > cm_left){
      myservo.write(center - 45);
    Serial.println("---#6 Turn a lot Left");
    }
    else {
      myservo.write(center + 45);
    Serial.println("---#7 Turn a lot Right");
    }
    IR_1();
  }  
}

Monday, June 25, 2012

Two ping and 1 IR sensor

This is a rough working bit of code for two ping sensors I intend on pointing to the sides of the car while the IR sensor points forward.

I have set up each sensor as a seperate function so I can only call the part of the code that I need.  It runs pretty fast but is a little jumpy.  I want to still figure out a way to get a more variable turn on the servo.  I think that will be by smoothing those sensors and then getting an avg. difference.  Somehow using that number to add or subtract the degree of the turn from center position

The speed of the motor is based on the distance from an object.  Still need to work out the situation where it will go very slow and just how slow the actual motor can spin while attached to a lego car. Not sure about that either at the moment.

The sharp IR sensor and Arduino Board


The code is below.  Such fun pondering this stuff.
---------------------------------------



// for the IR Sensor
int IRpin = 0;                                    // analog pin for reading the IR sensor
float volts = 0;   // value from sensor * (5/1024) - if running 3.3.volts then change 5 to 3.3
float forward_distance = 0;          // worked out from graph 65 = theretical distance / (1/Volts)S - luckylarry.co.uk

// for both ping sensors
  #include <NewPing.h>
  int p_d = 0;               //the value for the difference between ping sensors

  #define trig_right  2  // Arduino pin tied to trigger pin on ping sensor.
  #define echo_right  3  // Arduino pin tied to echo pin on ping sensor.
  #define max_distance_right 200 // Maximum distanceance we want to ping for (in centimeters). Maximum sensor distanceance is rated at 400-500cm.
  NewPing sonar_right(trig_right, echo_right, max_distance_right); // NewPing setup of pins and maximum distanceance.
  unsigned int pingSpeed_right = 50;  // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
  unsigned long pingTimer_right = 75; // Holds the next ping time, start at 75ms to give time for the Arduino pins to stabilize.
  int cm_right = 50;

  #define trig_left  12  // Arduino pin tied to trigger pin on ping sensor.
  #define echo_left  13  // Arduino pin tied to echo pin on ping sensor.
  #define max_distance_left 200 // Maximum distanceance we want to ping for (in centimeters). Maximum sensor distanceance is rated at 400-500cm.
  NewPing sonar_left(trig_left, echo_left, max_distance_left); // NewPing setup of pins and maximum distanceance.
  unsigned int pingSpeed_left = 50;  // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
  unsigned long pingTimer_left = 75; // Holds the next ping time, start at 75ms to give time for the Arduino pins to stabilize.
  int cm_left = 50;

// for the stearing servo
  #include <Servo.h>
  Servo myservo;
  int center = 90;                //the center position for the servo is 90 degrees

// for the dirve
  int motor = 11;                 //When doing analog, you must use int and not define.
  int motor_speed = 0;

void IR_1(){
  volts = analogRead(IRpin)*0.0048828125;   // value from sensor * (5/1024) - if running 3.3.volts then change 5 to 3.3
  forward_distance = 65*pow(volts, -1.10);          // worked out from graph 65 = theretical distance / (1/Volts)S - luckylarry.co.uk
  if(forward_distance <= 30)                           //this is the domain of the sensor, 30 to 140 cm.
    forward_distance = 30;
  if(forward_distance >= 140)
    forward_distance = 140;
  motor_speed = (205/110)*(forward_distance-30)+50;    //this is the equation for variable motor speed.
//  motor_speed = (255/110)*(forward_distance-30);       //this is used for when there is an LED Test Light in Place
  Serial.print(forward_distance);                       // print the distance
  Serial.println(" cm Forward Distance");
}

void Ping_Right(){
  // Notice how there's no delays in this sketch to allow you to do other processing in-line while doing distanceance pings.
  if (millis() >= pingTimer_right) {       // pingSpeed_1 milliseconds since last ping, do another ping.
    pingTimer_right += pingSpeed_right;    // Set the next ping time.
    cm_right = sonar_right.ping_cm();      // Send out the ping, get the results in centimeters.
  if(cm_right <= 15)                       //this is the domain of the sensor.  15 to 60 cm.
    cm_right = 15;
  if(cm_right >= 60)
    cm_right = 60;
    Serial.print(cm_right);          // Print the result (0 = outside the set distanceance range, no ping echo)
    Serial.println(" cm Ping Sensor RIGHT");
    delay(10);
  }
}

void Ping_Left(){
  // Notice how there's no delays in this sketch to allow you to do other processing in-line while doing distanceance pings.
  if (millis() >= pingTimer_left) {       // pingSpeed_1 milliseconds since last ping, do another ping.
    pingTimer_left += pingSpeed_left;     // Set the next ping time.
    cm_left = sonar_left.ping_cm();       // Send out the ping, get the results in centimeters.
  if(cm_left <= 15)                       //this is the domain of the sensor.  15 to 60 cm.
    cm_left = 15;
  if(cm_left >= 60)
    cm_left = 60;
    Serial.print(cm_left);          // Print the result (0 = outside the set distanceance range, no ping echo)
    Serial.println(" cm Ping Sensor LEFT");
  }
}

void ping_difference(){
  p_d = cm_left - cm_right;
  Serial.print(p_d);
  Serial.println(" Ping Difference");
}

void setup() {
  Serial.begin(9600);                             // start the serial port
  myservo.attach(7);
  myservo.write(50);

}

void loop() {
  IR_1();
  while (forward_distance == 140){                                    //Full Speed, Lots of Room
    analogWrite(motor, 255);
    myservo.write(center);
    IR_1();
    Serial.println("---#1  Full Speed, No Turns");
  }
  while (forward_distance >= 50 && forward_distance < 140){           //Variable speed, No Turns
    analogWrite(motor, motor_speed);
    myservo.write(center);
    IR_1();
    Serial.println("---#2  Variable speed, No Turns");
  }
  while (forward_distance >= 40 && forward_distance < 50){              //Variable speed, Little Turns
    analogWrite(motor, motor_speed);
    Ping_Right();
    Ping_Left();
    ping_difference();
    if (p_d > 0){
      myservo.write(center - 35);
    Serial.println("---#3 Turn a Little Left");
    }
    else {
      myservo.write(center + 35);
    Serial.println("---#4 Turn a Little Right");
    }
    delay (700);
    IR_1();
  }
  while (forward_distance >= 30 && forward_distance < 40){              //Variable speed, Little Turns
    analogWrite(motor, motor_speed);
    Ping_Right();
    Ping_Left();
    ping_difference();
    if (p_d > 0){
      myservo.write(center - 65);
    Serial.println("---#6 Turn a lot Left");
    }
    else {
      myservo.write(center + 65);
    Serial.println("---#7 Turn a lot Right");
    }
    delay(700);
    IR_1();
  }
}

Friday, June 22, 2012

1st Lego Prototype for Arduino Robot

I finished making the first model for my Arduino robot.  It's features are a rear wheel drive, with differential, and 360 degree turning.  I will try to mount the electronics on Monday.



Much Better Ping Code

Wednesday was an exciting day for us.  Because of the simple question, "If we are struggling with this, don't you think that someone else has already figured this out??"  So we looked into the Ping Sensor Bad Data issue and found that on the Arduino.cc site, there was a new library and sketch for the ping sensor we were using.  This new code got rid of the delay that occurs when there was an error reading, and returns a 0 instead of a delay.  So we just wrote out the 0 by using an "if" statement and life is better.

The code is below.  I still need to tweak a bit and am thinking that I may want to use three sensors.  There is still the issue that the ping sensor can't detect very well at angles greater then 45 degrees.
I will also try the Infrared Distance Sensors as a remedy to this problem.

Code
---------------------------------

//Two Ping Sensors with one Motor and one Servo

//This code is for controling a single motor and a servo with a pair of ping sensors (4-pin, HC-SR04).
//Orginally used for a Lego Technics car that self drives around a room
//by Philip Leete

//Define information about ping sensors
#include <NewPing.h>

#define TRIGGER_PIN_R  2  // Arduino pin tied to trigger pin on ping sensor.
#define ECHO_PIN_R     3  // Arduino pin tied to echo pin on ping sensor.
#define TRIGGER_PIN_L  8  // Arduino pin tied to trigger pin on ping sensor.
#define ECHO_PIN_L     9  // Arduino pin tied to echo pin on ping sensor.
#define MAX_DISTANCE 300 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
int distance_R = 0;
int distance_L = 0;

NewPing sonar_R(TRIGGER_PIN_R, ECHO_PIN_R, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
NewPing sonar_L(TRIGGER_PIN_L, ECHO_PIN_L, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

unsigned int pingSpeed_R = 50;  // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
unsigned long pingTimer_R = 75; // Holds the next ping time, start at 75ms to give time for the Arduino pins to stabilize.
unsigned int pingSpeed_L = 50;  // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
unsigned long pingTimer_L = 75; // Holds the next ping time, start at 75ms to give time for the Arduino pins to stabilize.

//This sections is required for the smoothing
const int numReadings = 2;
int readings_R[numReadings];
int readings_L[numReadings];                               // the readings from the analog input
int index_R = 0,             index_L = 0;                  // the index of the current reading
int total_R = 0,             total_L = 0;                  // the running total
int average_R = 0,           average_L = 0;                // the average of the light values
int difference = 0;
int counter = 0;                                           // this counter will be used to start/stop sensors

//Define information about motors
#define fwd_motor 6                    //fwd motor connected to digital pin 6
#define rev_motor 11                   //rev motor connected to digital pin 11
int rev_motor_speed = 0;               //a integer to be used to determine if the motor is on or off backwards

//Define information about steering servo
int center = 90;                       //the center position for driving straight with the servo
#include <Servo.h>
Servo stearing;

void setup() {
  Serial.begin (9600);                 //Turn on Serial Monitor
  //Define what will be inputs and what will be outputs
  pinMode(fwd_motor, OUTPUT);
  pinMode(rev_motor, OUTPUT);
  stearing.attach(5);                  //Where the steering servo will be put
  //These for statements are to initalize all of the smoothing settings to zero
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings_R[thisReading] = 0;                        
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings_L[thisReading] = 0;
}

//create a function called smooth_sensors so it can be called later in the void loop
void smooth_sensors(){
  while (counter < numReadings){
    counter = (counter + counter++);
  // Notice how there's no delays in this sketch to allow you to do other processing in-line while doing distance pings.
  if (millis() >= pingTimer_R) { // pingSpeed milliseconds since last ping, do another ping.
    pingTimer_R += pingSpeed_R;    // Set the next ping time.
    distance_R = sonar_R.ping_cm();  // Send out the ping, get the results in centimeters.
  // Notice how there's no delays in this sketch to allow you to do other processing in-line while doing distance pings.
  }
  if (millis() >= pingTimer_L) { // pingSpeed milliseconds since last ping, do another ping.
    pingTimer_L += pingSpeed_L;    // Set the next ping time.
    distance_L = sonar_L.ping_cm();  // Send out the ping, get the results in centimeters.
  }

//This section is for smoothing
  total_R= total_R - readings_R[index_R];           // subtract the last reading:  
  total_L= total_L - readings_L[index_L];      
  readings_R[index_R] = distance_R;                 // read from the sensor:
  readings_L[index_L] = distance_L;
  total_R= total_R + readings_R[index_R];           // add the reading to the total:
  total_L= total_L + readings_L[index_L];
  index_R = index_R + 1, index_L = index_R + 1;     // advance to the next position in the array:
  if (index_R >= numReadings)                       // if we're at the end of the array...
    index_R = 0;                                    // ...wrap around to the beginning
  if (index_L >= numReadings)                  
    index_L = 0;                                
  average_R = total_R / numReadings;                // calculate the average rt. distance
  average_L = total_L / numReadings;                // calculate the average lft. distance
  difference = average_R - average_L;               // calculate the difference beween sensors

//this sections prints out info to the serial monitor
    Serial.print(distance_L);          // Print the result (0 = outside the set distance range, no ping echo)
    Serial.println("cm Left");
    Serial.print(distance_R);          // Print the result (0 = outside the set distance range, no ping echo)
    Serial.println("cm Right");
  }
    Serial.print(average_L);
    Serial.println("  Left Sensor Avgerage");  
    Serial.print(average_R);
    Serial.println("  Right Sensor Avgerage");  
   delay (5000);
  counter = 0;
}

void loop() {
  smooth_sensors();

//Case #1 - No Time to Turn so Back Up
  if (average_R <= 3 && average_L <= 3){  
      analogWrite (fwd_motor, 0);
      rev_motor_speed = 0;
      stearing.write(center);
      Serial.println("STOP and Center stering c1");
      delay (3000);
    while(average_R <= 8 || average_L <= 8){
      analogWrite (rev_motor, 50);
      Serial.println("reverse slowly - Straight c1");
      rev_motor_speed = 50;
      smooth_sensors();
      delay(500);
    }
  }
//Case #2 - Need to Turn with in Turning Range and drive slow
  if (average_R <= 8 || average_L <= 8){
      if (rev_motor_speed > 0){
        analogWrite(rev_motor, 0);
        rev_motor_speed = 0;
        Serial.println("STOP, Turn off rev. motor c2");
        delay(2000);                      //if the Rev Motor is on, turn it OFF and wait 1 sec.
      }    
      if (difference < 0){            //indicates right sensor is closer so turn left
        stearing.write(center - 30);      //turn left
        analogWrite(fwd_motor, 50);        //drive fwd slowly
        Serial.println("   Turning Left and Drive Fwd Slow c2");
        delay(500);
      }
      if (difference > 0){      
        stearing.write(center + 30);      //turn right
        analogWrite(fwd_motor, 50);        //drive fwd slowly
        Serial.println("  Turn Right and driving fwd slowly c2");
        delay(500);
      }
      else {
        stearing.write(center);
        analogWrite(fwd_motor, 50);        //drive fwd slowly
        Serial.println("  Drive fwd slowly c2");
        delay(500);
      }
  }

//Case #3 - No obstacles so drive fwd at full speed.
  if (average_R > 8 && average_L > 8){
    if (rev_motor_speed > 0){
      analogWrite(rev_motor, 0);
      rev_motor_speed = 0;
      stearing.write(center);
      Serial.println("STOP, turn off Rev. Motor and center stearing c3");
      delay(2000);      //if the Rev Motor is on, turn it OFF and wait 1 sec.
    }
    while (average_R > 8 && average_L > 8){
        analogWrite(fwd_motor, 255);
        stearing.write(center);
        smooth_sensors();
        Serial.println("Drive Forward Full Speed c3");
        delay(500);
      }
  }
}

Monday, June 18, 2012

Buggy Code for Two Ping Sensors, One Motor and One Servo

Today was a successful day.  About as much as it could be.  Using the
Ultrasonic Module HC-SR04 Distance Sensor For Arduino, I was able to use the smoothing example in the Arduino Interface software, and something that I am calling threading to get the motor to turn on variable speeds based on distance, including reverse, and the servo to turn right or left depending on the difference of the two sensors.  The issue is that the sensors are still buggy.  With the smoothing, I am now getting better numbers because the errors are averaged out.  However, when an error happens on the sensor, it takes a second pause which given my written delay, it is taking as long as 4 seconds to get a measurement sometimes.  This causes the entire thing to slow down and become not reliable for a moving car that is trying to make decisions about going right or left or speeding up or slowing down.  I am hoping to have better luck with some IR Sensors.  I am hoping that it will give me more predictable results along with a faster response time.   The code for what I did is below.  It does work as is.  But is has issues.


--------------------------------------------

//Two Ping Sensors with one Motor and one Servo

//This code is for controling a single motor and a servo with a pair of ping sensors (4-pin, HC-SR04).
//Orginally used for a Lego Technics car that self drives around a room
//by Philip Leete

//Define information about ping sensors
int trigPin_R = 2, trigPin_L = 8;
int echoPin_R = 3, echoPin_L = 9;
int duration_R,    duration_L;
int distance_R,    distance_L;
int difference = 0;                                  //uses avg. distances to calculate

//This sections is required for the smoothing
const int numReadings = 10;
int readings_R[numReadings];
int readings_L[numReadings];                               // the readings from the analog input
int index_R = 0,             index_L = 0;                  // the index of the current reading
int total_R = 0,             total_L = 0;                  // the running total
int average_R = 0,           average_L = 0;                // the average of the light values
int counter = 0;                                           // this counter will be used to start/stop sensors

//Define information about motors
#define fwd_motor 6                    //fwd motor connected to digital pin 6
#define rev_motor 11                   //rev motor connected to digital pin 11
int rev_motor_speed = 0;               //a integer to be used to determine if the motor is on or off backwards

//Define information about steering servo
int center = 90;                       //the center position for driving straight with the servo
#include <Servo.h>
Servo stearing;

void setup() {
  Serial.begin (9600);                 //Turn on Serial Monitor
  //Define what will be inputs and what will be outputs
  pinMode(trigPin_R, OUTPUT);
  pinMode(echoPin_R, INPUT);
  pinMode(trigPin_L, OUTPUT);
  pinMode(echoPin_L, INPUT);
  pinMode(fwd_motor, OUTPUT);
  pinMode(rev_motor, OUTPUT);
  stearing.attach(5);                  //Where the steering servo will be put
  //These for statements are to initalize all of the smoothing settings to zero
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings_R[thisReading] = 0;                          
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings_L[thisReading] = 0;
}

//create a function called smooth_sensors so it can be called later in the void loop
void smooth_sensors(){
  while (counter < numReadings){
    counter = (counter + counter++);
//Activate the Left Ping Sensor
    digitalWrite(trigPin_L, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin_L, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin_L, LOW);
  duration_L = pulseIn(echoPin_L, HIGH);
  distance_L = (duration_L)/140;                  //conversion to inches
//Activate the Right Ping Sensor
    digitalWrite(trigPin_R, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin_R, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin_R, LOW);
  duration_R = pulseIn(echoPin_R, HIGH);
  distance_R = (duration_R)/140;                  //conversion to inches

//This section is for smoothing
  total_R= total_R - readings_R[index_R];           // subtract the last reading:    
  total_L= total_L - readings_L[index_L];        
  readings_R[index_R] = distance_R;                 // read from the sensor:
  readings_L[index_L] = distance_L;
  total_R= total_R + readings_R[index_R];           // add the reading to the total:
  total_L= total_L + readings_L[index_L];
  index_R = index_R + 1, index_L = index_R + 1;     // advance to the next position in the array:
  if (index_R >= numReadings)                       // if we're at the end of the array...
    index_R = 0;                                    // ...wrap around to the beginning
  if (index_L >= numReadings)                    
    index_L = 0;                                  
  average_R = total_R / numReadings;                // calculate the average rt. distance
  average_L = total_L / numReadings;                // calculate the average lft. distance
  difference = average_R - average_L;               // calculate the difference beween sensors
 
//this sections prints out info to the serial monitor
//  Serial.print(average_L);
//  Serial.println("  Left Sensor Avgerage");    
//  Serial.print(distance_L);                      
//  Serial.println("  Left Sensor Data");
//  Serial.print(average_R);
//  Serial.println("  Right Sensor Avgerage");    
//  Serial.print(distance_R);                      
//  Serial.println("  Right Sensor Data");
  delay(2);                                      // delay in between reads for stability          
  }
//  Serial.println("finished new average");
  counter = 0;
}

void loop() {
  smooth_sensors();

//Case #1 - No Time to Turn so Back Up
  if (average_R <= 5 && average_L <= 5){    
      analogWrite (fwd_motor, 0);
      rev_motor_speed = 0;
      stearing.write(center);
      Serial.println("stop and Center stering c1");
      delay (1000);
    while(average_R <= 10 || average_L <= 10){
      analogWrite (rev_motor, 50);
      Serial.println("reverse slowly - Straight c1");
      rev_motor_speed = 50;
      smooth_sensors();
      delay(1000);
    }
  }
//Case #2 - Need to Turn with in Turning Range and drive slow
  if (average_R <= 10 || average_L <= 10){
      if (rev_motor_speed > 0){
        analogWrite(rev_motor, 0);
        rev_motor_speed = 0;
        Serial.println("Turn off rev. motor c2");
        delay(1000);                      //if the Rev Motor is on, turn it OFF and wait 1 sec.
      }      
      if (difference < 0){            //indicates right sensor is closer so turn left
        stearing.write(center - 30);      //turn left
        analogWrite(fwd_motor, 50);        //drive fwd slowly
        Serial.println("   Turning Left and Drive Fwd Slow c2");
        delay(1000);
      }
      if (difference > 0){        
        stearing.write(center + 30);      //turn right
        analogWrite(fwd_motor, 50);        //drive fwd slowly
        Serial.println("  Turn Right and driving fwd slowly c2");
        delay(1000);
      }
      else {
        stearing.write(center);
        analogWrite(fwd_motor, 50);        //drive fwd slowly
        Serial.println("  Drive fwd slowly c2");
        delay(1000);
      }
  }

//Case #3 - No obstacles so drive fwd at full speed.
  if (average_R > 10 && average_L > 10){
    if (rev_motor_speed > 0){
      analogWrite(rev_motor, 0);
      rev_motor_speed = 0;
      stearing.write(center);
      Serial.println("turn off Rev. Motor and center stearing c3");
      delay(1000);      //if the Rev Motor is on, turn it OFF and wait 1 sec.
    }
    while (average_R > 10 && average_L > 10){
        analogWrite(fwd_motor, 255);
        stearing.write(center);
        smooth_sensors();
        Serial.println("Drive Forward Full Speed c3");
        delay(1000);
      }
  }
}

Thursday, June 14, 2012

Smoothing Two Ping Sensors

This is Cool!!

I was able to take the smoothing concept and run it on two ping sensors.  The result is much more fluid changes in values and even when error numbers roll across the screen, the data still only moves slowly.

The down side, given that I am pulling 100 number samples, the response time can be as much 5 seconds.
I will play with that and see if I can't get some better things going.  Or maybe I don't need that level of smooth.

The other thing that I did was to call the smoothing process a function so I can thread it easily into my void loop for when I need decisions to be made.

The code is below.
-------------------------------

// Two Ping Sensors with Smoothing
//by Philip Leete

//Define where the Ping Sensors are
int trigPin_R = 2, trigPin_L = 8;
int echoPin_R = 3, echoPin_L = 9;
int duration_R,    duration_L;
int distance_R,    distance_L;
 
//This sections is required for the smoothing
const int numReadings = 10;
int readings_R[numReadings];
int readings_L[numReadings];                               // the readings from the analog input
int index_R = 0,             index_L = 0;                  // the index of the current reading
int total_R = 0,             total_L = 0;                  // the running total
int average_R = 0,           average_L = 0;                // the average of the light values

void setup() {
  Serial.begin (9600);
  pinMode(trigPin_L, OUTPUT);
  pinMode(trigPin_R, OUTPUT);
  pinMode(echoPin_L, INPUT);
  pinMode(echoPin_R, INPUT);
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings_R[thisReading] = 0;                             // initialize all the readings to 0:
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings_L[thisReading] = 0;
  }

void smooth_sensors(){
    //Activate the Left Ping Sensor
    digitalWrite(trigPin_L, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin_L, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin_L, LOW);
  duration_L = pulseIn(echoPin_L, HIGH);
  distance_L = (duration_L)/140;                  //conversion to inches

//Activate the Right Ping Sensor
    digitalWrite(trigPin_R, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin_R, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin_R, LOW);
  duration_R = pulseIn(echoPin_R, HIGH);
  distance_R = (duration_R)/140;                  //conversion to inches

//This section is for smoothing
  total_R= total_R - readings_R[index_R];           // subtract the last reading:    
  total_L= total_L - readings_L[index_L];        
  readings_R[index_R] = distance_R;                 // read from the sensor:
  readings_L[index_L] = distance_L;
  total_R= total_R + readings_R[index_R];           // add the reading to the total:
  total_L= total_L + readings_L[index_L];
  index_R = index_R + 1, index_L = index_R + 1;     // advance to the next position in the array:
  if (index_R >= numReadings)                       // if we're at the end of the array...
    index_R = 0;                                    // ...wrap around to the beginning
  if (index_L >= numReadings)                    
    index_L = 0;                                  
  average_R = total_R / numReadings;                // calculate the average:
  average_L = total_L / numReadings;                // calculate the average:
 
//this sections prints out info to the serial monitor
  Serial.print(average_L);
  Serial.println("  Left Sensor Avgerage");    
//  Serial.print(distance_L);                      
//  Serial.println("  Left Sensor Data");
  Serial.print(average_R);
  Serial.println("  Right Sensor Avgerage");    
//  Serial.print(distance_R);                      
//  Serial.println("  Right Sensor Data");
  delay(1);                                      // delay in between reads for stability          
}

void loop() {
  smooth_sensors();
}

Smoothing

Today, I need to figure out how to smooth the code (Take the avg. of an analog input).
I hope that this will help to remove some of the bad data and get more consistent results.

The first thing I did was to use the code in the Arduino Exmples along with a light sensor.


/*How to smooth code from a light sensor
modified by Philip Leete from the Arduino Examples
tested with a light sensor wired to a 5v. circuit.
   
This code will show, with LED, how smoothing works by effecting the fade rates
of two LED lights.
*/

const int numReadings = 10;

int readings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average of the light values
int LED_Avg = 5;                // the LED for Avg readings is on pin 5
int LED_Real = 9;               // the LED for Real readings is on pin 9
int Light_Sensor = A0;          // the light sensor is in pin A0
int Light_Value;                // a value used to store the real light value

void setup()
{
  // initialize serial communication with computer:
  Serial.begin(9600);                
  // initialize all the readings to 0:
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings[thisReading] = 0;        
  pinMode(LED_Avg, OUTPUT);
  pinMode(LED_Real, OUTPUT);
}

void loop() {
  // subtract the last reading:
  total= total - readings[index];      
  // read from the sensor:
  readings[index] = analogRead(Light_Sensor);
  // add the reading to the total:
  total= total + readings[index];    
  // advance to the next position in the array:
  index = index + 1;                  

  // if we're at the end of the array...
  if (index >= numReadings)            
    // ...wrap around to the beginning
    index = 0;                        

  // calculate the average:
  average = total / numReadings;      
  // send it to the computer as ASCII digits
  Light_Value = analogRead(A0);

  analogWrite(LED_Real, Light_Value);  //this controls the fading of the LED
  analogWrite(LED_Avg, average);   //this is the fading of each LED

  Serial.print(average);
  Serial.println("  Avgerage");         //you can see how the avg will match the real value
  Serial.print(Light_Value);            //after a few moments.
  Serial.println("  Light Value");
  delay(1);                             // delay in between reads for stability          
}

-----------------------------------------