How can I set variable increments for a rotary encoder?"

Hi guys,, I want to use a rotary encoder with a selected range (for example, from 0 to 200) with varying increments. I came across an example from Matthias Hertel's library (RotaryEncoder-LimitedRotator) that I would like to upgrade by changing the increment from a certain value, but I haven't been able to achieve that.
For example, I would like my value to increment by 0.1 between 0 and 10, then by 0.5 between 10 and 20, and then by 1 from 20 to 200.
Do you have any solutions to propose?
Below is the code that I would like to upgrade.
// LimitedRotator.ino - Example for the RotaryEncoder library.
// This class is implemented for use with the Arduino environment.
//
// Copyright (c) by Matthias Hertel, http://www.mathertel.de
// This work is licensed under a BSD 3-Clause License. See http://www.mathertel.de/License.aspx
// More information on: http://www.mathertel.de/Arduino
// -----
// 26.03.2017 created by Matthias Hertel
// 06.02.2021 conditions and settings added for ESP8266
// -----

// This example checks the state of the rotary encoder in the loop() function.
// The current position is printed on output when changed.
// In addition to the SimplePollRotator example here the range of the rotator is limited to the range 0 - 16 and only incremental steps of 2 are realized.
// To implement this limit the boundaries are checked and eventually the current position is adjusted.
// The internal (physical) position of the rotary encoder library remains by stepping with the increment 1
// so the logical position is calculated by applying the ROTARYSTEPS factor.
// LimitedRotator.ino - Example for the RotaryEncoder library.
// This class is implemented for use with the Arduino environment.
//
// Copyright (c) by Matthias Hertel, http://www.mathertel.de
// This work is licensed under a BSD 3-Clause License. See http://www.mathertel.de/License.aspx
// More information on: http://www.mathertel.de/Arduino
// -----
// 26.03.2017 created by Matthias Hertel
// 06.02.2021 conditions and settings added for ESP8266
// -----

// This example checks the state of the rotary encoder in the loop() function.
// The current position is printed on output when changed.
// In addition to the SimplePollRotator example here the range of the rotator is limited to the range 0 - 16 and only incremental steps of 2 are realized.
// To implement this limit the boundaries are checked and eventually the current position is adjusted.
// The internal (physical) position of the rotary encoder library remains by stepping with the increment 1
// so the logical position is calculated by applying the ROTARYSTEPS factor.
Solution:
Yh @M M sure that the dynamic increment function actually addresses the issue . We might also want to optimize the getIncrement function by using a single if- else if chain or a switch statement for better readability and performance, especially if the range of increments becomes more complex tho...
Jump to solution
7 Replies
Camila_99$$
Camila_99$$4w ago
// Hardware setup:
// Attach a rotary encoder with output pins to A2 and A3.
// The common contact should be attached to ground.

#include <Arduino.h>
#include <RotaryEncoder.h>

// Example for Arduino UNO with input signals on pin 2 and 3
#define PIN_IN1 4
#define PIN_IN2 3

#define ROTARYSTEPS 0.1
#define ROTARYMIN 0
#define ROTARYMAX 200

// Setup a RotaryEncoder with 4 steps per latch for the 2 signal input pins:
// RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);

// Setup a RotaryEncoder with 2 steps per latch for the 2 signal input pins:
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

// Last known rotary position.
float lastPos = -1;

void setup()
{
Serial.begin(115200);
while (! Serial);
Serial.println("LimitedRotator example for the RotaryEncoder library.");
encoder.setPosition(10 / ROTARYSTEPS); // start with the value of 10.
} // setup()

// Read the current position of the encoder and print out when changed.
void loop()
{
encoder.tick();

// get the current physical position and calculate the logical position
float newPos = encoder.getPosition() * ROTARYSTEPS;

if (newPos < ROTARYMIN) {
encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
newPos = ROTARYMIN;

} else if (newPos > ROTARYMAX) {
encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
newPos = ROTARYMAX;
} // if

if (lastPos != newPos) {
Serial.print(newPos);
Serial.println();
lastPos = newPos;
} // if
} // loop ()

