help on using optical encoder with geared dc motor

hi guys i'm doing a project for which i need to move the x axis with the help of a geared dc motor whose position should be controlled by an optical encoder . i have seen videos and tutorials in which they showed how to control the position of the dc motor using rotary encoders by rotating the knob on the rotry encoder but what i want is...

i have to control the motor's position exactly that means i have to pre-program the arduino in such a way that it has to move my dc motor to a certain predefined angle and it should stop at that angle and it should rotate back to the zero angle or to the point where it has started and also while the code is running and if suddenly the power goes off and when i start the arduino again it should reset the motor from where it has stopped to zero degrees.

i heard that it is possible with the use of encoders but i need help in how to do it . which type of encoder should i use ? how the coding has to be done? i have seen some codes and also using pid controll for precise motion controll but im stuck with how to apply it for my purpose. plz help me

First thing, I suspect it will be difficult to get exact position with a DC motor. It is certainly not impossible, but the software won't be simple. A stepper motor would make things much easier.

It would be a big help if you describe the project you are trying to build.

It sounds like you only need positions between 0 and 360 degrees and an absolute position rotary encoder may be suitable - although they are more expensive. If you use a relative position encoder you will need to move the motor to the HOME or ZERO position at every startup so that the Arduino knows where to count from.

...R

i am making an automatic omlet and pan cake making machine which can make omlet and pancakes automatically and an x axis carriage will automatically move the pan cakes or dosas from the hot pan into a plate after they were cooked.

i have to move a carriage in x direction forward for a length of 350 mm wait for some time say 30 secs and moving bacward to its initial or home position.

