Log in

View Full Version : Issues with encoder code


jgannon
26-03-2006, 12:01
My team has been using Kevin Watson's encoder code in conjunction with the KOP gear tooth sensors, to great success. Unfortunately, during one of our last matches, the wires got yanked off of the RC, and broke the signal pin on digital IO 1. Fortunately, this is not a huge deal, so we got the broken pin out of the cable, and moved the encoders over to digital IO 3 and 4. Now, when I run the code, encoders 3 and 4 start out at 0. If I spin one side of the drivetrain, the count for that side increases to 1, and no more. I have the same problem if I try IO 5 or 6. I know that the sensors are still working fine, because if I move one back to IO 2, then I get the expected counts. Has anyone else run into trouble with using encoders on 3-6? Any suggestions? I'm hoping we'll be able to have a working autonomous mode again in Atlanta.

The Lucas
26-03-2006, 12:12
Could you post your InterruptHandlerLow code? As I remember it took a little work to get those "Port B" interrupts working.

jgannon
26-03-2006, 12:18
Could you post your InterruptHandlerLow code? As I remember it took a little work to get those "Port B" interrupts working.
I'm not sure if it is in violation of Kevin's license agreement to post this, so let me know if it is, and I'll take it down post haste. Anyway, this is what I've got:
void InterruptHandlerLow ()
{
unsigned char Port_B;
unsigned char Port_B_Delta;

if (PIR1bits.RC1IF && PIE1bits.RC1IE) // rx1 interrupt?
{
#ifdef ENABLE_SERIAL_PORT_ONE_RX
Rx_1_Int_Handler(); // call the rx1 interrupt handler (in serial_ports.c)
#endif
}
else if (PIR3bits.RC2IF && PIE3bits.RC2IE) // rx2 interrupt?
{
#ifdef ENABLE_SERIAL_PORT_TWO_RX
Rx_2_Int_Handler(); // call the rx2 interrupt handler (in serial_ports.c)
#endif
}
else if (PIR1bits.TX1IF && PIE1bits.TX1IE) // tx1 interrupt?
{
#ifdef ENABLE_SERIAL_PORT_ONE_TX
Tx_1_Int_Handler(); // call the tx1 interrupt handler (in serial_ports.c)
#endif
}
else if (PIR3bits.TX2IF && PIE3bits.TX2IE) // tx2 interrupt?
{
#ifdef ENABLE_SERIAL_PORT_TWO_TX
Tx_2_Int_Handler(); // call the tx2 interrupt handler (in serial_ports.c)
#endif
}
else if (INTCON3bits.INT2IF && INTCON3bits.INT2IE) // encoder 1 interrupt?
{
INTCON3bits.INT2IF = 0; // clear the interrupt flag
#ifdef ENABLE_ENCODER_1
Encoder_1_Int_Handler(); // call the left encoder interrupt handler (in encoder.c)
#endif
}
else if (INTCON3bits.INT3IF && INTCON3bits.INT3IE) // encoder 2 interrupt?
{
INTCON3bits.INT3IF = 0; // clear the interrupt flag
#ifdef ENABLE_ENCODER_2
Encoder_2_Int_Handler(); // call right encoder interrupt handler (in encoder.c)
#endif
}
else if (INTCONbits.RBIF && INTCONbits.RBIE) // encoder 3-6 interrupt?
{
Port_B = PORTB; // remove the "mismatch condition" by reading port b
INTCONbits.RBIF = 0; // clear the interrupt flag
Port_B_Delta = Port_B ^ Old_Port_B; // determine which bits have changed
Old_Port_B = Port_B; // save a copy of port b for next time around

if(Port_B_Delta & 0x10) // did external interrupt 3 change state?
{
#ifdef ENABLE_ENCODER_3
Encoder_3_Int_Handler(Port_B & 0x10 ? 1 : 0); // call the encoder 3 interrupt handler (in encoder.c)
#endif
}
if(Port_B_Delta & 0x20) // did external interrupt 4 change state?
{
#ifdef ENABLE_ENCODER_4
Encoder_4_Int_Handler(Port_B & 0x20 ? 1 : 0); // call the encoder 4 interrupt handler (in encoder.c)
#endif
}
if(Port_B_Delta & 0x40) // did external interrupt 5 change state?
{
#ifdef ENABLE_ENCODER_5
Encoder_5_Int_Handler(Port_B & 0x40 ? 1 : 0); // call the encoder 5 interrupt handler (in encoder.c)
#endif
}
if(Port_B_Delta & 0x80) // did external interrupt 6 change state?
{
#ifdef ENABLE_ENCODER_6
Encoder_6_Int_Handler(Port_B & 0x80 ? 1 : 0); // call the encoder 6 interrupt handler (in encoder.c)
#endif
}
}


// *** IFI Code Starts Here***
//
// unsigned char int_byte;
// if (INTCON3bits.INT2IF && INTCON3bits.INT2IE) /* The INT2 pin is RB2/DIG I/O 1. */
// {
// INTCON3bits.INT2IF = 0;
// }
// else if (INTCON3bits.INT3IF && INTCON3bits.INT3IE) /* The INT3 pin is RB3/DIG I/O 2. */
// {
// INTCON3bits.INT3IF = 0;
// }
// else if (INTCONbits.RBIF && INTCONbits.RBIE) /* DIG I/O 3-6 (RB4, RB5, RB6, or RB7) changed. */
// {
// int_byte = PORTB; /* You must read or write to PORTB */
// INTCONbits.RBIF = 0; /* and clear the interrupt flag */
// } /* to clear the interrupt condition. */
// else
// {
// CheckUartInts(); /* For Dynamic Debug Tool or buffered printf features. */
// }
}

