Saving rotary encoder data for next power up

I am relatively new to Arduino, and am wondering if someone could help me store rotary encoder data so that the angular position is always initialized correctly. I am using it for a robot I am building for a course in mechanical engineering, and need it to confirm crank angular displacement. I did see some examples, but they are over my head. As shown in the pic, I originally tried using a prox switch to initialize the encoder count but found some examples using "EEPROM" that I am unable to figure out at the moment.
image

My code below:
(the value I'm trying to store is "encoderPosCount")

//prox 
const int proxPin=11;
//update prox value every 10 ms
const unsigned long eventTimeProx=5;
unsigned long previousTime1=0;
int proxState=0;
int intitialProxPresses=0;
int totalProxPresses=0;
int PreviousProxState=0;
 
 //encoder
  int pinA = A5; // Connected to CLK on KY-040
  int pinB = A4; // Connected to DT on KY-040
  int encoderPosCount = 0;
  int pinALast;
  int aVal;
  boolean bCW;

// dc motor pins
  const int enable1=10;
  const int in2=7;
  const int ref_high=4;
  const int in1=8;

// servo pins
  const int ref_high2=12;

  const int in1_a=6;
  const int in2_a=9;
  const int enable1_a=5;

  const int in1_b=13;
  const int in2_b=2;
  const int enable1_b=3;

//SOLENOID PINS
  //power
  const int sol_actuate=A2;

void walkStraight() {
  digitalWrite(ref_high, HIGH);
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  analogWrite(enable1, 120);
}
void stopWalking() {
  digitalWrite(ref_high, HIGH);
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  analogWrite(enable1, 0);
}
void solenoidsDown() {
  digitalWrite(sol_actuate,LOW);
}
void solenoidsUp() {
  digitalWrite(sol_actuate,HIGH);
}
void turnRight() {
    analogWrite(enable1_a,0);
    digitalWrite(in1_a,LOW);
    digitalWrite(in2_a,HIGH);
}
void turnLeft() {
    analogWrite(enable1_a,255);
    digitalWrite(in1_a,HIGH);
    digitalWrite(in2_a,LOW);
}

void setup() {
  // put your setup code here, to run once:
  //SOLENOIDS
  pinMode(sol_actuate,OUTPUT);
  //Solenoid relay power supply
  digitalWrite(sol_actuate,HIGH);

  //prox
  pinMode(proxPin,INPUT);
  Serial.begin (9600);

  //encoder
  pinMode (pinA,INPUT);
  pinMode (pinB,INPUT);
  pinALast = digitalRead(pinA);

  //dc motor
  pinMode(enable1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(ref_high, OUTPUT);
  pinMode(in1, OUTPUT);

  //servo
  pinMode(ref_high2, OUTPUT);
  
  pinMode(in1_a,OUTPUT);
  pinMode(in2_a,OUTPUT);
  pinMode(enable1_a,OUTPUT);
  
  pinMode(in1_b,OUTPUT);
  pinMode(in2_b,OUTPUT);
  pinMode(enable1_b,OUTPUT);
//servo power supply
  digitalWrite(in1_b,LOW);
  digitalWrite(in2_b,HIGH); 
  analogWrite(enable1_b,255);
  digitalWrite(ref_high2, HIGH);
// initial servo state (on startup)
  delay(2000);
}

bool bool1=0;
bool bool2=0;


int triggerTime1=0;
int triggerTime2=0;



unsigned long msecLast;
enum { Idle, Stop, Straight, TurnRight,TurnLeft,walkAgain };
int state = Straight;
void loop() {
  unsigned long currentTime=millis();

  if(currentTime-previousTime1>=eventTimeProx) {
    proxState=digitalRead(proxPin);
    previousTime1=currentTime;
    if (proxState != PreviousProxState) {
      if (proxState==HIGH) {
        totalProxPresses++;
        Serial.println(totalProxPresses);
  }     PreviousProxState=proxState;
    }
  }
  // start encoder count when prox switch trips "totalProxPresses" number of times
  if (totalProxPresses>=10) {
    //ENCODER READINGS
      aVal = digitalRead(pinA);
      if (aVal != pinALast){ // Means the knob is rotating
      // if the knob is rotating, we need to determine direction
      // We do that by reading pin B.
      if (digitalRead(pinB) != aVal) { // Means pin A Changed first - We're Rotating Clockwise
      encoderPosCount ++;
      bCW = true;
      } else {// Otherwise B changed first and we're moving CCW
      bCW = false;
      encoderPosCount--;
      }
      Serial.print ("Rotated: ");
      if (bCW){
      Serial.println ("clockwise");
      }else{
      Serial.println("counterclockwise");
      }
      Serial.print("Encoder Position: ");
      Serial.println(encoderPosCount);
      }
      pinALast = aVal;
  }
  

if ((encoderPosCount<=15) && (bool1==0)){
  walkStraight();
}
if  ((encoderPosCount>=15)&&(bool1==0))  {
  bool1=1;
  stopWalking();
  triggerTime1=currentTime;
}

if ((currentTime-triggerTime1>2000)&&(bool1==1)){
  solenoidsDown();
  bool2=1;
}
if ((currentTime-triggerTime1>2500)&&(bool1==1)){
  turnLeft();
}
if ((currentTime-triggerTime1>5000)&&(bool2==1)){
  solenoidsUp();
}
if ((currentTime-triggerTime1>5500)&&(bool2==1)){
  walkStraight();
}
if (totalProxPresses>20){
  stopWalking();
}

}

have a look at how-to-get-the-best-out-of-this-forum
in particular what microcontroller are you using?

1 Like

Arduino Uno

try a web search for uno eeprom you will get plenty of links
be carful how often you update - EEPROM has a limited number of writes
you may be better off installing a FRAM

"Save Position of rotary Encoder" is somthing you better think over again.

1 Like

you could try enabling Brown Out detection (web search for uno brown out) - when supply volatge falls below some threshold an interrupt service routine is called which saves critical parameters to EEPROM - this assumes the power is retained for sufficent time to run the interrupt code

Suppose a service man has been taking the system apart and assembles it into another position. Assuming "nothing changed" at start up will make a robot useless, or even dangerous. Self check and initilization is basic parts in automation.

There will be nothing to prevent the robot's parts to move while switched off.

Upon startup, have the robot stretch their legs and use sensors to find their position, and possibly go back to the position it was on startup. That's the normal way of doing this, for good reason: it's the only way to know for sure what your position is.

in a system using an oscillating table which on power loss could be in any position I used a magnet attached to the table
on powerup table was rotated clockwise until a hall effect switch detected the magnet

This question is only relevant if an incremental encoder is used (sometimes a servomotor is fitted with an absolute encoder but runs multiple revolutions during movement, resulting in the same problem).

If you want to accommodate for movement after power failure AND not doing a homing movement, you need an absolute encoder on the position.

This probably means mechanical alteration of your robot to fit that.

Ok, I see that this will work for my application.
I found one online that I think will work:
https://api.pim.na.industrial.panasonic.com/file_stream/main/fileversion/2630

I don't know what communication protocol this utilizes (there is no documentation that I can find online). Should I get this? I'm afraid when it comes in I will probably not know how to read the angular positions with the Arduino UNO.

looks similar to arduino-rotary-encoder would it be sufficiently accurate for your application?
for protocol have a web search for grey code rotary encoder

1 Like

The link you sent is for an incremental encoder. For the Panasonic module I found, this is the schematic on the website:
image

Based on this, it looks like it would just output a voltage signal from 0-5V corresponding to the position, sort of like how a potentiometer would??

It's indicating that an oscilloscope is the instrument being used to visualize the signal.

Note in the specs.:

Ok so Arduino would not work for this? I would think it outputs some sort of bit combination using a communication protocol that I could download online for Arduino. There are only 16 positions for this Panasonic one.

It is simply a set of four switches; four inputs needed on the Arduino. The H/L pattern on the pins is the binary value of the position the encoder is in.

You have 16 positions maximum, with detents (so the encoder wants to click in place; you will feel resistance when turning it between positions). This means you have steps of 360/16 = 22.5°. That's the resolution you're going to get with these encoders. Your actual position is somewhere within that 22.5° margin.

1 Like

Oh ok. That is easy then. I'm sure I can find a code somewhere to interpret that data. Thanks for the help.

Easy peasy.  Make a sixteen position array and populate it with the binary equivalent of the gray code.  Use the gray code as the index into the array.

1 Like

Ok, I am a beginner at this as you can probably already tell.
So I know how to get my boolean values from the 4 input pins, but how do I combine these digitalreads into a 4 bit binary number, and then index an array with the elements of the below combinations? I would think the index is just an integer, not a 4-bit number.

image

Easiest is if you're clever about how to connect it and have the inputs connected to four pins that are in the same port, ideally bits 0-3. E.g. pin 8-11, which are PB0-PB3. Then it's a single line of code to read them all:

int position = PORTB & 0b00001111;

Depending on the inputs position will now contain a value 0-15.

The bitmask is to ignore PB4-PB7 (Arduino pins 12 and 13 and the crystal input)

1 Like