strange code/servo malfunction

ok, so i got V1.1 of the code for PRObot (not the one in my sig, it is now a black painted sigar box), with no OS, for my second robot body,mainly because i have plans to use it for other things.
also, i am now using the servo libary instead of my own for ease of use reasons, although this may be the cause of the problem.
my robot drives, and when it senses a waal, it looks right, then left(recording data from the rangefinder) but then the servo is meant to go back to middle posision, the robot starts slowly turning right and the servo twitches. even stranger, my stop button doesnt work(although i programed it to complete a cycle before listening to it) saying that there is either a fatal error or an infinite loop. this is all the code:

robot1.1:

/* ///////////////
//PRObot 1.1 code/
//by Laurens Weyn/
//for PRObot,also/
//built by       /
//Laurens Weyn   /
*/ ///////////////

#include <Servo.h> 

#define switchpin 12
#define IRPin 0
Servo Lmotor;
Servo Rmotor;
Servo sensor;  // create servo object to control a servo 

void setup() 
{ 

  attatchServos();//attatch / initialize servos
  attatchSensors();//set pin modes for sensors
} 

void loop() 
{ 
  sensor.write(80);//mid point for some reason.(80 degrees,not 90)
if(digitalRead(switchpin)==true)
{
  
if(analogRead(IRPin)>200)//wall nearby
{
  //driveStop(0);//stop the car
  
  if(scan()==true)
  {
    turnLeft(2000);//turn 90 degrees
  }else
  {
    turnRight(2000);//turn 90 degrees
  }
  
}else {driveForward();delay(100);}//else, continue driving //end wall nearby

}

else driveStop(0);//do not drive, here to prevent robot from driving away randomly(when there is an error in code).
}

sensor:

void attatchSensors()
{
    pinMode(switchpin, INPUT);
}

boolean scan()
{
  int leftVal;
  int rightVal;
  
sensor.write(0);
delay(300);
leftVal=analogRead(IRPin);
sensor.write(180);
delay(300);
rightVal=analogRead(IRPin);
sensor.write(80);//mid point for some reason.(80 degrees)

if(leftVal>rightVal)
{return true;}else{return false;}
}

servo:

void attatchServos()
{
  sensor.attach(2);
  Lmotor.attach(8);
  Rmotor.attach(9);
}


void turnLeft(int time)
{
  Lmotor.write(180);
  Rmotor.write(180);
  driveStop(time);
}
void turnRight(int time)
{
  Lmotor.write(0);
  Rmotor.write(0);
  driveStop(time);
}
void driveForward()
{
 Lmotor.write(0);  //drive 
 Rmotor.write(180);//forwards
}
void driveBackward()
{
 Rmotor.write(0);  //drive 
 Lmotor.write(180);//bakwards
}
void driveStop(int time)
{
  delay(time);
 Lmotor.write(90);//stop
 Rmotor.write(90);//stop
}

I don't remember PRECISELY when this crash happens, but it causes a slow right turn on the contunus servos.

Servo sensor;  // create servo object to control a servo

A most confusing name...

#define switchpin 12

Tells us nothing about the purpose of the switch attached to pin 12. Is it a limit switch? An "on" switch?

if(digitalRead(switchpin)==true)

The digitalRead() function returns HIGH or LOW, not true or false. While the value of HIGH and the value of true may be the same, the meaning is certainly not.

if(analogRead(IRPin)>200)//wall nearby

The value goes up as the wall gets closer?

sensor.write(0);
delay(300);

Does it take 3/10 of a second for the servo to travel 80 degrees?

sensor.write(180);
delay(300);

So, how come it also takes 3/10 of a second to travel 180 degrees?

If the midpoint is not 90 degrees, how is it that the left and right extents are 0 and 180?

if(leftVal>rightVal)
{return true;}else{return false;}

would be a lot simpler as

return leftVal > rightVal;

