Help with Saving Motor Position and Recovery after Interruptions

Hello everyone,

I'm working on a motor control project for my mechatronics engineering course, and I've run into a challenge that I hope you can help me solve.

The goal is to control a motor to rotate toward a desired position and then return to its initial position (0). The important thing is that the home position is saved in some way so that in the event of a power outage or other unwanted interruption, we can recover and return the motor to this home position.

I have written a code base (see below) that uses an encoder to track the motor position, but I am having difficulty implementing an effective way to save and retrieve the motor position using EEPROM. Especially to ensure that the position is kept up to date without overwrite the EEPROM too much.

Here is the code I've been working on:

// Defines the pin for encoder B
const int pinEncoderB = 3; // Make sure the pin supports interrupts

// Defines the pins for motor control
const int pinMotorControl1 = 7; // PWM pin to control speed or direction
const int pinMotorControl2 = 8; // PWM to control speed or direction
const int pinEnableMotor = 6; //Enable pin for motor driver

long encoderValue = 0;
long desiredPosition = 177; // Degrees with an error of +2 due to the error

void setup() {
   pinMode(pinEncoderB, INPUT_PULLUP);
   attachInterrupt(digitalPinToInterrupt(pinEncoderB), readEncoder, CHANGE);
   pinMode(pinMotorControl1, OUTPUT);
   pinMode(pinMotorControl2, OUTPUT);
   pinMode(pinEnableMotor, OUTPUT);
   Serial.begin(9600);
}

void loop() {
   long positionError = desiredPosition - encoderValue;
   if (encoderValue < desiredPosition) {
     //Moves the motor forward
     analogWrite(pinEnableMotor,100); //Enable motor
     digitalWrite(pinMotorControl1, HIGH);
     digitalWrite(pinMotorControl2, LOW);
   } else {
     // Stops the engine
     digitalWrite(pinEnableMotor, LOW);
   }
   Serial.println(encoderValue);
}

void readEncoder() {
   // Increase the encoder value with each change
   encoderValue++;
}

This are my questions:

  1. How can I modify my code to correctly implement the EEPROM save functionality and retrieve motor position effectively and safely?
  2. Is there a better strategy to handle unwanted interruptions, such as power outages, by ensuring that the motor returns to its initial position upon restart?

Any suggestions, code examples, or references to relevant documentation would be greatly appreciated.

Thank you in advance for your help!

The usual way would be to use endstops, absolute position encoders and index. You can save whatever you like to eeprom, but when the motor is turned while the arduino is off it's no use.

Welcome to the forum

What type of motor are you using ?
Whatever it is, the obvious solution is to have a way of knowing that the motor has reached its home position such as a mechanical switch ot interruption of a light beam

The initial position of your motor is ALWAYS ZERO, so there is no reason to save it or try to do something with it.

We are using an EMG30 Motor, this type of DC motor uses two encoders, but only one works. We are using that encoder for the current position of the motor. However, what we wanted to do is that in case the light goes out or something similar, the motor will be able to return to that 0 position. As you know, every time the motor is started again it causes its position to reset and the current one becomes 0 and we don't want that. I hope more or less to explain myself

It does sound like a home position switch of some kind is the answer otherwise you would need to save the current position each time the motor moves in order to return to position zero after a restart

How often does the motor move ?

As soon as your mechanic is moved with microcontroller switched off. All positioning saving has no more value and is useless.

Whenever your mechanic is moved and your microcontroller does not count encoder-pulses because the microcontroller is switched off = microcontroller program does NOT run. The real actual position will be unknown.

Instead of insisting on "there must be a way to do it" when there is no way with an incremental encoder.

You should give a detailed description of your project and post pictures how the mechanic looks like and what this mechanic is used for.

As soon the other users here on the forum have a clear picture of your project and your mechanic good suggestions can be made.

Without giving this detailed description you will have to think through all the generalised suggestions if they are really suitable for your application. Without giving this detailed description you can not use the years and decades of experience of the users here what kind of sensor might be suitable

