Servo behaviour

I’ve programmed a very simple obstacle avoidance robot. It goes forward until it finds an obstacle, then it looks right and left with a ping sensor mounted on top of a miniservo and it decides where to turn. Quite easy. The point is that the program only works five times. When it finds the sixth obtacle, it looks right, then it looks forward and the servo stops working! The ping sersor read the distances, the motors turn over smoothly, the only thing that doesn’t work is the mini servo. If I reset the arduino board, it works again correctly…five more times.

I would appreciate any help (and I’m sure my little students too).

I’ve attached the ino sketch.

And since this is my first post, I’d like to apologize if this is not the right place to post it.

Thanks in advance

RobotSimpleV2.ino (1.92 KB)

  servo1.attach(9);
  servo1.write(90);
  delay(400);
  servo1.detach();

Why do you keep attaching and detaching the servo ?

Inside the mira() function (it means to look) I feed a value to the servo in order to look at the desired angle. The IDE asked me to declare the servo's name inside the function as a local variable, so I thought I would attach it and detach it inside the function.

The last 4 lines in the main program loop()

servo1.attach(9);
  servo1.write(90);
  delay(400);
  servo1.detach();

were an attempt to fix the problem with the miniservo going idle at the 6th obstacle detection, but they don't seem to have any effect on the behaviour of the servo. The 400 ms are intended to provide enough time to the servo to reach the programmed angle.

How is your project powered ? Do you have separate power supplies for the Arduino, motors and servos ?

The IDE asked me to declare the servo's name inside the function as a local variable

I don't suppose that it actually said that.

Create an instance of a servo and give it a name at the start of the program after #including the Servo library. Attach the servo to a pin in the setup() function then use the servo name throughout the program. Do not attach/detach it again in the program.

I'll try tomorrow morning to clear the code of servo's attach/detach sentences and I'll let you know if it works. What puzzles me the most is that the robot works fine until 5 obstacles detected. Always 5. I was thinking about some RAM overflow, but it is such a little program...

BTW I have two different power supplies. One for the dC motors and the other one for the arduino, dC motor shield, ping and miniservo.

Aside from the silliness with detaching and attaching the servo all over the place,

long mira(int angulo){
  long dist;
  Servo servox;
  servox.attach(9);
  
  servox.write(angulo);
  delay(1000);
  dist= distancia();
  delay(100);
  servox.write(90);
  delay(1000);
  servox.detach();
  return dist;
}

All those delay() are going to make your robot a bumbling fool. What is the purpose of pointing the servo back to 90?

and the other one for the arduino, dC motor shield, ping and miniservo.

Nice words, but they are like trying to describe a rainbow to a blind person. Post a schematic.

Hi Paul,
I’ll try to explain myself.

the silliness with detaching and attaching the servo all over the place

It was an attempt to extend the battery life, because when you write to the servo, you’re powering it contonuously, even when it reaches the programmed angle. But I agree with you, it seems quite silly.

All those delay() are going to make your robot a bumbling fool

It worked fine…only 5 times. Some of the delays were there to give the servo enough time to get the final angle, others only were intended to increase the waiting time while explaining the behaviour to my daughter. I’ve adjusted the delays already.

What is the purpose of pointing the servo back to 90?

the function mira(input angle) looks at a desired angle. The ping sensor is looking forward (90º) then points to the input angle and then goes back to look forward, ready to the next call. You can avoid going back to 90º if you write the function in some other way, let’s say looking right and left, but you loose the beauty of symmetry.

By the way, I got rid of some attach/detach commands and now the robot works flawlessly. But the doubt remains, why it detected only 5 walls and went crazy at the 6th? I still think it has something to do with the RAM management.

#include <AFMotor.h>
#include <Servo.h>
#define TPin A4
#define EPin A5

AF_DCMotor motor1(1);
AF_DCMotor motor2(2);

Servo servo1;

void setup() {
  pinMode(TPin, OUTPUT);
  pinMode(EPin, INPUT);
  servo1.attach(9);
  Serial.begin(9600);

  // turn on motor
  motor1.setSpeed(180);
  motor2.setSpeed(255);
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  servo1.write(90);
  delay(400);
}

void loop() {
  long la_dist;
  long dist_dreta;
  long dist_esquerra;
  
  la_dist = distancia();
  Serial.println(la_dist);
  delay(200);
  if (la_dist > 30){
    endavant();
  }
  else{
    aturada();
    delay(1000);
    dist_dreta = mira(5);
    //delay(1000);
    dist_esquerra = mira(175);
    if (dist_esquerra > dist_dreta){
        giresquerra();
        aturada();
        delay(400);
    }
    else if (dist_dreta > dist_esquerra){
        girdreta();
        aturada();
        delay(400);
    }
    else{
        endarrera();
        girdreta();
        aturada();
        delay(400);
    }
  }
}
void endavant(){
  motor1.run(FORWARD);
  motor2.run(FORWARD);
}

void endarrera(){
  motor1.run(BACKWARD);
  motor2.run(BACKWARD);
  delay(300);
}

void aturada(){
  motor1.run(RELEASE);
  motor2.run(RELEASE);
}

void girdreta(){
  motor1.run(FORWARD);
  motor2.run(BACKWARD);
  delay(300);
}

void giresquerra(){
  motor1.run(BACKWARD);
  motor2.run(FORWARD);
  delay(300);
}

long distancia(){
  long distx;
  digitalWrite(TPin, LOW);
  delayMicroseconds(2);
  digitalWrite(TPin, HIGH);
  delayMicroseconds(6);
  digitalWrite(TPin, LOW);
  distx = pulseIn(EPin, HIGH, 6000)/29/2;
  if( distx == 0){
    distx= 200;
    return distx;
  }
  else{
    return distx;
  }
}

long mira(int angulo){
  long dist;
  servo1.write(angulo);
  delay(400);
  dist= distancia();
  servo1.write(90);
  delay(400);
  return dist;
}

I still think it has something to do with the RAM management.

The same RAM is being used now, and functioning properly, so I really can't understand your line of thinking.

I'm thinking that, since it works after you stopped attaching and detaching the servos, that detaching and attaching the servos was the problem. But, I could be wrong. I was once.

In the first appoach I had the servo attached/detached every time the function was called. Now, I attach the servo only once, inside the setup(). So attaching/detaching was the problem. But why?

From the point of view of the energy consumption I still think it was better to shut down things you don't use. From the point of view of programming, it seems that syntax was enough correct since the robot worked (until the 6th obstacle). That's the reason why I was thinking about data allocation in the RAM and how recursivity of the loop would affect it, since the only real difference was from where I made the attach/detach call and how many times it was repeated this process. Does it make any sense?

Anyway, I'd like to thank you both Paul and UKHeliBob for your insights. The real hint to fix the code was what UKHeliBob said about an error I was convinced the IDE told me I had with the servo declaration:

I don't suppose that it actually said that.

So thank you again

I still think it was better to shut down things you don't use.

Have you done any comparative measurements of the current consumed by the servo when attached and not attached in software ?

Good point. I'll measure it tomorrow.

Why don't you get your code to tell you what it is doing?

Actually, I think it’s a little shy. We don’t talk to each other like we used to do. But i’ll try again. Thanks for your advise, AWOL.