Encoder and Motor Control

Hi,

I have a project I am working on. Essentially it is a sliding door with a motor attached to it that either opens or closes the door. I have also piggy backed an encoder to the back of this motor.

The handle of the door gives the user a few ways of controlling it.

Firstly there are two force sensitive resistors- one on each side of the handle for each direction. These work very well and easily control the motor in both directions. They are activated by the user pushing on them.

Secondly I have a simple momentary push button on the handle. The idea is if the door is in the closed position and the person wants to fully open the door automatically (without having to walk along side the door) they push this button and the motor opens the door and shuts off when the encoder reaches the end of the door travel.

This push button/encoder section is the part I a having trouble with. The encoder works fine by itself however i think using a while loop is stuffing it up but cant think of another way of doing it…?

If you could take a look it would be appreciated!

thanks, Steve

fsrReading1 and fsrReading0 are the two force sensitive strips. touchtoopen is the button which is meant to open the door automatically. At the moment is does turn the motor on but it seems to run past the encoder position its meant to stop at. Its just quite unreliable atm

const int fsrAnalogPin0 = 0; // FSR is connected to analog 0
int const fsrAnalogPin1 = 1; // FSR is connected to analog 1
int fsrReading0;      // the analog reading from the FSR resistor divider
int fsrReading1;      // the analog reading from the FSR resistor divider
int touchtoopen;
int  x;
#define encoder0PinA  2
#define encoder0PinB  3
volatile unsigned int encoder0Pos = 1000;

void setup() {

  pinMode(7, INPUT);   //touchtoopen switch
  pinMode(10, OUTPUT); //enable
  pinMode(5, OUTPUT); //speed
  pinMode(9, OUTPUT);  //direction
  pinMode(6, OUTPUT);  //relay
  
  pinMode(encoder0PinA, INPUT);
  digitalWrite(encoder0PinA, HIGH);       // turn on pull-up resistor
  pinMode(encoder0PinB, INPUT);
  digitalWrite(encoder0PinB, HIGH);       // turn on pull-up resistor
  attachInterrupt(0, doEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2

  digitalWrite(6, HIGH);  // turn on relay
digitalWrite(10, LOW);  //set motor enable
}

void loop() {

  fsrReading0 = analogRead(fsrAnalogPin0);
  fsrReading1 = analogRead(fsrAnalogPin1);
  x = encoder0Pos;
  touchtoopen = digitalRead(7);

if (touchtoopen == HIGH){      // if touch to open button pushed open door fully then turn motor off
  
  while(x < 2000){
   digitalWrite(9, HIGH);
  analogWrite(5, 50);
  x = encoder0Pos;
}

}
 
else if (fsrReading1 > 200){       // if force sensitive resistor one touched start to close the door         
       digitalWrite(9, LOW);
  analogWrite(5, 50);
}

else if (fsrReading0 > 200){     // if force sensitive resistor zero touched start to open the door
       digitalWrite(9, HIGH);
  analogWrite(5, 50);
}

else {                              // if nothing is touched turned motor off
  digitalWrite(9, LOW);
  analogWrite(5, 0);   
} 
    
}

void doEncoder() {
  
  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
    encoder0Pos++;
  } else {
    encoder0Pos--;
  }
}

There are some things I would change. However before making any suggestions please tell us how many encoder pulses there are per revolution and what is the maximum number of pulses per second. Without that information it is hard to know how busy the Arduino will be.

You don’t seem to have any code to establish the zero postion for the encoder - i.e. where is the door when the Arduino starts?

This sounds like an application where a limit switch at each end of the door travel would be more appropriate and less complex.

…R

Hi,

The encoder is a omron 10 P/R encoder (E6B2-CWZ6C) - http://www.omron.com.au/products/family/487/lineup.html

The max speed of motor is about 1100 RPM, this translates to about 180 pulses per second.

In the code i just had the encoder start at 1000 when the door is in the closed position. I then have it start to count upwards as the door opens. Fully open the door should be at about 1500 - 1800 in the encoder count.

The reason why I would like to get the encoder to work and not use switches is eventually I want the door to begin to slow down before it gets to the closed or open position and not slam shut.

Steve

Robin2:
You don't seem to have any code to establish the zero postion for the encoder - i.e. where is the door when the Arduino starts?

This sounds like an application where a limit switch at each end of the door travel would be more appropriate and less complex.

...R

I agree, when you turn your controller ON, how does it know the door is closed?
Limit switches are a safety device also, to prevent motor over shoot and mechanical damage.
Tom... :slight_smile:

