FIRST Robotic Competition in Oregon: Coprocessor 20040909

Topics

Attendance

I was disappointed that none of the new recruits from Cresent Valley and West Albany showed up. They also haven't responded via email. I hope they show up next week.

Gary introduced us to gdb. He also demonstrated a simulator he wrote for the MSP430 processor, which is what is on the manifold. We needed that since the manifold wasn't working for some reason.

Notes by Gary:

We met to discuss the initial attack on construction of the Input Output "manifold" device. The unit, which consists of a small circuit board containing a TI microprocessor, will act as some of the input/output circuitry for a robot control system. During the meeting we discussed programming tools and communication protocol.

It looks like the best (and also least expensive) tools will be the GNU MSP430 C compiler. This is open source system (as in free) also contains a nice graphical console debugger and microprocessor simulator, so testing of new code can be done easily. It is an early version of the system, so there are still some rough edges as evidenced by my inability to get the basic system to run. After playing with it at my office most of the afternoon, where most things ran well, I was unable to get the system to run at home. It's likely due to the power supply for the microsprocessor board, so I'll try again after packaging the board with a wall-wart power supply. My battery pack was obviously not what was needed...

Communication Protocol:

The currently envisioned layout for the communication "network" consists of the FRC (First robotic controller) connected to our manifold board (which has two serial ports) with the second manifold serial port connecting to the LinkSys router, which becomes the "brains" of the robot. The program for the LinkSys will do the "heavy lifting" but has no direct way of doing input/output to the various devices and FRC. The manifold board has lots of i/o points (digital and analog) but does not have much compute power. The FRC has the guts of the I/O (radio and motor) but has no compute power and very little other I/O

Our initial definition of the communication protocol will allow any device to address any other device (so that the FRC could poll I/O on the manifold or the LinkSys could poll I/O or communicate with the FRC.) Communcation from LinkSys to FRC would, however, be indirect, in that the messages would need to pass THROUGH the manifold.

