closed loop dc motors control

Hi all,

I am trying to use the arduino board with the motor shield to control the speed of the motor. I have tried to control the motor speed using the following command:

void motor1(int high_low1, int pwm1)
{
digitalWrite(EN1,high_low1);
analogWrite(IN1,pwm1);
}

void motor2(int high_low2, int pwm2)
{
digitalWrite(EN2,high_low2);
analogWrite(IN2,pwm2);
}

void loop()
{
motor1(high, 180);
motor2(high, 180);
}

However, when i test the motor with the vehicle, the vehicle cannot move straightly. Then i tried to use a motor embedded with an encoder to do the dc motor feedback control. The speed of the left motor is kept constant while the speed of the right motor is changed. If the pulse count on the left motor is larger, the speed of the right motor increases. If the pulse count on the right motor is larger, the speed of the right motor decreases. However, this program also doesn’t work as after some time speed of the right motor will keep increasing or keep decreasing.

int IN1 = 6;
int EN1 = 7;
int IN2 = 5;
int EN2 = 4;
int encoder0count = 0; //encoder for left motor
int encoder1count = 0; //encoder for right motor
int encoder0PinA = 2;
int encoder1PinA = 8;
int encoder0PinALast = LOW;
int encoder1PinALast = LOW;
int n0 = LOW;
int n1 = LOW;
int l_pwm = 180; //speed of left motor
int r_pwm = 180; // speed of right motor
int timer = 0;

void setup()
{
Serial.begin(115200);
}

void loop()
{

motor1(HIGH,l_pwm);
motor2(HIGH,r_pwm);

n0 = digitalRead(encoder0PinA);
if ((encoder0PinALast == LOW) && (n0 == HIGH)) {

encoder0count++;
}
encoder0PinALast = n0;

n1 = digitalRead(encoder1PinA);
if ((encoder1PinALast == LOW) && (n1 == HIGH)) {

encoder1count++;
}
encoder1PinALast = n1;

Serial.print(encoder0count);
Serial.print(" “);
Serial.print(encoder1count);
Serial.print(” “);
Serial.print(l_pwm);
Serial.print(” “);
Serial.print(r_pwm);
Serial.println(” ");

if (timer ==100)
{

if (encoder0count < encoder1count)
{
r_pwm–;
}

else if (encoder0count > encoder1count)
{
r_pwm++;
}

encoder0count = 0;
encoder1count = 0;
timer = 0;

}

timer++;
}

void motor1(int high_low1, int pwm1)
{
digitalWrite(EN1,high_low1);
analogWrite(IN1,pwm1);
}

void motor2(int high_low2, int pwm2)
{
digitalWrite(EN2,high_low2);
analogWrite(IN2,pwm2);
}

I want to ask whether there are something wrong in the program or there are any other ways to control the motor speed so the vehicle can move straight.

I am trying to use the arduino board with the motor shield

Which ones? What else is the Arduino doing, if anything?

n0 = digitalRead(encoder0PinA);
 if ((encoder0PinALast == LOW) && (n0 == HIGH)) {
   encoder0count++;
 }
 encoder0PinALast = n0;

 n1 = digitalRead(encoder1PinA);
 if ((encoder1PinALast == LOW) && (n1 == HIGH)) {
   encoder1count++;
 }
 encoder1PinALast = n1;

Polling the encoders is probably not the best way to read them. I'd give some serious thought to using interrupts that are fired when the encoder changed.

What kind of encoders are they? Typically, encoders have multiple pins that need to be read - at least two - and both rising and falling edges need to be considered.

I'd guess that you are missing (lots of) encoder position changes.

I want to ask whether there are something wrong in the program or there are any other ways to control the motor speed so the vehicle can move straight.

You might also have issues with the fact that one revolution of the left motor does not cause as much left progress as one revolution of the right motor causes right progress. In other words, just keeping the two motors turning at exactly the same RPM does not guarantee that the robot goes in a straight line.

thx for your reply, I am using Arduino Duemilanove and i just focus on making the vehicle moving in a straight line, no other tasks are performed by the Arduino.
And the enocders i use are a optical shaft encoder attached to the motors, it generates 512 pulse per rotation, and it has two channel which has 90 degree pharse difference with each other. But i found that the two channel are actually in pharse in some testing i did before.(maybe i made mistake, i’ll try to check the pharse differnece between them), so i drop one channel…
What should i do if the left progress is not the same with the right progress? Does PID control help? How to measure the
error term - difference between left progress and right progress but not the difference between the RPM of the two motors?

What should i do if the left progress is not the same with the right progress?

If the left wheel is slightly larger or smaller than the right one, you'll need to spin one motor faster than the other. The difference in speed will be the ratio of the wheel circumferences.

How to measure the error term

Very carefully measure the wheel circumferences.

Does PID control help?

I can't see how. What are you trying to converge on? What are you measuring to accomplish that convergence?

But i found that the two channel are actually in phase in some testing i did before. (maybe i made mistake

How did you determine this? By polling the encoders? How large are the wheels on the robot? How fast are they turning? 512 pulses per revolution may mean that the pulses will be coming faster than you can poll them, especially with serial output occurring in loop().

the circumferences of the two wheels should be the same and the ratio should be close to 1.

If using PID control, can i converge on the difference between rpm between the wheels?

To determine the phrase between the two wheels, i have used a program to test:

int val; int encoder0PinA = 3; int encoder0PinB = 4; int encoder0Pos = 0; int encoder0PinALast = LOW; int n = LOW;

void setup() { pinMode (encoder0PinA,INPUT); pinMode (encoder0PinB,INPUT); Serial.begin (9600); }

void loop() { n = digitalRead(encoder0PinA); if ((encoder0PinALast == LOW) && (n == HIGH)) { if (digitalRead(encoder0PinB) == LOW) { encoder0Pos--; } else { encoder0Pos++; } Serial.print (encoder0Pos); Serial.print ("/"); } encoder0PinALast = n; }

However, when the wheels move in one direction, sometimes the encoder position increases, sometimes it decreases. If interrupt is used, will serial output fast enough to read the pulse? If not, are there any other ways to read the pulse in order to do the speed control.

the circumferences of the two wheels should be the same and the ratio should be close to 1.

In an ideal world, yes. In an ideal world, you could scrap the encoders, too, and just send the same PWM value to both motors, and the robot would go on a straight line.

If using PID control, can i converge on the difference between rpm between the wheels?

PID control will not help you.

To determine the phrase between the two wheels, i have used a program to test

http://www.arduino.cc/playground/Main/RotaryEncoders Typically, encoders have a PinA and a PinB. They are connected to two pins on the Arduino.

So, it appears that this code is reading one encoder. How that gives you any information about the difference between two encoders is beyond me.

If interrupt is used, will serial output fast enough to read the pulse?

Sorry. This question makes no sense. The interrupt fires when the encoder sends a pulse. The pulse is not coming in to the serial port. There is no output involved.

http://www.arduino.cc/playground/Main/RotaryEncoders Typically, encoders have a PinA and a PinB. They are connected to two pins on the Arduino.

So, it appears that this code is reading one encoder. How that gives you any information about the difference between two encoders is beyond me.

I'm sorry that I've made a mistake, the code in my last reply just measures the encoder position of one encoder, however, when the wheels move in one direction, sometimes the encoder position increases, sometimes it decreases, so I thought reading two pins may cause error and I only measured one pin instead.

I thought reading two pins may cause error and I only measured one pin instead.

Not reading both pins can cause errors. Reading both pins is how you avoid errors.