BCD switch programming

I am looking for a little insight on how to program a number of different autonomous functions by using a BCD (binary coded decimal) switch that will provide 0-9 out to the digital sidecar.

Let us assume that the BCD switch is wired to bits 5 thru 8 on the side car with bit 5 as LSB and 8 as MSB.

My question(s) are when using C++;

  1. how do you mask out only the BCD to have a “more useful number”?
  2. To select any one autonomous mode would you use ‘IF’s’ or ‘Case’ statements?

It would be real nice to see some sample code for this as I’m sure it go a long way for other teams as well.

Even better would be examples using C++, Java and Labview.

I sure hope that Alan will jump in on this one :slight_smile:

Have you looked at the digital inputs on the driver station? Our team uses those exclusively for deciding which autonomous we’re going to use. Last year we had 7 different autonomi xD And we use a big ‘if’ statement, with the arguments looking something like this:



if(ds->GetDigitalIn(1))
{
	//Autonomous1
}
else if(ds->GetDigitalIn(1))
{
	//Autonomous2
}

etc… This is a simple way to do it. You could also use a switch-case statement, would definitely be one of the few uses in robot programming to use it. The only reason we don’t is just that switch-case statements are so rarely useful in FRC programming that we normally forget about them :stuck_out_tongue: you would have to pass your switch case variable as an argument in the GetDigitalIn function.

BCD is a limited subset of a hex nibble (single hex character). You can do that using bit shifts:


uint8 temp = getDigitalIn(#);
temp |= (getDigitalIn(#)) << 1;
temp |= (getDigitalIn(#)) << 2;
temp |= (getDigitalIn(#)) << 3;

//Now temp is a number from 0x00 to 0x0F

The lower levels of the WPIlib access the Digital Inputs as a single uint16 from the FPGA. If you wanted to poke and find the function to read those, you could just apply a mask and bitshift to get your number, instead of creating 4 dio objects and reading all of them (much less code, more efficient):

uint16 auton_num = <get the 16 bit DI register>;
auton_num &= 0x00F0;
auton_num = auton_num >> 4;

In LV, we use the auton number to index a 2d array of auton types (a struct of an array of strings and a command number). The first index is the auton, the second is time (when the command returns True, it advances to the next element in the array on the next iteration). The array is populated on boot by reading text files and parsing them. The array of strings are arguments, which functions read numbers out of on the first call.

I’m enclosing two examples of how we have done what you are asking for.

DIORead.png:
This is how we read the BCD number wheel on our 2012 robot. This number was used to select which autonomous to execute. We used the Analog Inputs on the Driver Station to set our start up delay before the Autonomous started.

AutonRead.png:
We changed to a text based command structure for autonomous in 2013. The Selection was chosen on the Dashboard and read at the start of Autonomous Independent.vi and passed to this VI. This VI read T3-Auton.ini (we used ftp to copy it to the cRIO) and selected the Section to read and execute. Below the code is a small subset of the T3-Auton.ini file. It also posted the command it is currently executing to the Driver Station User Message Window

DIORead.png




DIORead.png

A quick grep of the 1425 2014 robot code reveals 67 switch statements. Do you code your state machines with a bunch of “if” statements?

I use LV, so a Case Structure is the same a both an If and a Switch. There’s also a Select, which picks one of two inputs based on a boolean input. In normal programming (in C), I use Switch/Case all the time, usually for states.

FOR loops, on the other hand, have very limited use in controls programming. In general, you can use something else (such as a ratcheting counter) where a lot of new programmers use For loops and history buffers.

Yeah we do, with boolean values holding the state of most mechanism on the robot. I’m being a bit dense, but I fail to see how a switch case could be used for that.

If you need more than two states, you could use an unsigned integer or enum (which is effectively a uint with names) and a Switch through all of them.

For example, a shot sequencer last year had three states: idle, fire_execute, and fire_retract. It transitioned in a ‘circle’, with a condition from idle to fire_execute (fire trigger input), two conditions to return from fire_execute to fire_retract (gun speed accel threshold met, or failure timer met) and a timer to return to idle (shot interval reset timer). We could represent this with the following C code:

typedef enum {
stIDLE,
stFIRE_EXECUTE,
stFIRE_RETRACT
} fire_seq_t;

fire_seq_t state = stIDLE;

/* Somewhere in a temporal task */
switch(state) {
 case stIDLE:
  if(FIRE)
  {
   state = stFIRE_EXECUTE;
  }
 output_piston = 0;
 break;
 case stFIRE_EXECUTE:
  if(GSA_TRIG || TIMER > FIRE_FAIL_TIME)
  {
   state = stFIRE_RETRACT;
  }
 output_piston = 1;
 break;
 case stFIRE_RETRACT:
  if(TIMER > RETRACT_TIME)
  {
   state = stIDLE;
  }
  output_piston = 0;
  break;
}

Thats really neat! I’d never used enums before, I might use them next year :smiley: The thing is that I would have used int’s, but on the robot this year, almost every mechanism has boolean values, as we’re using a fair amount of pneumatics. What it would have been helpful for is the shooter, as we’re forced to put that in two variables, one for cocked and ready to shoot, and one for whether or not you have a ball.

Enums are awesome.

I have only used them in C and LV, I don’t know about implementation other languages like Java. In both C and LV, they are represented as uint’s, so you can do integer math and table lookups using it as well (e.g. we frequently have an array of setpoints, which we index by the state).

In the ‘real world’, I’ve seen people implement things with registers full of boolean bits, e.g. one program had things like GENFGA, GENFGB, GENFGC (gen flags A,B,C…Z and 1…9), each an 8 bit register full of bits relating to stuff, and the software is very bit-flag centric. IMHO, a numerical state machine is easier to understand.

Enums are really useful. Here’s a good example from our 2013 code of a command that supervises a subsystem on the robot, with several states represented by enum values: