Rotary encoder - counting a 360 degree circle

Greetings,
I'm trying to build a flight simulator controller and I need to control the heading using a rotary encoder.
I tried different bits of code and libraries, but I eventually stuck to the official RotaryEncoder library.
The problem is that I can't figure out how to make it count from 0 to 359, then reset to 0 AND backwards (2, 1, 0, 359, 358 etc).

#include <RotaryEncoder.h>
#define ROTARYSTEPS 1

RotaryEncoder encoder(22,23);
int lastPos = 0;

void setup() {
	Serial.begin(115200);
	Serial.print("Serial started");
}

void loop() {
	encoder.tick();

	int encPos = encoder.getPosition() * ROTARYSTEPS;

	if(lastPos != encPos) {
	if(encPos < 0) encPos = 359;
	else if(encPos > 359) encPos = 0;
	Serial.println(encPos);
	}

	lastPos = encPos;
}

As a comparison, I tried to same thing without the library, just by reading the state of the pins, and although it's pretty innacurate (it only goes every two steps and it's not very precise), I could get it to do what I want.

void CRS() {
	int State = digitalRead(CRS1);
	if(State != CRSLastState) {
		if(digitalRead(CRS2) != State) {
			counter++;
		} else {
			counter--;
		}
		Serial.print("CRS: ");
		if (counter>359) counter = 0;
		else if (counter<0) counter = 359;
		Serial.println(counter);
	}
	CRSLastState = State;
}

Hi,
First you have to establish if your encoder outputs 360 pulses or an integer multiple of that per revolution.

How many counts does your encoder give for 360degrees?
If in the thousands of pulses you may be okay with a non integer multiple.

What model Arduino are you using?
What model encoder?
Does the encoder need pullup or pulldown resistors?

Thanks.. Tom... :slight_smile:

The encoder has 20 steps per revolution. And the value that I want to control is in degrees, so an integer is necessary. Each encoder step has to increment/decrement by 1 degree.
Which is does with the code that I posted. I can even set limits from 0 to 359.

Arduino is Mega 2560, typical no-name blue encoder with pushbutton. I don't think it needs resistors, I believe they're set internally in the Arduino.

Hi,

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

What model encoder?

Thanks.. Tom.. :slight_smile:

There's nothing much to see yet, I've just wired an encoder and a button and wrote the code to see if it works.

"The encoder has 20 steps per revolution. Each encoder step has to increment/decrement by 1 degree."

Do you see the problem here? You won't get 1 degree resolution out of an encoder that moves 360/20 = 18 degrees per 'click'.

Also, why the separate push button? Why not use the one built into the encoder?

The encoder library will have some debounce bulit in (I hope) so that might be why it doesn't work so well without using that library.

Finally, I have to say that the soldering is appaling. You need to practice that or you will get many problems along the project. Solder is not glue. Youtube has videos of how to do it properly.

Hi,
Your encoder does not have enough connections.
You should have;
5V
gnd
Output A
Output B

At the moment you are probably only looking at one output, this will not give you direction information.

Also that encoder may need pullup resistors.
This should help explain.

http://henrysbench.capnfatz.com/henrys-bench/arduino-sensors-and-input/keyes-ky-040-arduino-rotary-encoder-user-manual/

Tom... :slight_smile:

if (counter>359 && counter<1) {counter = 0};

What program do you use to communicate between the arduino and the simulator?

BuzziBi:

if (counter>359 && counter<1) {counter = 0};

How can this work? A counter cannot be more than 359 AND less than 1 at the same time!
Maybe an OR would be better in here?

You are right! The brain took a wrong turn. :slight_smile:
The trap must be like this:

if (compass>359 && compass==360) {compass = 0;}; 
  if (compass<0) {compass = 359;};

BuzziBi:
You are right! The brain took a wrong turn. :slight_smile:
The trap must be like this:

if (compass>359 && compass==360) {compass = 0;}; 

if (compass<0) {compass = 359;};

Almost.

But what if the encoder took 2 steps in between you reading it? You will lose steps. Try this instead....

while (compass>=360) {compass -= 360;}; 
  while (compass<0) {compass += 360;};

The photo looks OK to me. 3 connections to the encoder is OK. Soldering looks OK. But I would not use solid wire in the final version. Buy some stranded hookup wire.

Thumbs up!

if (compass>359 || compass<0) {compass = 0;};

skywatch:

if (compass>359 || compass<0) {compass = 0;};

So how do you go left from 0 degrees?

You can use an offset and modulo to keep it in the 0-259 range.

Example (if compass not is less than -360):

compass = (compass + 360) % 360

Also, why the separate push button? Why not use the one built into the encoder?

The final project will use both the pushbutton from the encoders and some of those separate pushbuttons.
For the moment, I'm just testing them.

Finally, I have to say that the soldering is appaling. You need to practice that or you will get many problems along the project. Solder is not glue. Youtube has videos of how to do it properly.

I've been working with electronics for many years, that's just some quick, crap soldering I've done in some free time at work with a cheap soldering iron. The final project will have proper connections and wiring.
Coding however is not my strenght...

Also that encoder may need pullup resistors.
This should help explain.

The board has internal pullup resistors, which I've set in code. The encoder works by pulling down the two side pins to the middle pin (which is ground).
I also added some capacitors to debounce the encoder.

What program do you use to communicate between the arduino and the simulator?

I will probably go with extplane via ethernet, but we'll see.

I'll try the code suggested and come back with results.