Hey All,
this is my first post here, and it´s all about incremental rotary encoder (quadrature encoded ).
I read a lot in the forums about the highest tick frequency one can handle with an Arduino and interrupts and how to increase the speed of my program.
My setup consists of an Arduino Mega and a high-res (500 PPR) incremental encoder.
On the software side I use the highspeed encoder library found here:Encoder Library, for Measuring Quadarature Encoded Position or Rotation Signals
Since I wanna connect four rotary encoders and I don't need the 4x counting support of the library, I connect the A-Output to an Interrupt Input and the B-Output to a normal Digital-Input. (a little slower as connecting both to interrupts)
So far so good. When testing this setup with one encoder connected and turning by hand as fast as I can( I don't need real high RPM ) it works as expected.
Since I just have on encoder and I wanna test the other inputs, I connected A and B outputs also to the second pair of inputs, so using the same encoder on two input pairs. If I do this and turn it fast and abruptly by hand the two tick counts in the software differ.
Since I don't believe the Arduino is to slow I thought one of the followings could be the case:
- Since the two input interrupts get triggered at the same moment I miss one every time. This wouldn't be the case if I would use two separate encoders, since the chance is pretty small they are triggered at the exact same time (withing µs) ?
- The problem is that the encoder can't handle multiple outputs at the same time. Maybe something todo with the voltage ?
Can anyone give me tips on handing multiple encoder ?
Attached is the full code with all four encoders and also sending the data over the network every 100ms.
REF_BUTTONS and max_steps is used to synchronize with an external reed switch.
/*
Name: SensorApp.ino
Created: 10/6/2017 5:19:25 PM
Author: Patrick Fuerst
*/
//#define ENCODER_OPTIMIZE_INTERRUPTS
//#define ENCODER_DO_NOT_USE_INTERRUPTS
#include <Encoder.h>
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
#include <SPI.h>
#include <Ethernet.h>
#include "Arduino.h"
#include <digitalWriteFast.h>
//#define DEBUG
#define REF_BUTTON1_PIN 22 //I00
#define REF_BUTTON2_PIN 23 //I01
#define REF_BUTTON3_PIN 24 //I02
#define REF_BUTTON4_PIN 25 //I03
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip_remote(192, 168, 1, 255);
IPAddress ip (192, 168, 1, 211);
// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
unsigned int remote_port = 8888; // local port to listen on
unsigned int local_port = 8888; // local port to listen on
char ReplyBuffer[] = "acknowledged\n"; // a string to send back
#define ENCODER_ONE_PIN_A 21
#define ENCODER_ONE_PIN_B 17
#define ENCODER_TWO_PIN_A 20
#define ENCODER_TWO_PIN_B 15
#define ENCODER_THREE_PIN_A 19
#define ENCODER_THREE_PIN_B 14
#define ENCODER_FOUR_PIN_A 18
#define ENCODER_FOUR_PIN_B 3
Encoder enc_one(ENCODER_ONE_PIN_A, ENCODER_ONE_PIN_B);
Encoder enc_two(ENCODER_TWO_PIN_A,ENCODER_TWO_PIN_B);
Encoder enc_three(ENCODER_THREE_PIN_A,ENCODER_THREE_PIN_B);
Encoder enc_four(ENCODER_FOUR_PIN_A, ENCODER_FOUR_PIN_B);
unsigned long last_time_send = 0;
Encoder* encoders[] = {&enc_one, &enc_two, &enc_three, &enc_four};
bool button_state[] = {false,false,false,false};
long oldPosition[] = {-1,-1,-1,-1};
long newPosition[] = {0,0,0,0};
// used to normalize the values
// max position gets written when we write zero to the encoder position
long max_steps[] = {0,0,0,0};
// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(2000000);
Serial.println("Basic Encoder Test:");
pinMode(REF_BUTTON1_PIN, INPUT);
pinMode(REF_BUTTON2_PIN, INPUT);
pinMode(REF_BUTTON3_PIN, INPUT);
pinMode(REF_BUTTON4_PIN, INPUT);
// start the Ethernet connection:
Serial.println("Trying to get an IP address using DHCP");
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
// initialize the Ethernet device not using DHCP:
Ethernet.begin(mac, ip);
}
// print your local IP address:
Serial.print("My IP address: ");
ip = Ethernet.localIP();
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(ip[thisByte], DEC);
Serial.print(".");
}
Serial.println();
Udp.begin(local_port);
}
// the loop function runs over and over again until power down or reset
void loop() {
newPosition[0] = enc_one.read();
newPosition[1] = enc_two.read();
newPosition[2] = enc_three.read();
newPosition[3] = enc_four.read();
button_state[0] = (boolean)digitalReadFast(REF_BUTTON1_PIN);
button_state[1] = button_state[0];
button_state[2] = button_state[0];
button_state[3] = button_state[0];
// whenever we get a ref signal we put the position back to zero
for(int i=0; i<4; i++){
if ( button_state[i]) {
encoders[i]->write(0);
if(abs(newPosition[i]) > max_steps[i])
max_steps[i] = abs(newPosition[i]);
}
}
#ifdef DEBUG
for(int i=0; i<4; i++){
if (newPosition[i] != oldPosition[i]) {
oldPosition[i] = newPosition[i];
Serial.print("Sensor:");
Serial.print(i);
Serial.print(" ");
Serial.println(360*newPosition[i]/max_steps[i]);
}
}
if(button_state[0]){
Serial.println("REF");
}
#endif
int normalized_position[4];
if( millis() - last_time_send > 100){
for(int i=0; i<4; i++){
normalized_position[i] = 360*newPosition[i]/max_steps[i];
}
// send a reply to the IP address and port that sent us the packet we received
Udp.beginPacket(ip_remote,remote_port);
Udp.write((char*)&normalized_position, sizeof(int)*4);
Udp.endPacket();
last_time_send = millis();
}
}