Go Down

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

SimonR

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?

Thanks for your help.

Regards


SimonR

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

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

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 pin


boolean 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 +5V

int val = 0;               // variable to store the value read
int previous_val = 0;           // variable to store the previous value read
unsigned long encoder = 0;           // variable to store the position of the encoder we want


void 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.

Thanks for your help

Regards



SimonR

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

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

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

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

Seems you should have two switches. One at minimum position, and one at maximum position.
Anywhere between is free game.

Go Up