I have been loosely following Articulated Robotics' series on ROS and decided to use his ros_arduino_bridge code to drive my motors over serial to my Arduino Mega 2560 from ROS2. Anyways my robot uses 4-wheel mecanum drive, so the code does need modification.
Everything seems simple enough to change except the encoder code as it utilizes concepts of the Arduino I am not familiar with. I have learnt some since but not 100%. Below are all the main bits I believe to pertain to the encoder code.
In Setup:
void setup() {
...
//set as inputs
DDRD &= ~(1<<LEFT_ENC_PIN_A);
DDRD &= ~(1<<LEFT_ENC_PIN_B);
DDRC &= ~(1<<RIGHT_ENC_PIN_A);
DDRC &= ~(1<<RIGHT_ENC_PIN_B);
//enable pull up resistors
PORTD |= (1<<LEFT_ENC_PIN_A);
PORTD |= (1<<LEFT_ENC_PIN_B);
PORTC |= (1<<RIGHT_ENC_PIN_A);
PORTC |= (1<<RIGHT_ENC_PIN_B);
// tell pin change mask to listen to left encoder pins
PCMSK2 |= (1 << LEFT_ENC_PIN_A)|(1 << LEFT_ENC_PIN_B);
// tell pin change mask to listen to right encoder pins
PCMSK1 |= (1 << RIGHT_ENC_PIN_A)|(1 << RIGHT_ENC_PIN_B);
// enable PCINT1 and PCINT2 interrupt in the general interrupt mask
PCICR |= (1 << PCIE1) | (1 << PCIE2);
...
}
In econder_driver.h:
...
//below can be changed, but should be PORTD pins;
//otherwise additional changes in the code are required
#define LEFT_ENC_PIN_A PD2 //pin 2
#define LEFT_ENC_PIN_B PD3 //pin 3
//below can be changed, but should be PORTC pins
#define RIGHT_ENC_PIN_A PC4 //pin A4
#define RIGHT_ENC_PIN_B PC5 //pin A5
...
In encoder_driver.ino:
volatile long left_enc_pos = 0L;
volatile long right_enc_pos = 0L;
static const int8_t ENC_STATES [] = {0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0}; //encoder lookup table
/* Interrupt routine for LEFT encoder, taking care of actual counting */
ISR (PCINT2_vect){
static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PIND & (3 << 2)) >> 2; //read the current state into lowest 2 bits
left_enc_pos += ENC_STATES[(enc_last & 0x0f)];
}
/* Interrupt routine for RIGHT encoder, taking care of actual counting */
ISR (PCINT1_vect){
static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PINC & (3 << 4)) >> 4; //read the current state into lowest 2 bits
right_enc_pos += ENC_STATES[(enc_last & 0x0f)];
}
/* Wrap the encoder reading function */
long readEncoder(int i) {
if (i == LEFT) return left_enc_pos;
else return right_enc_pos;
}
...
I did the monkey brain tactic of just adding two more DDRB and DDRA, and PORTB and PORTA assignments for two other motors and adding two more ICR functions. I am not quite sure on how to do the bit mask and shifting and stuff tho for the functions. Although from what I gathered the Mega might not even have enough interrupt pins for 4 motors. Sadly I cannot actually test this with the actual motors which is an interesting problem right now, so I am hoping someone can help me out all the same.
The
ros_arduino_bridgeis mainly codded for theArduino Uno Atmega328pand you can see that from the pins selected and their correspondingPCINT.ATmega328Pmicrocontroller has three Pin Change Interrupt vectors:There are a total of 24 pins on the
ATmega328Pthat can trigger pin change interrupts, but they are grouped into these three vectors. You should like the Arduino uno pin out to understand more.You can always configure more than one pair of pins to trigger encoder changes. it doesn't have to be
PD2andPD3for example only handled byPCINT2_vect. You can handle other pins in there.So here is what you can do if you are using Arduino Uno. You can use
PCINT0-3which is grouped inPCINT0_vectand cross pond to pinsPB0-4(pins 8-11 on the uno headers) and connect your two news encoders. (ofc assuming they are not used - if they are you get the concept and can find others).to set them up
and the ISR can be something like this
if you want to use the Arduino Mega you would have to configure the pins and the
PINCT#_Vectused for all 4 encoders. existing ones and new ones as well. you can look at the mega pinout diagrams and easily figure out the numbers. ThePCINTsare grouped in the Arduino Mega similar to theUNOjust map to differentPORTsand PIN numbers