MD49 and Arduino: Get Encoder Issues

I am using the 24V Devantech motor set, that comes with the Devantech MD49 motor controller. I am using the tx and rx of an Arduino uno to send control signals/receive information to/from the MD49.

I am trying to use the encoders to move the motors a specific distance, however my code is acting buggy and I’m not sure exactly how to solve it. Basically, I am sending the get encoder signal, reading the 4 byte response, and bit shifting to obtain a 32 bit integer result, just like the specification recommends. You may find my least buggy version of the code below: (Note, I have stripped the code of everything but the encoder reading functionality, to focus on the issue)

#define CMD          (byte)0x00 
#define GET_ENC1     0x23
#define ENC_RESET    0x35

// reads the value of encoder 1 into an unsigned 32 bit int
uint32_t encoder1() {
	char chars[4];
	uint8_t ints[4];
	uint32_t encoder = 0;
	Serial.write(CMD);
	Serial.write(GET_ENC1);
	if (Serial.available() > 0) {
		Serial.readBytes(chars, 4);
		for(int i=0; i<4; i++)
			ints i] = (uint8_t) chars i];
		encoder = ((ints[0] << 24) +
		  (ints[1] << 16) +
		  (ints[2] << 8) +
		  (ints[3] << 0));
		return encoder;
	}
	else
		return NULL;
}

void enc_reset() {
	Serial.write(CMD);
	Serial.write(ENC_RESET);
}

void setup() {
	Serial.begin(9600);
	enc_reset();
}

void loop() {
	Serial.print(encoder1());
}

It works fine most of the time, but about 1 in every 10 times running the code, the returned integer value jumps by orders of magnitude, rather than by single integer values, as the motor spins.

I did some debugging and when printing the individual byte values to the serial monitor (i.e. those stored in “ints” in the code above), I noticed it appeared to be a timing issue with the sampling of these bytes, so the bytes would be shifted out of place.
For example, an encoder value of [0, 2, 0, 234], when incorrect, may be sampled as [2, 0, 234, 0] or [233, 0, 2, 0], etc. I have made sure that the code is written so that the only code in between the serial write of GET_ENC1 and the serial read is the Serial.available() function, which is routinely used (and written for the purpose of) being called right before a read, and shouldn’t throw off the timing. As well, I have also done this using a for loop with Serial.read() rather than Serial.readBytes(), but the result has been identical. It works ~90% of the time, but every now and again, the bytes are shifted, ruining the functionality of the encoder.

I have not found any solutions to (or even mentions of) this problem online. By the specification, it appears that only the 4 bytes are sent from the MD49, and that there is no checksum.

Is there anything else I can do, or any way I can get around this problem. It really defeats the purpose of having bought these motors if the encoders are unreliable, and thus useless.

Thanks for your help

I think what might be happening is that you’re trying to read bytes faster than they arrive. You could check this by verifying the return value of your readBytes call:

byte count = Serial.readBytes(chars, 4);
if (count != 4) {
 digitalWrite(13, HIGH); // Turn pin 13 high to show error has occurred
}

To fix the problem, I would recommend changing your Serial.available call to this

if (Serial.available() >= 4) {

to ensure that all four bytes have arrived before reading them.

I would also recommend adding code to empty read buffer before sending the your get command, something like this just before Serial.write(CMD):

while (Serial.available() > 0) {
 Serial.read();
}

Thanks! Clearing the serial buffer did the trick. There must’ve been extra bits in the buffer that threw off the order every now and then. The encoders seem to work perfectly now!

I also posted another problem involving buggy behavior of the motor controller on the initial start-up. If you could help me with that as well, I would really appreciate it. md49-and-arduino-start-up-behavior-issues-t11982

Thanks again so much for your help!!