So I only ever turn the arduino on when the door is in the fully closed position. So the starting encoder count is always 1000 when door is fully shut and should stay that way if it never loses count.

End stop switches are a good idea and will look at implementing them.

For your button work: use a finite state machine. That way you can still be responsive to the FSR or the button itself, allowing the user to stop the movement.

So in a very simple form you get something like this:

[loop]
#define DOOR_IDLE 0
#define DOOR_OPENING 1

uint8_t doorState;

void loop() {
  if (buttonPress() && doorState == DOOR_IDLE) {
    doorState = DOOR_OPENING;
  }
  switch (doorState) {
    case DOOR_OPENING:
      runMotor();
      if (doorOpen()) {
        doorState == DOOR_IDLE;
      }
      break;
    }
  }
}

Then you can have another button press, or pressure on the "closing" FSR, have the doorState go to DOOR_IDLE. You can also use the same states, add DOOR_CLOSING, that are directly set using the FSRs.

Indeed the encoder is a good way to keep track of how far you are (note that you use a CHANGE interrupt so you will get two counts for every one "click" of the encoder), but limit switches are a very good addition, and probably necessary. That as it's the only way for you to know where the door is at, when you switch on the power, and allows you to move the door at a greater speed when you know it's well away from its limits, then slow down as you approach the limit, so you can stop gently when the door is fully closed/opened without slamming into to frame or moving really slowly.

In your state machine, the encoder can change the state to say DOOR_OPENING_NEAR_LIMIT when it records you're close (or, on startup, when you just don't know yet where you are), then the limit switch triggering sets it to DOOR_IDLE.

I think you should have a startup routine in which the door is run to one of the limit switches to identify the ZERO position positively. If it is already at the limit then the startup should move it a short distance away from the switch and back to it.

You could also re-verify the encoder position every time that a limit switch is triggered.

In the code in your Original Post you have created encoder0pos as an unsigned int which is 2 bytes. When you read that variable in loop() you need to briefly disable interrupts to ensure that part of the variable is not updated while the other part is being read - like this

noInterrupts();
  latestEncoderCount = encoder0pos;
interrupts();

If it was my project I think I would have a boolean variable (a single byte) to flag when the pulse count has been updated as it would reduce the number of times the encoder0pos needs to be read - something like

if (newEncoderPulse == true) {
  noInterrupts();
    latestEncoderCount = encoder0pos;
    newEncoderPulse = false;
  interrupts();
}

...R

Hi, thanks for the replies.

I have just identified a problem which i think has been contributing to the bad encoder counts. When i have the arduino plugged into the usb port the encoder works fine, doesn't lose count.

Im checking this by turning a little led on when encoder gets to count 100 and the angle at which the led stays on is staying consistant. When i run it off the battery it stuffs up. Im running it off a 14.4v li ion with a step down converter to 5 volts. Any ideas why the battery would be causing problems?

swisscheese:
I have just identified a problem which i think has been contributing to the bad encoder counts.

Post the latest version of your program.

...R

Hi,
Where on the Arduino are you connecting the 5V from the DC-DC converter?

It should be the 5V pin on the Arduino, not the Vin.

Vin is the input to the on board linear 5V regulator and you need at least 7V or more on Vin for it to be able to provide a stable 5V supply.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Tom... :slight_smile:

Circuit diagram please. Common cause would be grounds not connected.