Our protocol is packet based. Each packet starts with a unique character (we've chosen the "$" for no particular reason) followed by zero or more data bytes (in pairs) followed by a carriage return. The data bytes are organized in pairs of hexadecimal digits (0 to 9 and A to F) representing pairs of 4 bit characters or a total of 8 bits. Thus each pair of digits corresponds to a single BYTE of data.

The message is terminated by the carriage return. All other character values (such as line feed) are ignored.

The first byte of data (hereafter a pair of hex digits) is the "address byte". The high order four bits represent an address of the node that is sending the message or the address of the node where a response should be sent. The low order four bits are the destination address for the message. The remaining bytes (up to but not including the last byte) are command bytes, followed by data (if appropriate.) The commands defined at this point are:

1x Write to port X. Data byte following contains data to write.
2x Read from a port. No data following. Data value is returned in a reply message.
3x Read data value X. This is the reply to a 'Read Data' message.
4x Write configuration for port X. Data byte following is mode, where 1 bits are OUTPUT and 0 bits are input.
5x Read configuration for port X. No data following. Port config byte is returned in a reply message.
6x Read configuration reply from port X. This is the reply to a read configuration message.
7x-Dx not used.
Ex

Set periodic process X. Next two bytes are delay in milliseconds, high byte first. Next byte is a length. Following are the number of bytes specified by "length" which are treated as a message that is processed an interval specified by the delay value. For example, if the message was:

$12E503F803122021xx\r\n (xx is message checksum)
The LinkSys (node 1) sends a message to the manifold (node 2) that specifies setting of periodic process 5 to be the message "122021" which is a "read of port 0 and 1 and send the results to node 1 (the linksys.)

A periodic process X can be cancelled by sending it a zero length process string:
$12E500xx\r\n

Fx Error report. Next byte is a length byte. Following are 'length' bytes of the error message.

The message checksum should be easy to calculate. My suggestion is to form the checksum as the "two's complement" of the sum of the data. This way, adding of the byte value of all the data between the $ and the carriage return will yield ZERO for a properly formed message.

The "two's complement" is just another way of saying the "negative" of a number. You calculate this by adding all byte values (as pairs of hex digits) of all data after the $, up to the end and then negating it and adding the resulting value to the end of the message as two additional hex digits. When a message is received, you add up the byte values and if the sum is zero, remove the last byte and process the message.


A simple set of source code has been placed on the scalawags.org server in a CVS (source code control system) repository. A simple tasking kernel and sample application have been uploaded. I'll do some work on the simple app to make it a good starting place for development (before I hand it off to you guys to program...) I'll add some documentation for the tasking kernel (it is very simple and only has about 20 function calls available) and upload it later this week. I'll post a note and instructions.

Jeff / Allen - I forgot to tell you but I've added accounts for both of you on this system - we'll need to coordinate to get you the initial passwords - I'll expect you to change them the first time you log on. You'll need the passwords to access the source code repository.

-Gary

In case there is any confusion about this I want to clarify how data is sent. Each "word" in the packet is technically a byte since it is 8 bits long. And it is always accompanied by its address. But we don't send binary data in packets, so the most information each of those bytes will carry is actually a nibble. And since we also have start, stop, and checksum, the protocol efficiency is somewhere around 20%.

Gary and I discussed the bandwidth requirements set by the Operator Interface. I estimated that at 10 bytes every 26ms. If the FRC is only capable of 9600baud, then we have a problem since that takes up all of the available bandwidth. We need to determine if this can be cranked up. I think we need at least x4 that bandwidth.

If we cannot increase the baud rate of the FRC serial port then we will need to implement a parallel protocol. But before putting any effort into that, we should first determine if the serial port can do what we want.

By the way, this points to a slight blind spot. We actually have 4 nodes on our daisy-chained network. The Operator Interface is at one end. However, I don't think this changes anything in our protocol since the OI is not capable of participating in networking.

Also, I thought of another message that I would like to see: LogThis. Along with error reports, the payload to this message would go into our log file. The log file would be downloadable after each match.

The overall structure of a packet doesn't seem to be defined above. Let me take a shot at it here. [By the way, lets drop the \r. It just takes up badly needed bandwidth.]

Byte# What Comment
1 Start Always '$'.
2 Src This is the node number of the sourcing device.
3 Dest This is the node number of the destination device.
4 Message This the first command in the packet. See the message table
5-m Data This is optional data to the message in byte 4. If the message has no data, then we skip this and byte 5 can be the next message or else the cksum.
m Optional Next Message This will again be followed by optional data.
n-2 CKSUM1 High Nibble of the Checksum
n-1 CKSUM0 Low Nibble of the Checksum
n End Always '\n'.

I notice that we need to receive a full packet before interpreting that packet. There are two reasons for this. First, you don't actually know if you are seeing a CKSUM or another message until you see the End flag (\n). But more importantly, you don't know if the packet is valid until you have checked the CKSUM. If it isn't, then you don't *want* to interpret it.

Packet size will need to be limited to work within the constraints of the FRC. We will need to quantify those limits. If we are lucky, they won't be a real problem.

But we also are better off with larger packets since those make better use of the bandwidth. We will have to give this more thought later in the development process.

And the message addressing is designed around the limits of the manifold. Since the FRC has different limits, I think we need to revisit this. That would change the message table.

I want to take another shot at the message table above. I will add the log command. But for now I will leave addressing alone. And I think the original proposal for the PERIODIC command co-opt'ed the address field for the length. Not really sure. But I think we need to retain that field. If there can be more than one PERIODIC active, and if we want to be able to update any of them, then we need some way to address them. Partly because I'm not sure about the original proposal's meaning, and partly because I would like to make some tweaks, the following is actually a different proposed message table.

Message Name Char Length Mess. Char [1st byte] Addr. Char Time Len. Data Chars Comments
WRITE 4 1 [0-F] - - [0-F] [0-F] Write one byte of decoded data to the port.
READ 2 2 [0-F] - - - Request read from specified port.
DATAIS 4 3 [0-F] - - [0-F] [0-F] The value of the requested port is supplied as data. This is the reply to a 'READ' message.
CONFIGWR 4 4 [0-F] - - [0-F] [0-F] Write configuration for port X. Data byte following is mode, where 1 bits are OUTPUT and 0 bits are input.
CONFIGRD 2 5 [0-F] - - - Read configuration for port X. No data following. Port config byte is returned in a reply message.
CONFIGIS 4 6 [0-F] - - [0-F] [0-F] Read configuration reply from port X. This is the reply to a CONFIGRD message.
- - [7-C] [0-F] - - [0-F] [0-F] not used.
PERIODIC >=6 D [0-F] [0-F] [0-F] [0-F] [0-F] any even number of [0-F]

Set a periodic process. The time field is delay in milliseconds, high nibble first. The data field contains twice the number of nibbles specified by "length". That field is treated as a message that is processed at an interval specified by the time value. For example, if the packet was:

$12D51A02122059\n
  • $ - Start Packet
  • 1 - Node 1, the LinkSys, sends this packet.
  • 2 - Node 2, the manifold, is to receive this packet.
  • D - This is a PERIODIC message type.
  • 5 - PERIODIC message slot 5.
  • 1A - Time period in hexadecimal milliseconds. 26ms.
  • 02 - Length
  • 1220 - Data to be packetized and executed periodically.
    • 1 - Node 1, the LinkSys, sends this packet.
    • 2 - Node 2, the manifold, is to receive this packet.
    • 2 - READ message.
    • 0 - Port 0.
  • 59 - Checksum. (I didn't really calculate the checksum here.)
  • \n - End Packet.

A periodic process X can be cancelled by sending it a zero length process string:
$12D50000xx\n

LOG >6 E [0-F] - [0-F] [0-F] any even number of [0-F] Messages are encoded as nibble pairs. When stored, they are compressed to bytes.
ERROR >6 F [0-F] - [0-F] [0-F] any even number of [0-F] Error report. Next byte is a length byte. Following are 'length' bytes of the error message.

Please note that in the table above the shorthand: [0-F] means any of the hexadecimal character set [0123456789ABCDEF]. In other words, [0-F] is a single character which will decode to a nibble.

In general, the length field would specify the number of bytes after compression. That means the data field would contain twice the number specified in the length field. That is why the data field is always an even number of characters. It may be worth considering using only one nibble for the length field. That would still allow for packets of 16 bytes after compression.

We could get better protocol efficiency by including multi-byte reads. This would almost double the efficiency.


Schedule


Last modified 11 Dec 2006
http://brown.armoredpenguin.com/~abrown/contact.html
http://brown.armoredpenguin.com/~abrown/first/first2004/coprocessor/notes20040909.html