i am using an old printer head setup for my x-axis which is attatched to a lead screw which is driven by stepper motor(i'm following ur suggestion to use stepper motor). still i need a feedback circuit to know exactly where my stepper is and it should go to home position when the power to the arduino goes off suddenly and after every reset it should check its position . if it is at home position it can start the routine but if its not at home position it should correct itself and start . which encoder should i use and how the code should be? would you plz help me ...

Hi,
If all the arm is doing is moving from one predetermined point to another and back, and those two points do not change.

You could use two limit switches,one at each end of the action, and not have the complexity of an encoder.

Tom.. :slight_smile:

Yes. Limit switches is the right solution. I just dismantled an old radio-cd-player, because the cd unit didn’t work. It was a cd cradle, which could hold three cd’s. It performed all movements always from predefined point a to predefined point b. Like your pancake machine. Not like a printer head, the movements of which depend heavily on what we are printing.
The cd cradle had dc motors and limit switches.

siddhu108:
after every reset it should check its position . if it is at home position it can start the routine but if its not at home position it should correct itself and start . which encoder should i use and how the code should be? would you plz help me ...

I agree with the others. A limit switch is normally used to establish the HOME position. Once the Arduino knows the home position it can determine any other position by counting the steps the motor is asked to make. Of course this assumes that the motor is correctly sized so it can move the load without missing steps.

...R

thank you guys :slight_smile: i am very relaxed now using limit switches is the better and much simpler solution.i will work on the code and will get back to you guys

hi guys
i am using limit switches for position controll of a dc motor with l293d ic for speed and direction controll. i have written the code for speed and direction controll but i am facing problem with position controll.

i am makilng my own limit switch . when the button of the switch is pressed it will give input signal of 5 v to input pin of the arduino which tells the arduino to move the motor or to stop the motor. my required functionality is like this

when the slider on the x axis(plz read my previous posts) is at initial position it is resting on the limit switch ' 1 ' that means the input for arduino is high as long as the slider stays on the switch pressing it. then the arduino should read the signal and make the motor turn such that it moves away from the limit switch heading towards another switch located at the final position of the slider. when the slider press the limit switch 2 again the input for arduino on another pin is high and arduino should stop the motor wait for some seconds and turn the slider backwards to home position and then the process repeats. here is my code for making the slider forward and backward using a driver ic for dc motor without limit switches as i dint know how to code using limit switches

[code
//initialising the pins on arduino
const int in_1=3;
const int in_2=4;
const int pwm=2;
void setup()
{
pinMode(pwm,OUTPUT);
pinMode(in_1,OUTPUT);
pinMode(in_2,OUTPUT);
}
void loop()
{
//forward movement
digitalWrite(in_1,HIGH);
digitalWrite(in_2,LOW);
digitalWrite(pwm,255);
delay(3000);

//bacward movement
digitalWrite(in_1,HIGH);
digitalWrite(in_2,LOW);
delay(3000);
}
]
for this code i need to add limit switches how should i modify my code to get my required functiinality plzzz help me...

You can't use delay() if you want the limit switches to be detected. With the delay(3000) that you have there would also be 3 seconds in which the switch could not be checked.

Have a look at how millis() is used to manage timing without blocking in Several things at a time. Note how each function runs very briefly and returns to loop() so the next one can be called. And there may be dozens of calls to a function before it is actually time for it to do anything.

To control your motors the way you want the simplest way is to have a variable (let's call it moveDirection) that keeps track of the state of the system - maybe having the value 'L' for moving Left and 'R' for Right. If it is moving left and the limit switch is triggered the moveDirection would be changed to 'R' etc. The code would be something like this pseudo code

void loop() {
   checkSwitches()
   moveMotors()
}

void checkSwitches()
   if (digitalRead(leftSwitchPin == LOW) { // assumes LOW when pressed
      moveDirection = 'R'
   }
   // etc for other switch
}

void moveMotors() {
   if (moveDirection == 'R') {
      // code to make motor move right
   }
   // etc
}

...R

hi robin

i have written the code according to your code . i have some small doibt regarding the initialisation of limitswitch state storing variable and assigning and comparing int variable with char variable . here is the code ...

[/
#define in_1 3
#define in_2 4
#define lm_1 5// limit switch1 i/p
#define lm_2 6// limit switch2 i/p
const int pwm=2;
int movedirection;// is it correct initialisation??
char r;
char l;
int lm_1state=HIGH;// variable storing limit switch 1 state
int lm_2state=LOW;// variable storing limit switch 2 state
void setup()
{ 
pinmode(in_1,OUTPUT);
pinmode(in_2,OUTPUT);
pinmode(pwm,OUTPUT);
pinmode(lm_1,INPUT);
pinmode(lm_2,INPUT);
}
void loop()
{
 checkswitches();
 motormove();
}
void checkswitches()
{ 
lm_1state=digitalRead(lm_1);
lm_2state=digitalRead(lm_1);

if(lm_1_state==HIGH)
{    
    movedirection='r';// can we store character in                         int variable
}
if(lm_2state==HIGH)
{   
    movedirection='l';
}
}
    void motormove()
{
if(movedirection=='r')// moving towards right
{
    digitalWrite(in_1,HIGH);
    digitalWrite(in_2,LOW);
    analogWrite(pwm,255);
}

if(movedirection=='l')// moving towards left
{
     digitalWrite(in_2,HIGH);
     digitalWrite(in_1,LOW);
     analogWrite(pwm,255);
}
}
]
is my code correct or should i make any change to it??

The first thing you should do after you write or modify a piece of code is try it out and see what happens. Then you can tell us.

It is very difficult to read code when it is not indented consistently. Use the AutoFormat tool and it will make the code easier for you as well as us.

I am not good at spotting problems without trying to run a program so I may have missed lots of things. These two lines should be deleted

char r;
char l;

and this line

int movedirection;// is it correct initialisation??

should be

char movedirection;

as you want to store a character in it.

While it does not affect the code in anyway I find that the use of what is called camel-case makes variable name easier to read. For example moveDirection rather than movedirection. But this is your own choice.

...R

hi guys i want to know how fast an interrupt will read the state change of an input pin to the arduino. i am using a mechanical rotary encoder whuch was taken from an old mouse.

the two pins from this encoder are connected to the arduino on the interrupt pins. i plan to use both interrupts for position and direction feedback. but the problem is i dont know much about interrupts i have seen some examples and understood a bit but there is no complete explanation about the interrupts and their capability.

in my project the encoder will turn atleast at the rate of 500 rpm. the inputs will change very quickly from on and off states. so my question is , can an interrupt read the states of inputs as quick as they change and do what they need to do as per the code?? or will the interrupts also miss the input pulses when rotating at that rpm?? plzzz help me

siddhu108:
hi guys i want to know how fast an interrupt will read the state change of an input pin to the arduino

Very fast.

You say your encoder is running at 500 rpm but you have not told us how many pulses are produced every revolution. It is the number of pulses per second that will be the limiting factor.

Assuming (wild guess) there are 200 pulses per revolution and 8.33 rps then there would be about 1700 pulses per second or one every 588 microsecs. A 16 MHz Arduino should have no problem with that. (But check my maths and put in the correct number of pulses per revolution).

...R

hi robin

i have written a code for controlling the directon of rotation of a dc motor with limit switches and interrupts to detect them . here is the code plz correct me where i am wrong.

#define motorpin_1 7
#define motorpin_2 8
#define pwm 6
int lm_1=2;
int lm_2=3;
int limitswitch_1state=LOW;
int limitswitch_2state=LOW;
volatile char movedirection;


void setup()
{
   attachInterrupt(0,isr_1,CHANGE);
   attachInterrupt(1,isr_2,CHANGE);
   pinMode(motorpin_1,OUTPUT);
   pinMode(motorpin_2,OUTPUT);
   pinMode(pwm,OUTPUT);
   pinMode(lm_1,INPUT);
   digitalWrite(lm_1,LOW);
   pinMode(lm_2,INPUT);
   digitalWrite(lm_2,LOW);
 }
 
 
 void isr_1()
{

      limitswitch_1state=digitalRead(lm_1);

      if(lm_1==HIGH)
      {
      movedirection='r';
      }

}


void isr_2()

{
      limitswitch_2state=digitalRead(lm_2);
       
      if(lm_2==LOW);
      {
      movedirection='l';
      }

}


void loop()
{
    
    if(movedirection=='r')
    {
      digitalWrite(motorpin_1,HIGH);
      digitalWrite(motorpin_2,LOW);
    }
    
    if(movedirection=='l')
    {
      digitalWrite(motorpin_1,LOW);
      digitalWrite(motorpin_2,HIGH);
    }
}

my question is ,can i write all the code in the interrupts itself without using the loop? if i declare movedirection as volatile and changing its value according to the limitswitch state in the interrupt function will that variable state continues in the loop function as in the interrupt function??

siddhu108:
plz correct me where i am wrong.

You have not said what the program actually does and what you want it to do that is different.

my question is ,can i write all the code in the interrupts itself without using the loop?

It may be possible but it would be a bad idea. Keep the code in the ISR as short as possible.

In fact your ISR code could be shortened to this

void isr_1()
{
     movedirection = 'r';
}

if i declare movedirection as volatile and changing its value according to the limitswitch state in the interrupt function will that variable state continues in the loop function as in the interrupt function??

Yes. That is the whole idea of doing it like that.

Why do you think it might not work like that?

…R

How are your limit switches wired?

Your ISR's do not look correct. The conditional test needs to be on the limitswitch_state. Currently you are testing the pin number which will always appear as HIGH. Why is one switch tested for HIGH and the other one LOW?

Robin's suggestion for the minimal ISR is good.

I would use INPUT_PULLUP on the interrupt pins 2 and 3.

Wire the limit switches between the interrupt pins and ground, so the Arduino reads HIGH when the switch is not closed and LOW when closed. Use FALLING as the mode for the interrupt trigger.

hi robin

thanks for helping me out from this interrupts riddle . i want to keep the interrupt routine as short as possible . i will tell u wat the program does exactly. sorry for not including it in the previous post.

my program will turn a dc motor clockwise which moves a carriage in x axis forward direction. the carriage rests on the limit switch 1 until we power on the arduino. once we power on the arduino the limitswitch1gets a +5v pulse fom the 5v out from arduino which sets the signal to high on the interrupt pin 2 of the arduino. as soon as the interrupt recieves the high signal on the pin2 it should go to the 1st interrupt routine which asks to check the state of the limitswitch 1 and if its high then assign the variable 'moveDirection' a character say 'r'.

then it should return to the loop checks if the 'moveDirection' variable has the value of 'r'.if its 'r' move the motor clockwise which is always true at the startup of the program becoz the limitswitch1 is immediately getting a high signal when arduino turns on becoz carriage rests on the limit switch 1 always at the start.

then while the motor mives the carriage at some point the carriage hits the limitswitch2 which turns on the high signal at interrupt pin 3 and make the motor move back to the limit switch 1 and the process repeats.

hi cattledog,

both the switches are tested for HIGH state only because i am making my own limit switches which are normally open type means they are LOW when its open and they turn HIGH when closed. i have designed like them because a carriage will press the buttons of the switch when it comes into contact with.

but the real problem is this, the interrupts are designed to detect the state change but in my project at the start up of the arduino the state of limitswitch1 will always be high because the carriage will rest on the limitswitch1 always at the start of the program .

but i fear the 1st interrupt will not work because i have written RISING on the first isr attacment which means it should detect the limitswitch state when changing from low to high but the switch will always be high as soon as the arduino powers on . so how to write the interrupt code for that. is my fear true???

i will consider your idea of using pullups on pins 2&3 and making the switches function reverse but still as long as the carriage rests on the limitswitch 1 wether its state is high or low i dont think that the interrupt will detect the state of change because it wont change . so what should i do to make the carriage mive from the limitswitch 1 using an interrupt

@siddhu108

Why did you change from the approach you were taking in reply#8? The use of interrupts was introduced with a discussion of a rotary encoder taken from a mouse. There is no indication that is being used in the latest code.

You appear to be struggling with the use of interrupts, and how to handle your initial conditions. Providing external pulses, not from the switches, to trigger interrupts at start up is not necessary. You should be able to read the switches and know what to do.

Until you understand interrupts better, I would go back reading the limit switches with digitalRead() in loop, and not use interrupts unless you encounter a problem. If you encounter issues, then you can decide to use interrupts for the limit switches when running back and forth. Start up from a parked condition should not involve interrupts.

Hi,

both the switches are tested for HIGH state only because i am making my own limit switches which are normally open type means they are LOW when its open and they turn HIGH when closed.

How are you making sure they are LOW when OPEN?
Do you have a 10K pull down resistor?

Leaving an input open circuit does not mean it is HIGH or LOW, this is because the input is HIGH IMPEDANCE.

Thanks.. Tom.. :slight_smile: