Go Down

Topic: Arduino 4WD Mobile Platform w/Romeo Board and Devantech Sensor (Read 2738 times) previous topic - next topic

rysw

Apr 25, 2011, 04:00 pm Last Edit: Apr 26, 2011, 04:41 am by rysw Reason: 1
I've assembled the kit, connected all the wires and ran a few examples with the board. All successful. Specifically, I tested the example given starting from Page 10 here and it works. I also made an alternate version which makes the 4WD run a predefined path.

Code: [Select]
// Everything from the previous program except the 'loop' functions remain identical

void loop(void)
{
   forward (10000, 10000);
   delay (100);
   turnright (10000, 10000);
   delay (100);
   forward (10000, 10000);
   stop ();
}


I also was able to successfully run the ping test example, so my Devantech SRF05 sensor is working fine.

The program comes when I try to write a program such that the robot moves forward and prints the changing ping as it advances towards whatever obstacle it's seeing.

Code: [Select]
// Assign wheels to digital I/O channels
int E1 = 5;
int E2 = 6;
int M1 = 4;
int M2 = 7;
int Sensor = 2;

// Stop movement
void stop (void){
 digitalWrite (E1, LOW);
 digitalWrite (E2, LOW);
}

// Move forward
void forward (char a, char b){
 analogWrite (E1, a);
 analogWrite (E2, b);
 digitalWrite (M1, LOW);
 digitalWrite (M2, LOW);
}

// Move backward
void backward (char a, char b){
 analogWrite (E1, a);
 analogWrite (E2, b);
 digitalWrite (M1, HIGH);
 digitalWrite (M2, HIGH);
}

// Turn left
void turnleft (char a, char b){
 analogWrite (E1, a);
 analogWrite (E2, b);
 digitalWrite (M1, HIGH);
 digitalWrite (M2, LOW);
}

// Turn right
void turnright (char a, char b){
 analogWrite (E1, a);
 analogWrite (E2, b);
 digitalWrite (M1, LOW);
 digitalWrite (M2, HIGH);
}

// Convert microseconds to centimeters
long microsecondsToCentimeters (long microseconds)
{
 return microseconds / 29 / 2;
}

// Initialise
void setup (void){
 int i;
 for (i = 6; i <= 9; i++)
 pinMode (i, OUTPUT);
 Serial.begin (19200);
}

// Read input
void loop (void){
 long duration, cm;
 
 pinMode(Sensor, OUTPUT);
 digitalWrite(Sensor, LOW);
 delayMicroseconds(2);
 digitalWrite(Sensor, HIGH);
 delayMicroseconds(5);
 digitalWrite(Sensor, LOW);
   
 pinMode(Sensor, INPUT);
 duration = pulseIn(Sensor, HIGH);
 cm = microsecondsToCentimeters(duration);
 Serial.print(cm);
 Serial.print(" cm");
 Serial.println();
 delay (1000);
 
 forward (10000, 10000);
}


The distance is being printed on the serial monitor, but the 4WD doesn't move and a continuous beep sound can be heard, which I take to mean an error.

Can someone explain to me what I'm doing wrong? Thanks in advance. ^^;

wildbill

Does that compile without warnings/errors? Your steering functions expect char parameters and are used in that fashion in the example you linked to. Your code however, is passing 10000, which is orders of magnitude too big. Try 100.

PaulS

Why isn't all this code in it's own function?
Code: [Select]
  long duration, cm;
 
  pinMode(Sensor, OUTPUT);
  digitalWrite(Sensor, LOW);
  delayMicroseconds(2);
  digitalWrite(Sensor, HIGH);
  delayMicroseconds(5);
  digitalWrite(Sensor, LOW);
   
  pinMode(Sensor, INPUT);
  duration = pulseIn(Sensor, HIGH);
  cm = microsecondsToCentimeters(duration);
  Serial.print(cm);
  Serial.print(" cm");
  Serial.println();

rysw

#3
Apr 26, 2011, 04:48 am Last Edit: Apr 26, 2011, 06:42 am by rysw Reason: 1

Does that compile without warnings/errors? Your steering functions expect char parameters and are used in that fashion in the example you linked to. Your code however, is passing 10000, which is orders of magnitude too big. Try 100.


Yeah, no warnings or errors whatsoever. By magnitude being too big, do you mean that there's some limit to the char type arguments I can write in the code? Because 10000 works fine when there's no sensor codes in the loop function.


Why isn't all this code in it's own function?
Code: [Select]
 long duration, cm;
 
 pinMode(Sensor, OUTPUT);
 digitalWrite(Sensor, LOW);
 delayMicroseconds(2);
 digitalWrite(Sensor, HIGH);
 delayMicroseconds(5);
 digitalWrite(Sensor, LOW);
   
 pinMode(Sensor, INPUT);
 duration = pulseIn(Sensor, HIGH);
 cm = microsecondsToCentimeters(duration);
 Serial.print(cm);
 Serial.print(" cm");
 Serial.println();



This is bad coding on my part. I'm trying to get things working before tidying it up. ^^;

Would badly organised coding cause some kind of logic error?

EDIT:

Turns out that changing my steering function values to 100 works like a charm. Thanks a lot, Bill, but do you mind explaining why 10000 was not working? Is it some kind of overflow?

wildbill

From the reference:
Quote