You realize that scanning takes 6/10 of a second, right?

  }else
}else {driveForward();delay(100);}//else, continue driving //end wall nearby

There is no reason to jam the else tight up against the }. Put it on the next line.

There is no reason to put multiple commands on the same line, or to put code on the same line as the {. Spread stuff out so it easier to read.

void driveStop(int time)

Drive and Stop in the same function name? Is the function supposed to make the robot drive or stop?

I don't remember PRECISELY when this crash happens, but it causes a slow right turn on the contunus servos.

This will make it difficult to solve, then. There is nothing in this code that causes a slow turn. The robot moves as fast as possible until there is something in front of it. Then, it comes to a complete stop, looks left and right, chooses a direction, turns for 2 seconds (seems like a long time to make a turn), then speeds off again, ignoring everything for 1/10 of a second at a time.

Anything outside of this behavior is a hardware problem.

PaulS:

Servo sensor;  // create servo object to control a servo

1.A most confusing name...

#define switchpin 12

2.Tells us nothing about the purpose of the switch attached to pin 12. Is it a limit switch? An "on" switch?

if(digitalRead(switchpin)==true)

3.The digitalRead() function returns HIGH or LOW, not true or false. While the value of HIGH and the value of true may be the same, the meaning is certainly not.

if(analogRead(IRPin)>200)//wall nearby

4.The value goes up as the wall gets closer?

sensor.write(0);

delay(300);



5.Does it take 3/10 of a second for the servo to travel 80 degrees?



sensor.write(180);
delay(300);



6.So, how come it also takes 3/10 of a second to travel 180 degrees?

If the midpoint is not 90 degrees, how is it that the left and right extents are 0 and 180?



if(leftVal>rightVal)
{return true;}else{return false;}



7.would be a lot simpler as


return leftVal > rightVal;




8.You realize that scanning takes 6/10 of a second, right?



}else
}else {driveForward();delay(100);}//else, continue driving //end wall nearby



9.There is no reason to jam the else tight up against the }. Put it on the next line.

