*Originally posted by Joe Johnson *
**The main thing had to do with the Programming port from the Stamp2 on the RC echoing back any character that I sent it.
This was a MAJOR pain in the rear.**
Isn’t that the truth. It took us a few days to figure that one out. We managed to get a pure serial link working between the RC and our microcontroller (HC08) by having the RC issue a ‘request’ (a 1 byte command) that the uC would respond to with a 1 byte response. We had 3 pieces of data to pass back (X, Y coordinates and our orientation) that were each a byte. Initially we tried a single request byte to which the uC would respond with all 3 bytes but ran into a big problem with that: the BASIC Stamp is barely capable of 9600 bps. Even after adding delays into our uC between each byte the RC still wasn’t always capable of keeping up with it. So we settled on 1 request byte for each byte of data we returned (ugly, painful, and slow but it worked). Also the other problem we ran into is if you try to SERIN multiple bytes in the same statement, the timeout parameter only works if NO bytes are received. For example, if you’re trying to SERIN 3 bytes but only end up reading in 2 bytes, the SERIN command will NOT time out, and eventually the RC will reset the BASIC Stamp. This causes a mess during autonomous.
To solve the “echo” problem, we created command bytes that were reserved (i.e. only the RC could send them - before the uC sends out a byte, it ensures that the byte doesn’t match any of the command bytes). This way, the interrupt service routine on our microcontroller can safely assume that any byte that’s not a command byte is an echo and discard it. We do this by checking the outgoing byte in our SendByte routine on the uC and rounding down any value that matches a command byte (also we have no sequential commad bytes).
Here’s the relevant RC code:
'==========================================
'========= InputData Subroutine ===========
'== Inputs: none
'== Outputs: s_curr_pos_x - current X position
'== s_curr_pos_y - current y position
'== s_curr_orient - current orientation
'== Modifys: tmp1, tmp2, tmp3
'== Purpose: get current position data from CC
'==========================================
InputData:
'request X
Serout 16, CC_OUTBAUD, [CC_CMD_REQ_X_POS]
Serin 16, CC_INBAUD, 5, InputDataNoData, [tmp1]
'request Y
Serout 16, CC_OUTBAUD, [CC_CMD_REQ_Y_POS]
Serin 16, CC_INBAUD, 5, InputDataNoData, [tmp2]
'request theta
Serout 16, CC_OUTBAUD, [CC_CMD_REQ_THETA]
Serin 16, CC_INBAUD, 5, InputDataNoData, [tmp3]
GET s_waypoint, waypoint
if(waypoint__idx = DEFAULT_WAYPOINT_IDX) then
'The RC has just reset, we must ask the CC for what waypoint we were at before the reset.
' On powerup the CC will default the index to 0, so powerup will work fine.
Serout 16, CC_OUTBAUD, [CC_CMD_REQ_WAYPOINT]
Serin 16, CC_INBAUD, 5, WaypointManagerDone, [tmp3]
waypoint__idx = tmp3
endif
'If we reset in the middle of auton mode, then we won't be able to figure out the autonomous
' program number so it will be INVALID. In this case, ask the CC for that info
if((waypoint__prog_side & WAYPOINT_PROG_ONLY_MASK) = AUTO_LIST_INVALID) then
Serout 16, CC_OUTBAUD, [CC_CMD_REQ_PROG_SIDE]
Serin 16, CC_INBAUD, 5, WaypointManagerDone, [tmp3]
waypoint__prog_side = tmp3
endif
PUT s_waypoint, waypoint
'debug "x ", DEC tmp1, " y ", DEC tmp2, " t ", DEC tmp3, CR
'X,Y,Theta of Zero means the CC has reset and doesn't know where it is. We will
' feed it with the last known data (or in a powerup case, the data for the our start
' position on the field.
if ((tmp1 = 0) AND (tmp2 = 0) AND (tmp3 = 0)) then
GET s_curr_pos_x, tmp1
GET s_curr_pos_y, tmp2
GET s_curr_orient, tmp3
Serout 16, CC_OUTBAUD, [CC_CMD_SET_POSITION, tmp1, tmp2, tmp3]
else
PUT s_curr_pos_x, tmp1
PUT s_curr_pos_y, tmp2
PUT s_curr_orient, tmp3
endif
goto InputDataEnd
InputDataNoData:
'NO CUSTOM CIRCUIT!!!
'Toggle 7
'debug "Serin timeout", CR
nvr_2_3_auton_bits__auton_stop = 1
GET s_target_orient, tmp1 'No custom circuit so set the curr theta to target to prevent theta correction
PUT s_curr_orient, tmp1
InputDataEnd:
return 'from InputData
A decent portion of this routine is dedicated to ‘disaster recovery’. As we mentioned on CD before, at one point we were having major problems with our RC and/or custom circuit resetting due to static electricity discharge. To handle that and other reset problems, we built in some code that keeps key autonomous information redundant between the RC and the CC. If the RC were to reset, it wouldn’t know which waypoint it was heading towards. If the CC reset, it woudln’t know where it was anymore (it would think it was back at the starting point). So, we store the waypoint in the CC and the position in the RC for redundancy. This way, if the custom circuit resets, the RC can detect that and initialize it with the robot’s current position on the field. If the RC resets, the CC will feed it the correct waypoint. It’s a pretty neat feature that we added sometime after the Midwest regional I believe. Luckily we never made much use of it in competition (because it still slows everything down when the RC resets!)
Well hopefully this gives you something to noodle over. Let us know if we can provide more info or help!