The char datatype is a signed type, meaning that it encodes numbers from -128 to 127. For an unsigned, one-byte (8 bit) data type, use the byte data type.


In other words, it's a single signed byte with a maximum value of 127. No way to squeeze 10,000 in there.

jraskell


From the reference:
Quote

The char datatype is a signed type, meaning that it encodes numbers from -128 to 127. For an unsigned, one-byte (8 bit) data type, use the byte data type.


In other words, it's a single signed byte with a maximum value of 127. No way to squeeze 10,000 in there.


What the Arduino does is squeeze the first 8 bits of that 10,000 into the char (since the char is an 8 bit datatype).  So you were actually setting that char to a value of 16.
10,000 in binary = 10011100010000
The first 8 bits being underlined is what gets assigned to your char variables, which equals a value of 16.

It is always important to make sure the values you are working with fit within the range of values the datatype can hold.  The Arduino reference lists these ranges for every datatype.

rysw

I see. Thanks for the replies.

So, if I want to turn the device 180 degrees, how should I go about doing that? E1 and E2 are motor speed controls, so I guess changing the value it receives won't change anything. Will I just have to brute-force my way through and test how long the steering function has to be on for before it turns around?

Aeturnalus

Unless you have a way of measuring wheel speeds (encoders), then yes, you will need to experiment with open-loop angular control.  You could, of course, just build some encoders, and use some basic math to find angular rate of the drive base from the angular rates of the wheels. 

rysw

So I'm guessing I should do something like:

Code: [Select]
  if (distance < 17){
    stop ();
    backward (100, 100);
    delay (1000);
    for (int i = 0; i < 10000; i++){
      turnleft (-100, -100);
    }
    delay (1000);
  }


And fiddle around with the maximum value for counter 'i'?

Also, I've now mounted a servo to the platform. The Sweep example works just fine, but again, I'm having trouble making the parts all work together. I've asked the Arduino to set the servo to a certain position after it has detected an obstacle, but it skips that part of the code.

Code: [Select]
// Include servo library
#include <Servo.h>

// Assign servo to function name
Servo myservo;

// Assign wheels to digital I/O channels
int E1 = 5;
int E2 = 6;
int M1 = 4;
int M2 = 7;
int Sensor = 2;

// Stop movement
void stop (void){
  digitalWrite (E1, LOW);
  digitalWrite (E2, LOW);
}

// Move forward
void forward (char a, char b){
  analogWrite (E1, a);
  analogWrite (E2, b);
  digitalWrite (M1, LOW);
  digitalWrite (M2, LOW);
}

// Move backward
void backward (char a, char b){
  analogWrite (E1, a);
  analogWrite (E2, b);
  digitalWrite (M1, HIGH);
  digitalWrite (M2, HIGH);
}

// Turn left
void turnleft (char a, char b){
  analogWrite (E1, a);
  analogWrite (E2, b);
  digitalWrite (M1, HIGH);
  digitalWrite (M2, LOW);
}

// Turn right
void turnright (char a, char b){
  analogWrite (E1, a);
  analogWrite (E2, b);
  digitalWrite (M1, LOW);
  digitalWrite (M2, HIGH);
}

// Sensor ping test
long Ping (int a){
  long duration, distance;
 
  pinMode(a, OUTPUT);
  digitalWrite(a, LOW);
  delayMicroseconds(2);
  digitalWrite(a, HIGH);
  delayMicroseconds(5);
  digitalWrite(a, LOW);
 
  pinMode(a, INPUT);
  duration = pulseIn(a, HIGH);
  distance = duration / 29 / 2;
 
  return distance;
}

// Initialise
void setup (void){
  int i;
  myservo.attach (1);
  for (i = 6; i <= 9; i++){
    pinMode (i, OUTPUT);
  }
  Serial.begin (19200);
}

// Read input
void loop (void){
  long distance;
 
  // Run ping test to gauge distance
  distance = Ping (Sensor);
 
  // If distance < 17cm
  if (distance < 17){
    stop ();
    backward (100, 100);
    delay (1000);
    myservo.write (0);
    delay (500);
    myservo.write (180);
    delay (500);
  }
  // If distance > 30cm
  // Note to self: 13.5cm distance from delivery board
  else if (distance > 30){
    stop ();
    forward (100, 100);
    delay (1000);
    myservo.write (0);
    delay (500);
    myservo.write (180);
    delay (500);
  }
}


Any ideas?

jraskell

Code: [Select]
I'm having trouble making the parts all work together.

Say hello to the pitfall of delay().  Don't use delay().  Period.

Look at the Blink Without Delay example.
Learn the Blink Without Delay example.
Love the Blink Without Delay example.
Work with the Blink Without Delay example until you have a full understanding of it's true power.
Only then will you be able to easily and seamlessly get multiple separate systems all working together on the same AVR microprocessor.

Ok, I'm admittedly being more than a bit melodramatic, but it's for good reason.  delay() really is an extremely limiting little function and should only ever be used in the most simple of sketches.  I'm of the firm belief that Arduino should provide NO examples that use delay().  That one little function has been the source of countless beginner problems.  Probably the only beginner problem bigger than delay() is working with Serial input.

Bottom line, delay() IS evil (and that's not being melodramatic).

rysw

Looks like I've got homework to do over the weekend.

Thanks for the tip. I'll come back if I run into problems. ^^

Go Up