Arduino Software HW IO - RobotCasserole1736/RoboSim GitHub Wiki

Background

Since the Arduino Uno only has 12 available IO pins (0 and 1 are taken by serial), and runs on a 0-5V system, a few hardware peripherals were needed to adjust the arduino to the FRC electronics environment. This page details the software required to work with this IO setup

Getting Data On and Off the Arduino

IO Card

The IO card was by far the most complex part of the IO design. Its electrical schematics can be found in \RoboSim\Eagle\RoboSim\IO_Board.sch . There is also a corresponding board design, but that is not yet complete.

At a high level, the board consists of four shift registers, 8 bits each, connected in serial. This effectively forms a 32-bit shift register with 16 bits dedicated to analog outputs, 8 bits to digital outputs, and 8 bits to digital inputs.

The board and software is designed such that if more IO is needed, duplicates of the board can be made and ganged together. This will increase the effective device to a shift register of (32*num_io_boards) bits.

There were two types of shift register chips used. The outputs (analog and digital) are a type of shift register that sets outputs based on the state of an internal set of registers. The inputs are of a different kind, which sets internal registers based on external voltages.

From a software perspective, four electrical signals must be generated by the Arduino:

  • Data Out - output pin which outputs the data for the IO card in serial fashion (one bit after another)
  • Data In - input pin which gets the data that was in the IO card's registers back
  • Clock - Output pin which toggels high-low for every bit. A falling edge on the clock indicates that the IO card should take one new bit from arduino, shift all its bits internally by one, and assert a new output on the Data In line for the arduino. By toggling the clock 32 times, a full new set of bits is given to the IO card, AND the full set of bits from the last data sample is read back in.
  • Sync - The shift registers used on the IO card are all "buffered" - this means that the internal registers which do the shifting are not directly connected to the input and output pins. This allows us to shift data internal to all the registers, without affecting the state of the output pins until we actually want to. (Without buffering, the output states of the pins would jump around a lot while shifting data).
    • As it turns out, the output shift registers propagate data from the internal registers to the actual pin outputs on the falling edge of the sync signal. However, the input shift register transfers data from the pins to the internal registers whenever the sync signal is low. This minor difference in behavior defines the shape of the sync signal - high almost all the time, but a quick pulse low right before starting the shift, and brief pulse after the shift has happened.
      • The first pulse samples the inputs into the internal register.
      • Then we shift the data
      • Then the second pulse sets the new outputs to the output pins

Analog Inputs

The PWM filter card's job is to remap the -12 to +12 V input range of motor controllers to a 0-5V range which the Arduino can read (and it won't burn out the Arduino). Additionally, it averages out the PWM signal so that it looks like a smooth DC signal to the Arduino (mostly).

The ideal mapping is as follows:

  • Full Fwd = 12V from motor controller = 0.0 V at Arduino input = analogRead() returns 0
  • Stop = 0 V from motor controller = 2.5 V at Arduino input = analogRead() returns 512
  • Full Rev = -12V from motor controller = 5.0 V at Arduino input = analogRead() returns 1024

Due to tolerances on electrical components, the actual mapping may not be as precise, so a 3-point map is used to adjust the analogRead() value. Note the negative slope relationship between motor controller output and analogRead() return values - this is due to the fact that the PWM input board has an inverting amplifier on it.

The read values are simply stored to global variables, where they are read back by the serial functions and returned to the PC.

Encoders

The encoders are probably the second most complex part of the output. To get more info on how the encoders have to work, check out https://en.wikipedia.org/wiki/Rotary_encoder#Incremental_rotary_encoder .

The Arduino is responsible for maintain accurate frequency output to represent the rotational speed of the encoder. This is done by scheduling a recurring function as part of the encoder_init() function. Using the FlexiTimer2 library, we cause an interrupt service routine to be fired off every 100us, much faster than what the RTOS tick supports. This very short routine moves a state machine through one of four states representing the grey code sequence of encoder output expected by a quadrature encoder (00, 01, 11, 10). The rate of transitioning states and the direction is determined by a handful of volatile global variables, which get set every time a serial packet comes in with new speed data.

Serial

The arduino reads and writes serial packets for communication with the PC. All packets are assumed to start with the character ~ and are of fixed length. See https://github.com/RobotCasserole1736/RoboSim/wiki/Serial-Protocol for more info.