For the start-up problem: that's a safety issue. Imagine power goes out, then back on. You don't know where the door is - open or closed. This may cause the door to start closing without warning and supervision, which is a serious safety hazard (especially if it's a heavy door with strong motors).

So you better have it not do anything upon power on. But indeed no idea whereabouts you are

Then when the button is pressed, you just start opening slowly until you hit the switch - that's your homing. As someone pressed the button, there's a human that wants the door open, so it's safe to move.

Same for the pressure: if there's pressure detected, just start moving slowly until you hit the switch (open or close - either side should have a switch), and you have your home position. Doesn't matter if it's open or close, as long as you know which one it is. The next time you sense pressure, or a button press, you can have it move faster again as you know when to start slowing down.

Now if the door is half open, that's OK. Presumably a human intentionally left the door half open before.

TomGeorge:
Hi,
Where on the Arduino are you connecting the 5V from the DC-DC converter?

It should be the 5V pin on the Arduino, not the Vin.

Vin is the input to the on board linear 5V regulator and you need at least 7V or more on Vin for it to be able to provide a stable 5V supply.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Tom... :slight_smile:

Yep i had it connected to Vin..... on monday i will swap it over and report back. Thanks for the help!

hi,

So I’ve done some changes and it seems to be working fine when i don’t have the motor attached to the door. As in the motor turns until the correct encoder count is read and then it stops. There is also no missing steps. This is when the motor is on the bench.

Problems arise when I attach the system to the door. I think as a load is now applied to the motor it is drawing a lot of amps and this is affecting it.
With the motor attached to the door I serial printed the values to my computer to see what the encoder was doing. As soon as I press the ‘touch to open’ button the motor starts for a split second and then shuts off. At the same time the encoder count goes from about 50 to 63000 instantaneously. The board isn’t shutting down so i think its still getting power but the encoder seems to be losing power.

Any pointers on how i can fix this?

Steve

Hi,
What is the spec on your motor ?
Can you please post a link to spec/data?
What are you using to control the motor?

What are you using for your power supply/supplies?

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom.. :slight_smile:

swisscheese:
As soon as I press the ‘touch to open’ button the motor starts for a split second and then shuts off.

Maybe it’s necessary to do some safe and manual tests of motor and door combination. That is… have a safety switch that lets you manually operate the motor/door combination… to see if works under various conditions. That is… don’t involve arduino to begin with… to assess whether the door/motor works. If it does… then it’s going to work with arduino.

Hi,

Here is the motor, it is a brushless dc motor with hall sensor -

To run the motor I am using a bld 120a motor driver -

The battery I am using is a 14.4 Li-ion 1500 mah. Samsung cells.

I don't have a diagram but will try and explain the setup as best as possible.

I have power coming from battery going to voltage Regulator. Regulator set to output 9 Volts. This is going to Vin on arduino board. Encoder also gets its power from this.

The arduino is then hooked up to a relay which switches on during Setup() with power coming from 5v on arduino board. The relay supplies 14.4v for the motor driver directly from the battery.

This is working perfectly when on the bench with no load/torque applied but when put in the door and button pressed the motor starts for a split second and then stops as the count is getting lost and going outside settings I have in the code. I.e the code is setup to only power the motor between count 50 and 300 however the count is skipping straight to about 63000 when button pressed.

Southpark:
Maybe it's necessary to do some safe and manual tests of motor and door combination. That is.... have a safety switch that lets you manually operate the motor/door combination..... to see if works under various conditions. That is... don't involve arduino to begin with..... to assess whether the door/motor works. If it does.... then it's going to work with arduino.

Hi,

Yes, so if I disregard the encoder from the code and just have the motor turn on with the force sensitive resistors on the handle as the input then the motor works completely fine when it's in the door. The motor has plenty of power to open/close the door by itself. Problems happen when I try and incorporate the encoder( and only happen when in the door panel).

Steve

swisscheese:
I don't have a diagram but will try and explain the setup as best as possible.

Time to do something about that, then. Circuit diagrams should come before the build.

Powering a relay directly off the Arduino is a bad idea. Why not set your regulator to 5V, and use that to power the Arduino (5V pin), the relay and the encoder?

Overall it sounds like your battery can't supply enough power. A 1500 mAh supplying 5.4A (motor peak current - it will draw that for a while as it gets the door to start moving) is a tall order and most likely will cause the voltage to drop. That can cause all kinds of weird effects on the Arduino.

OK probably not 5.4A peak as you're having this voltage drop, and the motor is rated for 24V while you provide barely more than half that.

Running a motor off batteries is anyway an issue: the battery is probably drained after a couple dozen open/close cycles.

Have just spent some more time trying to get it to work no luck, I think I'll instead just use some end stop switches.

wvmarle - I was told that you should only power the boards through the Vin Pin hence using 9 volts.

The battery is charged when the door is in the closed position.

swisscheese:
wvmarle - I was told that you should only power the boards through the Vin Pin hence using 9 volts.

That's wrong advice then. The Vin pin means you're powering it through the regulator - dropping 4V there, so when you try to power a relay through the 5V pin you may easily overheat it, causing resets. This doesn't seem to be the case here, though. It sounds more like a brown-out: voltage dropping too low causing erratic behaviour.

You can power the boards just fine through the 5V pin (also called Vcc on some boards) - provided you make sure it's really 5V (4.5-5.5V are safe limits). That's basically how your board is powered when connected to USB as well.

When connecting your encoder to 5V you can also be sure that the output signal of the encoder is no more than 5V, and safe to connect directly to an Arduino input pin.