// The End
// Hardware setup:
// Attach a rotary encoder with output pins to A2 and A3.
// The common contact should be attached to ground.

#include <Arduino.h>
#include <RotaryEncoder.h>

// Example for Arduino UNO with input signals on pin 2 and 3
#define PIN_IN1 4
#define PIN_IN2 3

#define ROTARYSTEPS 0.1
#define ROTARYMIN 0
#define ROTARYMAX 200

// Setup a RotaryEncoder with 4 steps per latch for the 2 signal input pins:
// RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);

// Setup a RotaryEncoder with 2 steps per latch for the 2 signal input pins:
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

// Last known rotary position.
float lastPos = -1;

void setup()
{
Serial.begin(115200);
while (! Serial);
Serial.println("LimitedRotator example for the RotaryEncoder library.");
encoder.setPosition(10 / ROTARYSTEPS); // start with the value of 10.
} // setup()

// Read the current position of the encoder and print out when changed.
void loop()
{
encoder.tick();

// get the current physical position and calculate the logical position
float newPos = encoder.getPosition() * ROTARYSTEPS;

if (newPos < ROTARYMIN) {
encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
newPos = ROTARYMIN;

} else if (newPos > ROTARYMAX) {
encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
newPos = ROTARYMAX;
} // if

if (lastPos != newPos) {
Serial.print(newPos);
Serial.println();
lastPos = newPos;
} // if
} // loop ()

// The End
M M
M M4w ago
Hi @Camila_99$$ , I checked your code and you need to add and modify in any part. add a function to adjust the increment dynamically base on the position. float getIncrement(float pos) { if (pos >= 0 && pos < 10) { return 0.1; } else if (pos >= 10 && pos < 20) { return 0.5; } else { return 1.0; } } then update the position in the loop.
Solution
Marvee Amasi
Marvee Amasi4w ago
Yh @M M sure that the dynamic increment function actually addresses the issue . We might also want to optimize the getIncrement function by using a single if- else if chain or a switch statement for better readability and performance, especially if the range of increments becomes more complex tho
Marvee Amasi
Marvee Amasi4w ago
float getIncrement(float pos) {
switch ((int)pos) { // Cast to int for range comparison
case 0 ... 9:
return 0.1;
case 10 ... 19:
return 0.5;
default:
return 1.0;
}
}
float getIncrement(float pos) {
switch ((int)pos) { // Cast to int for range comparison
case 0 ... 9:
return 0.1;
case 10 ... 19:
return 0.5;
default:
return 1.0;
}
}
M M
M M4w ago
Good suggestion! The switch statement with range comparison definitely improves readability and performance. But, the range-based case (case 0 ... 9) is a GCC extension and may not be supported on all compilers or platforms.
Camila_99$$
Camila_99$$4w ago
Hi @M M @Marvee Amasi ,
Thanks for the insights! I’m leaning towards using a switch statement for improved readability. However, considering the compatibility issue with range-based cases, I’ll explore alternative approaches that ensure broader support. Maybe we could look into structuring ranges with separate cases or using a different method to maintain compatibility? What do you think?
M M
M M4w ago
yes, right! Using a switch would definitely improve readability, but ensuring compatibility is important. One way to handle this is to break down the range logic into discrete cases, but that could still get cumbersome as the ranges grow. An alternative could be using a simple array or struct to map position ranges to increments. This would make it easier to extend or adjust the ranges without affecting performance. struct Range { float min; float max; float increment; }; Range ranges[] = { {0, 10, 0.1}, {10, 20, 0.5}, {20, 200, 1.0} }; float getIncrement(float pos) { for (Range range : ranges) { if (pos >= range.min && pos < range.max) { return range.increment; } } return 1.0; // default case }
Want results from more Discord servers?
Add your server