Go Down

### Topic: Position control with DC motor (Read 4809 times)previous topic - next topic

#### SimonR

#15
##### Jul 29, 2015, 09:31 am
Hello MarkT,

The first problem with my code was my multiplication. The return value for  : encoder = (val*1216)/1023; was wrong.
So I did that :  encoder = (val*1216L)/1023L;  and now the encodor value is correct.

So yesterday I used this code :

Code: [Select]
`void loop() {  val = analogRead(analogPin); encoder = (val*1216L)/1023L;         // Do the conversion between coder position and voltage                                    // 1 turn is 360° or 1216 coder values. So we can have the                                     // desired value. Example 3.3V = (675*1216)/1023 = 802 (coder)                                    // is equal to 237°   if(val > previous_val)            // check the side we need to turn  {        if(encoder_pos  < encoder)     // if the value we want is still superior as the current value                                    // the motor turn    {      motorForward(200);    }    else                            // else the motor stop    {     motorBrake();    }   }  else if(val < previous_val)  {    if(encoder < encoder_pos)    {      motorBackward(200);    }    else    {      motorBrake();     }     } previous_val = val;   }`

The motor moves well between 1 to 4V.
But when I did 0 to 1V, 4V to 5V, 5V to 4V and 1V to 0V the motor doesn't move.

I would like to try out your code but I have some questions about it.

- The read_encoder() function : Same as the interrupt, just return the position number?
- the P factor, How to determine the value.

- How to manage the direction by using onlu one direction pin?

Regards

#### SimonR

#16
##### Jul 29, 2015, 02:30 pm
Below the code I wrote :

Code: [Select]
`void loop() { val = analogRead(analogPin); encoder = 1 + (val*1216L)/1023L;         // Do the conversion between coder position and voltage                                    // 1 turn is 360° or 1216 coder values. So we can have the                                     // desired value. Example 3.3V = (675*1216)/1023 = 802 (coder)                                    // is equal to 237°   if(val > previous_val)            // check the side we need to turn  {        if(encoder_pos  < encoder)     // if the value we want is still superior as the current value                                    // the motor turn    {      motorForward(200);    }    else                            // else the motor stop    {     motorBrake();    }   }  else if(val < previous_val)  {    if(encoder < encoder_pos)    {      motorBackward(200);    }    else    {      motorBrake();     }    }  else if(val == previous_val)  {    motorBrake();     } Serial.print (encoder); Serial.print ("  /  ");  previous_val = val;  }`

There's still some problem if anyone has an idea to fixe them.

1 - The motor doesn't move when I do quick transition between (0V to 1V / 4V to 5V /5V to 4V / 1V to 0V), It moves well between 0 and 1 when I change the voltage slowly (100mV by 100mV).

2 - When the voltage doesn't change there are still lot of vibration in the motor. It never really stopped. Except when the value is 0V or 5V

3 - When I comment the Serial.print lines it doesn't work.

Anyone ideas? Or other solutions?

#### MarkT

#17
##### Jul 30, 2015, 01:25 am
That's probably due to using two sets of variables as I mentioned.

Post all the code if you want it fixed, its impossible to guess what the parts of the code
are that you keep a secret!
[ I DO NOT respond to personal messages, I WILL delete them unread, use the forum please ]

#### SimonR

#18
##### Jul 30, 2015, 08:55 am
Hi,  There is the code I used :

