Radio Packet loss + closed loop control system = lunging robot

Teams that have implimented closed loop speed/position controls should be aware that when packet loss occurs, and the PWM outputs are disabled, that your control loop software will continue to run and accumulate error that may in turn result in rather agressive behavior when the radio link is re-established.

When the robot controller has declared a communication’s failure and disables the outputs the user firmware currently has no direct means of determining that the robot is now in a “disabled” state. All your firmware will know is that the motors are slowing down and will attempt to make them go faster. When the outputs are re-enabled, the (now) larger control values will be immediately applied to the motors and make them rapidly increase in speed, until the control firmware recognizes the overspeed condition and takes corrective action.

The “disabled” bit in the mode struct only indicates whether the disable input on the competition interface has commanded a disable, and thus cannot be reliably used as an indication to your control loop why the motor(s) are slowing down.

I’ve asked IFI to make the local disable visible to the user code, and they are considering a change, but at this late date, I wouldn’t rely upon it to resolve this problem.

In the alternative, possible work arounds, which I’ve not yet had an oppertunity to test, include:

1.) Watching the ‘packet_num’ byte to make certain it is changing

2.) Wiring a ‘relay’ output directly back into a user ‘input’, set the relay output ON and use the user input bit as an indication of output disable.

Although I’ve had the closed loop control firmware implimented for a few weeks, this problem became much more obvious after loading the V14a RC master CPU firmware. V14a disables the outputs much more quickly than V13 did, so with V13, a few lost packets only caused a momentary loss of control, but didn’t create an immediate problem for the control firmware.

Your solution number 2 is really slick, I like it a lot!

Thanks for bringing this problem and potential solutions up :]

Just remember to use a relay output directly and not a spike, since the digital inputs are not 12v tolerant (this is mainly a warning to teams reading this who may misunderstand).

Perhaps I am mistaken, but I believe Dave meant that you take the relay output from the RC and wire it back into a digital input on the RC; Setting the relay output so that it is not what the default is.

That way when the problem occurs you can see that the digital input is showing the value of the default relay output, rather than what you set the relay output to be.

(the concept is what I’m trying to clarify, maybe you can use other ports, like digital out to digital in)

Sorry if I have misinterpreted you Dave.

Yes, I was suggesting setting one of the relay outputs true which should drive the pin high.

Though not directly documented, this post from IFI’s forum says that the relay outputs are VHCT (logic family) output pins in series with 330 ohm resistors. This should safely drive a “Digital I/O” pin, which just has a 1k series resistor and 0.001uF capacitor to ground before it goes into the CPU’s port pin.

The relay and PWM outputs are disabled by the master CPU, but the user Digital I/O pins are untouched, so one of those pins, configured as an output, couldn’t be used as an indicator of the robot being disabled.

I added the disclaimer in my inital post that I had tried neither approach yet, and won’t be able to do so until tomorrow. I’m reasonably certain that the relay outputs are 5V logic levels but would confirm that first.

I suspect that watching the packet number will work, and if so, I will post an example of how to do that.

Ok, I finally had time to work on this code tonight.

Both methods outlined in my first posting do work, however some additional consideration is warranted.

For the hardware method, the IFI forum posting I referred to either contains incorrect information, or outdated information… either way it isn’t right.

The ‘relay’ outputs on the robot controller actually only source power to the outputs via a series resistor, which appears to be closer to 400 ohms than the 330 ohms referenced in the post.

Because the outputs only source, and because the OI inputs only can have a pull up resistor (in the CPU), something must be provided to pull the relay output down to create a logic zero on the digital input.

A 2K load resistor from the relay output to ground results in an ON voltage of around 4.1V. The low resistance was enough to combat the digital input pull up resistor and in my case pulled it down to under 100mV. Both of these voltage levels meet Microchips specifications for logic high and logic low inputs values.

The relay output pins are indeed 5V and can be directly connected to a digital input.

The other method I described about watching the packet_num databyte also works quite well. It is a byte wide value, and will simply count 0 to 255 and then roll over to zero again. Checking it each time a the default user code executes is an easy way to reliably check to see when packets are being lost.

Here is some code I wrote to test both of these methods of detecting packet loss, and how I made the lost packet counter visible on the operator interface.

  static unsigned int discnt = 0;
  static unsigned int discnt2 = 0;
  static unsigned char last_mode = 0;
  static unsigned char last_packet_num = 0;
  static unsigned char last_in = 0;

	if (rxdata.packet_num != last_packet_num) {
		if (rc_dig_in10) {

	if (rc_dig_in10 != last_in) {
		if (!(rc_dig_in10)) {
		} else {
			lost_pkts = 0;

	last_in = rc_dig_in10;

	last_packet_num = rxdata.packet_num + 1;

	if (user_display_mode == 0) {
	} else {
		User_Mode_byte = discnt;

	printf("discnt: %5d  discnt2: %5d lost: %5d
\r",discnt, discnt2, lost_pkts);		

For those that are interested in adding some additional level of protection against lunging as a result of packet loss, the information above should help you impliment something that prevents this.