as there are

  • using an absolute encoder. There are many different types with very different prices

  • using a distance-measuring sensor (which again there are many different types with very different prices of very different size
    unclear what precision you need

  • as this is a mechatronics project build an absolute encoder yourself
    (no idea what skills and machines you have available for building such an absolute encoder)

All in all
welcome to the arduino-forum.
I'm pretty sure that you agree and will follow the way how to solve your problem mimimum 200 minutes faster.
This requires to invest 20 minutes of your precious time to read how to speedup solving your problems.

Directly after registering you got presented informations how to speed up solving your problem.
You should really read it.

best regards Stefan

My name is Alan and I would like to ask for help with a project I have for university. What I need to make is an automatic pillbox, the pillbox will have 13 empty spaces and one extra, which will be covered to be our starting position (giving a total of 14 spaces). As I am relatively new to the Arduino and I am in an "early" stage of the code, I am testing how I can make the motor rotate to the desired position and return to the initial position. As well as implementing a way that when "resetting" the pill box, it returns to the initial position regardless of the position it was in before the reset. For example: if the motor was in a 90° position, when the pill box is reset, it should return to 0, that is, the position of the closed space.
What I have been using is code that ChatGPT has given me, however, it does not work or does not correctly comply with what is being requested.

My problem lies in 2 things:

  1. How can I make the motor return to the initial position?
  2. How can I save the last position collected from the encoder and have it be used when restarting the pill box?

For the second issue, a professor recommended that I use EEPROM memory, but I would also like to hear his recommendations to see if it is feasible to use it or not.

What will be used will be an Arduino nano, however, at the moment I am using an Arduino UNO because that is the one I have at the moment. In addition to using:
A voltage source from the same university, in which 12V is being provided to the H bridge
an H-bridge (L298N): L298N Motor Driver Module Pinout, Datasheet, Features & Specs
a DC Motor (EMG30): EMG30 data
The issue with the motor is that it has 2 encoders, however, only one works. Making it so that instead of giving 360 beats per turn, it only does 180.

What I take from the code is something very basic to move the motor to a position x.

//Code for the motor position

// Defines the pin for encoder B
const int pinEncoderB = 3; // Make sure this pin supports interrupts

// Defines the pins for motor control
const int pinMotorControl1 = 7; // Example of PWM pin to control speed or direction
const int pinMotorControl2 = 8; // Example of PWM pin to control speed or direction
const int pinEnableMotor = 6; //Enable pin for motor driver

long encoderValue = 0;
long desiredPosition = 177; // Degrees with an error of +2 due to the error

void setup() {
   pinMode(pinEncoderB, INPUT_PULLUP);
  
   attachInterrupt(digitalPinToInterrupt(pinEncoderB), readEncoder, CHANGE);

   pinMode(pinMotorControl1, OUTPUT);
   pinMode(pinMotorControl2, OUTPUT);
   pinMode(pinEnableMotor, OUTPUT);
  
   Serial.begin(9600);
}

void loop() {
   long positionError = desiredPosition - encoderValue;

   if (encoderValue < desiredPosition) {
     //Moves the motor forward
     analogWrite(pinEnableMotor,100); //Enable motor
     digitalWrite(pinMotorControl1, HIGH);
     digitalWrite(pinMotorControl2, LOW);
    
  // if(positionError> encoderValue){
   // analogWrite(pinEnableMotor,100); //Enable motor
    // digitalWrite(pinMotorControl1, LOW);
     //digitalWrite(pinMotorControl2, HIGH);
//readEncoder2();
  // }
   
   } else {
     // Stops the engine
     digitalWrite(pinEnableMotor, LOW);
   }

   Serial.println(encoderValue);
}

void readEncoder() {
   // Increase the encoder value with each change
   encoderValue++;
}
// void readEncoder2() {
   // REDUCES the encoder value with each change
  // encoderValue--;
//}

I attach photos of what I have from the project. (PS: I couldn't take a photo of the engine, since it is difficult to remove the engine)



Now who would have guessed that?

Can you explain how a covered space will be identified by your program?

My apologies, I split off 3 replies into another topic thinking they were a hijack of someone else's topic, then I noticed they were actually part of the same person's topic, so I have put them back.
Sorry for the mess.

Please explain how this project relates to your first post in this thread.

  • You might want to consider 14 Hall-effect switches, use digital sensors not analog. (20 for $12.00 Amazon)
    A magnet at an index location is detected by these sensors.

  • You would of course need 14 Arduino inputs.

  • A simple gear motor with MOSFET driver would turn the disc.
    No reversing is needed.

  • You would not need direct drive, simple friction slip clutch connection would be okay.

You need a way to sense power failing and save the current position to EEPROM. You could keep a small super capacitor charged and switched in at power failure to power the MCU just long enough to save a few parameters. Another way would be using an external battery backed counter that the MCU could read on restart.

Apologies if I missed it but, what does the thing do in NORMAL operation?

Okay, reading a lot of your points and questions that you tell me. The normal operation of the pill box is that when the time to dispense the pill arrives (this time will be assigned by the user). The motor rotates from the initial position (the covered space) to where the pad is located. Wait a certain amount of time and return to the starting position.

The compartment assigned by the user and the time in which the motor would move is being seen by another colleague, who will use an RTC so that it can work.

Returning to the engine, although I like the ideas of putting sensors and other components for the desired position. It is complicated for me due to electronic limitations. Since my team and teacher tell me that with the material we are working on we can make it work perfectly. Just as the electronic components would go inside the pillbox, we have limited space.

Regarding the initial position, it was planned to declare in the code that the covered space would be position 0. How do we declare it for the initial position, what is planned is that when the pill box is started it will already be in the covered part so that it takes it as the initial position.

Continuing in the same direction or reversing?

Is this an academic exercise for far away from everyday life teaching professors
or
should this device be developped to a stage that is working high reliably and therefore could be really used in everyday life.

With operating high reliably I mean the following case:

device is switched OFF
while device is switched OFF the rotating part is rotated to a different position.

after switching on the device shall still be able to rotate to the correct and desired position.

To make it even more clear I use numbers for the positions

Let's assume last position to spend a pill was 8.
The Code will store "8" into the eeprom.
After spending the pill device rotates to position 14.
Under normal circumstances when it is time to spend pill at position 9
the device would rotate from position 14 to position 9 which is rotate 9 positions

Now for what reason ever the device is switched off
While device is switched off the rotating part is rotated from position 14 to position 10

Device is switched on again. The code reads from EEPROM last position "8"
then calculating rotate 9 positions to reach position 9
As the device was rotated to position 10 while device was switched off
rotating 9 positions means

If it is time to spend pill from position 9 the device will rotate 9 positions

normal operation under ideal conditions
distance in positions: 0  1  2  3  4  5  6  7  8  9
real position-number: 14, 1, 2, 3, 4, 5, 6, 7, 8, 9

rotated to position 10 while switched OFF
which the code does not know because device was switched OFF
distance in positions: 0  1  2  3  4  5  6  7  8  9
real position-number: 10,11,12,13,14, 1, 2, 3, 4, 5, 6, 7, 8, 9

this means the device would rotate from position 10 to position 5 which ist totally wrong.
as it should be position 9.

And this is the reason why your device needs a reference-point like EACH and EVERY positioning-device has it that shall work high reliably.

If the device performs referencing the closed part-position it will always work.
Even in case the rotating part was misplaced with device switched off.

Sure the space inside is limited.
You should post pictures how the rotating part for the pills looks from looking from underneath and how the lower part of the housing looks like if you have taken away the rotating part.

There are really small sensors that should easily fit inside that can be used for referencing the closed-part-position.

Your knowledge about programming seems to be high improvable.
And yes you should learn quite a bit programming.
Take a look into this tutorial:

Arduino Programming Course

It is easy to understand and has a good mixture between explaining important concepts and example-codes to get you going. So give it a try and report your opinion about this tutorial.

maybe the problem is to understand how a reference-sensor works.

There is some kind of a "mark" on the rotating part.
You start rotating the motor and check hundreds of times per second if the sensor detects the mark.

If sensor detects mark which will make the sensor switch his outputsignal stop motor:
=> now the rotational position is very well known.

After referencing you can rotate with counting the encoder-pulses to any position.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.