Code: [Select]
`// Motor_basic + encoder#define InA1            10                      // INA motor pin#define InB1            11                      // INB motor pin#define PWM1            6                       // PWM motor pin#define encoder0PinA    2                       // encoder A pin#define encoder0PinB    3                       // encoder B pinboolean run = false;                                     // motor moves// volatile long encoder_pos = 0L ;volatile long encoder_pos = 0 ;volatile long encoder_errors = 0L ;volatile byte prev_pins = 0 ;volatile unsigned int encoder0Pos = 1;int analogPin = A0;     // potentiometer wiper (middle terminal) connected to analog pin A0                       // outside leads to ground and +5Vint val = 0;               // variable to store the value readint previous_val = 0;           // variable to store the previous value readunsigned long encoder = 0;           // variable to store the position of the encoder we wantvoid setup() {   Serial.begin (9600);  pinMode (analogPin,INPUT);     pinMode(InA1, OUTPUT); pinMode(InB1, OUTPUT); pinMode(PWM1, OUTPUT);  pinMode(encoder0PinA, INPUT); pinMode(encoder0PinB, INPUT);  digitalWrite(encoder0PinA, HIGH);                      // turn on pullup resistor digitalWrite(encoder0PinB, HIGH);  attachInterrupt (0, encoder_fn, CHANGE) ; attachInterrupt (1, encoder_fn, CHANGE) ;  }void loop() {   val = analogRead(analogPin); encoder = 1 + (val*1216L)/1023L;         // Do the conversion between coder position and voltage                                    // 1 turn is 360° or 1216 coder values. So we can have the                                     // desired value. Example 3.3V = (675*1216)/1023 = 802 (coder)                                    // is equal to 237°   if(val > previous_val)            // check the side we need to turn  {        if(encoder_pos  < encoder)     // if the value we want is still superior as the current value                                    // the motor turn    {      motorForward(200);    }    else                            // else the motor stop    {     motorBrake();    }   }  else if(val < previous_val)  {    if(encoder < encoder_pos)    {      motorBackward(200);    }    else    {      motorBrake();     }    }  else if(val == previous_val)  {    motorBrake();     } Serial.print (encoder); Serial.print ("  /  ");  previous_val = val;  }void encoder_fn (){  byte pins = (PIND & 0x0C) >> 2 ; // read both pins, yield 00, 01, 11, 10 in sequence  if (pins & 2)    pins ^= 1 ;  // convert to 00 01 10 11 sequence    byte diff = 3 & (pins - prev_pins) ; // compute difference from last time (should be 01 or 11)    prev_pins = pins ; // store for next time    if (diff == 1)    encoder_pos += 1 ;    else if (diff == 3)    encoder_pos -= 1 ;    else if (diff == 0)    ;    else    encoder_errors ++ ;}void motorForward(int PWM_val)  { analogWrite(PWM1, PWM_val); digitalWrite(InA1, LOW); digitalWrite(InB1, HIGH); run = true;}void motorBackward(int PWM_val)  { analogWrite(PWM1, PWM_val); digitalWrite(InA1, HIGH); digitalWrite(InB1, LOW); run = true;}void motorBrake()  { analogWrite(PWM1, 0); digitalWrite(InA1, HIGH); digitalWrite(InB1, HIGH); run = false;}`

With this code problems are :

1 - The motor doesn't move when I do quick transition between (0V to 1V / 4V to 5V /5V to 4V / 1V to 0V), It moves well between 0 and 1 when I change the voltage slowly (100mV by 100mV).

2 - When the voltage doesn't change there are still lot of vibration in the motor. It never really stopped. Except when the value is 0V or 5V

3 - When I comment the Serial.print lines it doesn't work.

I did other tests with the error value as you recommanded. The result is much better
Same code as previous juste the loop is changing.

Code: [Select]
` void loop(){  long desired_position = analogRead (analogPin) *912L;  desired_position = desired_position/1023L;  long error = desired_position - encoder_pos ;    if(error == 0)  {     motorBrake();   }  else if(error > 0)  {    motorForward(200);  }  else  {    motorBackward(200);  }  }`

This one works fine. Just some vibrations at 0V and 5V.

Regards

#### SimonR

#19
##### Aug 03, 2015, 05:08 pm
Hello guys,

I can control the motor with the code posted in my previous note when I managed to use the error to move it as mentionned by Mark T.

Now I want to define a 0 position. When the input voltage goes to 0V I have my zero (home) position, but if I stop the power supply, the motor will be stuck in its current position and my zero will be lost.

How can I manage to have a home position no matter what happens.

I though by maybe using a switch. During the setup I turn backward the motor and when I hit the switch I trigger a signal to say that it's my home position.

But if condition doesn't work in the setup so I don't know how to do.

#### scottyjr

#20
##### Aug 03, 2015, 09:44 pm
Quote
But if condition doesn't work in the setup
.

What makes you think that? I can't remember for sure if I've ever had to do it but I think it's just valid code (if you code it correctly) and can be in setup() or loop().

- Scotty

#### MarkT

#21
##### Aug 04, 2015, 12:16 am
The only thing special about setup is that main() calls it before calling loop() the first time.
There's a main.cpp in the sources if you want to check it all out.
[ I DO NOT respond to personal messages, I WILL delete them unread, use the forum please ]

#### Kunal04

#22
##### Oct 15, 2015, 11:09 pm
Hi I don't understand by this part.

Code: [Select]
`// moveMotor(FORWARD, 100, 464*2);                        // direction, PWM, ticks number`

What is the tick number?

Reagrds
Kunal

#### jack wp

#23
##### Oct 16, 2015, 01:49 am
Seems you should have two switches. One at minimum position, and one at maximum position.
Anywhere between is free game.

Go Up