Created Fri, 01 Mar 2013 13:48:53 +0000 by alphamike
Fri, 01 Mar 2013 13:48:53 +0000
I have a max32 that I would like to use to read two quadrature encoders (1024 p/r) to relay that information to my robot operation system. Is there any libs that I can use in mpide?
Sun, 03 Mar 2013 06:40:33 +0000
The pontech uav100 code can rwad a single encoder and it should be easily expandable to two.
Search for it on github
Jacob
Wed, 06 Mar 2013 23:50:36 +0000
I looked through the uav100 code but I could not find the part that read an encoder. I have pieced together this code from ones I have found online. The issue I am having is that only one encoder will count up and down. the other will only count up or down, regardless of direction. I know this cod is very unrefined. I am not at all good at writing code. What I am trying to do is read two Quadrature encoders (1024 p/r) and relay that info to the Robot operating system running on my computer. I would be thankful of any help. [code][// Quadrature encoders // Left encoder #define c_LeftEncoderInterrupt 2 #define c_LeftEncoderPinA 20 #define c_LeftEncoderPinB 6 #define LeftEncoderIsReversed volatile bool _LeftEncoderBSet; volatile long _LeftEncoderTicks = 0;
// Right encoder #define c_RightEncoderInterrupt 3 #define c_RightEncoderPinA 21 #define c_RightEncoderPinB 7 volatile bool _RightEncoderBSet; volatile long _RightEncoderTicks = 0;
void setup() { Serial.begin(115200); // Quadrature encoders // Left encoder pinMode(c_LeftEncoderPinA, INPUT); // sets pin A as input pinMode(c_LeftEncoderPinB, INPUT); // sets pin B as input attachInterrupt(c_LeftEncoderInterrupt, HandleLeftMotorInterruptA, RISING);
// Right encoder pinMode(c_RightEncoderPinA, INPUT); // sets pin A as input pinMode(c_RightEncoderPinB, INPUT); // sets pin B as input attachInterrupt(c_RightEncoderInterrupt, HandleRightMotorInterruptA, RISING);
}
void loop() { Serial.print(_LeftEncoderTicks); Serial.print("\t"); Serial.print(_RightEncoderTicks); Serial.print("\n"); delay(20); }
// Interrupt service routines for the left motor's quadrature encoder void HandleLeftMotorInterruptA() { // Test transition; since the interrupt will only fire on 'rising' we don't need to read pin A _LeftEncoderBSet = digitalRead(c_LeftEncoderPinB); // read the input pin
// and adjust counter + if A leads B #ifdef LeftEncoderIsReversed _LeftEncoderTicks -= _LeftEncoderBSet ? -1 : +1; #else _LeftEncoderTicks += _LeftEncoderBSet ? -1 : +1; #endif }
// Interrupt service routines for the right motor's quadrature encoder void HandleRightMotorInterruptA() { // Test transition; since the interrupt will only fire on 'rising' we don't need to read pin A _RightEncoderBSet = digitalRead(c_RightEncoderPinB); // read the input pin
// and adjust counter + if A leads B #ifdef RightEncoderIsReversed _RightEncoderTicks -= _RightEncoderBSet ? -1 : +1; #else _RightEncoderTicks += _RightEncoderBSet ? -1 : +1; #endif }/code]
Thu, 07 Mar 2013 03:53:25 +0000
This code will read one encoder using a pair of interrupts it should be easy to make it read another with a different pair of interrupts. (I could use change Notice pins but that would require direct register addressing like was done on the UAV100)
volatile signed long pos = 0;
volatile char changed = 0;
void setup()
{
Serial.begin(115200);
pinMode(PIN_INT0, INPUT);
pinMode(PIN_INT1, INPUT);
if(digitalRead(PIN_INT0))
attachInterrupt(0, Fall0, FALLING);
else
attachInterrupt(0, Rise0, RISING);
if(digitalRead(PIN_INT1))
attachInterrupt(1, Fall1, FALLING);
else
attachInterrupt(1, Rise1, RISING);
}
void loop()
{
if (changed==1)
{
changed=0;
Serial.println(pos);
}
}
void Rise0()
{
if(digitalRead(PIN_INT1))
pos++;
else
pos--;
changed=1;
attachInterrupt(0, Fall0, FALLING);
}
void Fall0()
{
if(digitalRead(PIN_INT1))
pos--;
else
pos++;
changed=1;
attachInterrupt(0, Rise0, RISING);
}
void Rise1()
{
if(digitalRead(PIN_INT0))
pos--;
else
pos++;
changed=1;
attachInterrupt(1, Fall1, FALLING);
}
void Fall1()
{
if(digitalRead(PIN_INT0))
pos++;
else
pos--;
changed=1;
attachInterrupt(1, Rise1, RISING);
}
Note: You could use only one interrupt and a digital input but then you have half the resolution. You must have both Rising and Falling to keep a accurate count of position unless the encoder only travels in one direction.
Fri, 08 Mar 2013 15:15:21 +0000
So I changed the code to
volatile signed long posleft = 0;
volatile char changedleft = 0;
volatile signed long posright = 0;
volatile char changedright = 0;
void setup()
{
Serial.begin(115200);
pinMode(PIN_INT0, INPUT); //2
pinMode(PIN_INT1, INPUT); //3
pinMode(PIN_INT4, INPUT); //20
pinMode(PIN_INT3, INPUT); //21
// left encoder
if(digitalRead(PIN_INT0))
attachInterrupt(0, Fall0, FALLING);
else
attachInterrupt(0, Rise0, RISING);
if(digitalRead(PIN_INT1))
attachInterrupt(1, Fall1, FALLING);
else
attachInterrupt(1, Rise1, RISING);
// right encoder
if(digitalRead(PIN_INT3))
attachInterrupt(3, Fall3, FALLING);
else
attachInterrupt(3, Rise3, RISING);
if(digitalRead(PIN_INT4))
attachInterrupt(4, Fall4, FALLING);
else
attachInterrupt(4, Rise4, RISING);
}
void loop()
{
// left encoder
if (changedleft==1)
{
changedleft=0;
Serial.print("left ");
Serial.println(posleft);
}
// right encoder
if (changedright==1)
{
changedright=0;
Serial.print("right ");
Serial.println(posright);
}
}
// left encoder
void Rise0()
{
if(digitalRead(PIN_INT1))
posleft++;
else
posleft--;
changedleft=1;
attachInterrupt(0, Fall0, FALLING);
}
// right encoder
void Rise3()
{
if(digitalRead(PIN_INT4))
posright++;
else
posright--;
changedright=1;
attachInterrupt(3, Fall3, FALLING);
}
// left encoder
void Fall0()
{
if(digitalRead(PIN_INT1))
posleft--;
else
posleft++;
changedleft=1;
attachInterrupt(0, Rise0, RISING);
}
// right encoder
void Fall3()
{
if(digitalRead(PIN_INT4))
posright--;
else
posright++;
changedright=1;
attachInterrupt(3, Rise3, RISING);
}
// left encoder
void Rise1()
{
if(digitalRead(PIN_INT0))
posleft--;
else
posleft++;
changedleft=1;
attachInterrupt(1, Fall1, FALLING);
}
// right encoder
void Rise4()
{
if(digitalRead(PIN_INT3))
posright--;
else
posright++;
changedright=1;
attachInterrupt(4, Fall4, FALLING);
}
// left encoder
void Fall1()
{
if(digitalRead(PIN_INT0))
posleft++;
else
posleft--;
changedleft=1;
attachInterrupt(1, Rise1, RISING);
}
// right encoder
void Fall4()
{
if(digitalRead(PIN_INT3))
posright++;
else
posright--;
changedright=1;
attachInterrupt(4, Rise4, RISING);
}
The code will read both my encoders. when i start spinning the motors faster, the serialprint readout starts to skip numbers. it still count up or down correctly, but may skip 10 or 100 counts. Is this because the max 32 cant detect the pulses or is the serial is too slow to update every pulse?
Fri, 08 Mar 2013 16:00:34 +0000
It is the Serial that is slow. You may be having multiple interrupts during the send. This may cause errors in the sent data if the number changes in the middle of sending it (I have not looked at the source code for Serial.print) try copying the value to a different variable before sending it so the value won't change in the middle.
Tue, 12 Mar 2013 01:15:52 +0000
Okay that makes sense. What could I add to the code to output a speed? Like rpm?
Tue, 12 Mar 2013 04:09:33 +0000
The easiest way would be to read one of the timers ReadCoreTimer() returns a 32 bit tick timer value increases at a rate of 40MHz for a 80MHz part. micros(); Returns the number of microseconds since the board began running the current program. In the interrupt average several values together and use that value with the number of counts in one rotation to calculate the velocity.
Don't forget to account for rollover when the values exceed the capacity of the variable and go back to zero.
Note: You need #include <plib.h> to use ReadCoreTimer()