The Lucas
26-03-2006, 13:46
Here are a couple things (differences with my code) to try :

Try declaring Old_Port_B like this:
unsigned char Port_B;
unsigned char Port_B_Delta;
static unsigned Old_Port_B = 0xFF;


Try spliting your handler into separate rise and fall handlers like so:
if (Port_B & 0x10) Int_3Rise_Handler();
else Int_3Fall_Handler();

Double check that you set INTCONbits.RBIE in initialization
Those are the only differences between my handler (2 encoders & 3 GTS) and your handler. We changed it last year and I don't remember exactly what fixed what.

jgannon
26-03-2006, 13:59
Try declaring Old_Port_B like this:
unsigned char Port_B;
unsigned char Port_B_Delta;
static unsigned Old_Port_B = 0xFF;

Hm... looking at the code, that seems to be a really important thing to do. I'll give it a try in Atlanta, and let you know what happens. Thanks!

Mike
26-03-2006, 14:32
I also remember that his code is defaultly optimized for velocity readings on ports 1 and 2 and optimized for position control on ports 3 and 4. I might be wrong with the numbers, but different ports are optimized for different purposes. Check if your new ports were optimized for a purpose other than your old ports where.

Kevin Sevcik
26-03-2006, 14:53
Mike,
It occurs to me that you've hit the nail on the head. 3 and 4 are opitmized for positions, so they're expecting a quadrature encoder. They look for the B channel on another set of pins (can't remember which) and they will only increment properly if the cycle goes A rise, B rise, A fall, B fall. If B stays high or low, then the code thinks the encoder is fiddling back and forth and not actually turning. There should be a way to fix this in the code, but I don't have it in front of me. That's exactly what the problem is, however.

JG,
Check Kevin's readme and code comments. They should tell you how to use those inputs for velocity instead of position.

Kevin Watson
26-03-2006, 15:12
I'm not sure if it is in violation of Kevin's license agreement to post this, so let me know if it is, and I'll take it down post haste.I guess I should explain why I don't want entire copies of my code available elsewhere on the 'net. Two years ago, I posted some code that was later modified and posted on a team's website (team A). Another team (Team B) used the modified version of the code on their robot, but had problems because the modified code had a bug introduced by team A. Team B e-mailed me and said that my code didn't work for them and asked if could I help find the bug. Well, this was during the 2004 six week build period and I was at work when I got the e-mail. Not seeing how the bug could possibly happen and worried that many teams were having the same problem, I left work early so that I could go home and try to reproduce the bug on a real controller. Well, after a few frustrating hours trying to reproduce the bug, I found out that Team B used Team A's modified code, where the bug was found. The point I'm trying to make is that it's much easier for me (and others here on CD) to help diagnose problems if I know that the team started with a build that I know works on my hardware.

-Kevin