9.There is no reason to put multiple commands on the same line, or to put code on the same line as the {. Spread stuff out so it easier to read.



void driveStop(int time)



10.Drive and Stop in the same function name? Is the function supposed to make the robot drive or stop?



> I don't remember PRECISELY when this crash happens, but it causes a slow right turn on the contunus servos.


11.This will make it difficult to solve, then. There is nothing in this code that causes a slow turn. The robot moves as fast as possible until there is something in front of it. Then, it comes to a complete stop, looks left and right, chooses a direction, turns for 2 seconds (seems like a long time to make a turn), then speeds off again, ignoring everything for 1/10 of a second at a time.

Anything outside of this behavior is a hardware problem.
  1. its basicaly an external switch, sinse all electronics are housed in a box, it can be quite hard to turn of the robot during a malfunction(like this one). also, VERY handy when you want to upload code to the robot without it driving off the table.

  2. sorry, used to that from Java. changing that.

  3. yes, yes it does. i dont know why, but that is how IR rangefinders work.

5.dont know, just chose a random delay. ill change that to 1 second
6.aaand that.

  1. didnt know that, changing it

  2. yes. so?

9.sorry bout that.

10.for some reason, the compiler didnt let me use stop. probably used by something else. driveStop was used due to the drive commmands being grouped. also, i was told to do these things by my teatcher, so you can make, for E.G. sensorStop or something else of that type.

  1. ill try re-run the robot. and yes, that is what it does. drives to the furthest detected distance. and full rotation servos are slow yet strong. it can make a 90 degree turn in that time.(or very close). or the battery as almost dead.

10.for some reason, the compiler didnt let me use stop. probably used by something else.

whoa(), stopDriving(), stopNowDammit(), ...

A function name should reflect what the function does, and typically contains a verb or a verb and noun, when the verb alone is insufficient (or reserved). drive is a verb. So it stop. Using two in a function name is confusing.

ok, so when it encounters a wall, it seems the half workingly look left and right, then slowly turn right again, before repeating this 3 times or so when it randomly turns right slowly continusly.

however, it seems that driveStop is causing the problem, here:

if(analogRead(IRPin)>200)//wall nearby
{
  driveStop(0);//stop the car

but I can't just remove it. i have tryed that, though. it fixes it. but the robot rammed into the wall.

PaulS:

10.for some reason, the compiler didnt let me use stop. probably used by something else.

whoa(), stopDriving(), stopNowDammit(), ...

A function name should reflect what the function does, and typically contains a verb or a verb and noun, when the verb alone is insufficient (or reserved). drive is a verb. So it stop. Using two in a function name is confusing.

ok, then. ill remember that for next time.

I think that is is time to put the robot on a stand, and connect it to the computer, and use Serial.begin() and Serial.print() to understand what it is doing.

Store the value from analogRead(IRPin) in a variable so you can print it and use it.

Print it out. Print out the values from analogRead in the scan() function.

Determine that the IR sensor is working correctly. Determine that the servo that the IR sensor is attached to is moving correctly.

The servos you are using for motion may be a problem. You assume that 0 full speed in one direction, that 180 is full speed in the other direction, and that 90 is stopped. These values may not be correct. Full speed one way may be a few degrees off of 0. Full speed the other way may be a few degrees off of 180. Stopped may be a few degrees off of 90.

Typically, people do not use Servo.write() to command continuous rotation servos (which really are not servos, but we won't get into that again). Typically, they use Servo.writeMicroseconds() to get better control over the top speed in each direction and minimum speed (stopped).

Add Serial.print() statements in each function, too, so you can track the function calls made when the robot has problems.

strange, works fine when plugged in:

startup complete
wall detected!
stopped
starting scan...
left value recorded: 103
right value recorded: 352
scan false,turning right
scan complete!

but when on battery power it does this. i have seperate batteries for the microcontroller and for the servos. checking them both...
that is probably the problem.

fixed it!
servo batteries were dead, causing the circut to attempt to take power from that poor 9V battery, and that powering 3 servos caused a power shortage, causing the system to not have enough power to function properly. OK, then. what else to make it do.....

thanks for the help!

servo batteries were dead, causing the circut to attempt to take power from that poor 9V battery

How have you got the batteries wired?

Below is some code I used with the serial monitor to test two continous rotation servos for a two wheel routerbot. Due to the small ~10us off deadband, using writeMicroseconds is about the only way to center the servo stopped value. Servos can be detatched to stop unwanted movement, but don't have any code doing this.

// zoomkat 11-22-10 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 0019 and later
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550

#include <Servo.h> 
String readString, servo1, servo2;
Servo myservo1;  // create servo object to control a servo 
Servo myservo2;

void setup() {
  Serial.begin(9600);
  myservo1.attach(6);  //the pin for the servo control 
  myservo2.attach(7);
  Serial.println("servo-test-21"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    delay(1);  
    if (Serial.available() >0) {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    } 
  }

  if (readString.length() >0) {
      Serial.println(readString); //see what was received
      
      // expect a string like 07002100 containing the two servo positions      
      servo1 = readString.substring(0, 4); //get the first four characters
      servo2 = readString.substring(4, 8); //get the next four characters 
      
      Serial.println(servo1);  //print to serial monitor to see results
      Serial.println(servo2);
      
      int n1; //declare as number  
      int n2;
      
      char carray1[6]; //magic needed to convert string to a number 
      servo1.toCharArray(carray1, sizeof(carray1));
      n1 = atoi(carray1); 
      
      char carray2[6];
      servo2.toCharArray(carray2, sizeof(carray2));
      n2 = atoi(carray2); 
      
      myservo1.writeMicroseconds(n1); //set servo position 
      myservo2.writeMicroseconds(n2);
    readString="";
  } 
}