
| Note - SRV-1 Blackfin version of SRV_protocol found here - http://www.surveyor.com/blackfin/SRV_protocol_bf.html All commands from the host to the SRV-1 robot are comprised of ASCII characters, and all commands receive an acknowledgment from the robot to the host, which is either a '#' character followed by the command, or '##' for variable length responses. Variable length commands which don't specify a return size append a newline ('\n') to their response. |
| Note that all of these commands can be executed via a terminal or console program. With a Zigbee radio setup, just connect your terminal program to the USB radio serial port (COM4, /dev/usb0, /dev/cu.SLAB_USBtoUART, etc) at 115200 baud, 8-bit, no parity, 1 stop bit, and type the commands direct to the robot. With the Wiport radio, the serial interface is 921600 baud, but you'll connect via 'telnet robot-ip 10001' |
| When the robot first powers up, it will dump the 'V' Version command results ("##Version ...\n") so you can see what version of firmware is running. There is typically a 5 second delay after startup before the robot can accept any commands while the camera and other sensors are initialized. After startup, just to test that there is 2-way communication, send an '8' which commands the robot to move forward, a '5' which commands the robot to stop, a '0' which commands the robot to rotate left approx 20 deg, etc. The only command that will produce strange results is the 'I' IMJ command, which grabs a JPEG frame - this will flood the screen with binary characters. |
| Note that an entire set of commands have been added for BASIC and C interpreters that are found in latest versions of SRV-1 firmware - srv1.hex.053007c (Zigbee radio w/C interpreter), srv1.hex.053007w (Wiport radio w/C interpreter) and srv1.hex.053007b (Zigbee radio w/BASIC interpreter). The 'Q' command will execute a BASIC or C program that has been stored in the robot's flash memory user segment. When the program finishes (assuming the BASIC/C program isn't running an infinite loop), control returns to the regular SRV-1 command processing loop. |
| If there are any questions about this protocol, send email to support@surveyor.com or check the Surveyor Robotics Forum. |
| Command | Response | Description |
|---|---|---|
| Core Robot Commands | ||
| 'Mabc' | '#M' | direct motor control (all characters sent as hex)
a=left speed, b=right speed, c=duration*10milliseconds speeds are 2's complement hex values - 00 through 7F is forward, FF through 81 is reverse, e.g. the 4-byte sequence 0x4D 0x32 0xCE 0x14 = M 50 -50 20 (rotate right for 200ms) duration of 00 is infinite, e.g. the 4-byte sequence 0x4D 0x32 0x32 0x00 = M 50 50 00 (drive forward at 50% indefinitely) |
| '7' | '#7' | robot drift left |
| '8' | '#8' | robot drive forward |
| '9' | '#9' | robot drift right |
| '4' | '#4' | robot drive left |
| '5' | '#5' | robot stop |
| '6' | '#6' | robot drive right |
| '1' | '#1' | robot back left |
| '2' | '#2' | robot drive back |
| '3' | '#3' | robot back right |
| '0' | '#0' | robot rotate left 20-deg |
| '.' | '#.' | robot rotate right 20-deg |
| '+' | '#+' | high motor speed range |
| '-' | '#-' | low motor speed range |
| 'a' | '#a' | set capture resolution to 80x64 |
| 'b' | '#b' | set capture resolution to 160x128 |
| 'c' | '#c' | set capture resolution to 320x240 |
| 'A' | '#A' | set capture resolution to 640x480 |
| 'f' | '#f' | turn on "failsafe mode" (stop motors if no radio contact) |
| 'F' | '#F' | turn off "failsafe mode" |
| 'I' | '##IMJxs0s1s2s3....' | grab JPEG compressed video frame
x = frame size in pixels: 1 = 80x64, 3 = 160x128, 5 = 320x240, 7 = 640x480 s0s1s2s3=frame size in bytes (s0 * 256^0 + s1 * 256^1 + s2 * 256^2 + s3 * 256^3) .... = full JPEG frame Note that sometimes the 'I' command returns nothing if the robot camera is busy, so the 'I' command should be called as many times as needed until a frame is returned |
| 'B' | '##BounceIR - aa bb cc dd\n' | send 0xFF bit pattern from each IR emitter in sequence
aa bb cc dd are bounced bit counts for front, left, back, right |
| 'V' | '##Version ...\n' | read firmware version info response is terminated by newline character |
| 'ddxx' | '##dd\n' | set data direction for i/o pins, 1=output, 0=input, xx = [0 0 0 E9 E10 E11 E12 E13] |
| 'dr' | '##drxx\n' | xx = read levels of E9 E10 E11 E12 E13 in this order - [0 0 0 E9 E10 E11 E12 E13] |
| 'dwxx' | '##dw\n' | write output levels for bits on i/o pins, 1=high, 0=low, xx = [0 0 0 E9 E10 E11 E12 E13] e.g sets E9, E11 and E13 to output - "dd15", set E11 and E13 high - "dw05" |
| 'zwdddd...\0' | '##zw\n' | write null-terminated data (up to 1024 bytes) to robot flash memory. dddd = ASCII data to be written, e.g 'zwmy name is srv-1\0' writes the string 'my name is srv-1' to flash memory note - to make certain the robot is ready to receive all of the data, insert a small delay (500 milliseconds) between sending 'zw' and the data |
| 'zr' | '##zrdddd...\n' | read data from robot flash memory until 1024 bytes have been read or null (\0) is encountered, dddd = ASCII data from flash, e.g 'zr' returns '##zrmy name is srv-1\n'. |
| Vision Commands | ||
| 'w' | '#w' | turn on "wander mode" in 160x128 resolution (robot will move around on its own)
the 'w' and 'm' command initializes wander mode, capturing the color of the ground in front of the robot and using that information thereafter to determine whether the area in front is open or blocked, so each time a 'w' is issued, the reference ground color is recaptured |
| 'W' | '#W' | turn off "wander mode" |
| 'S' | '##Scan - 010203...\n' | view raw "pixel column vector" data from frames captured in "wander mode"
01, 02, 03, etc represents hex value from 0x00-0x40 for each pixel column (80 or 0x50 columns total), so a low value indicates blockage nearby, high value indicates open column (vector). the value is roughly proportional to distance from robot to blockage |
| 'vgcx1x2y1y2' | '##vgcy1y2u1u2v1v2\n' | the
'vg' command grabs and samples the range of YUV colors in a rectangular
region defined by x1, x2, y1, y2, and save info to color bin #c. there
are 16 possible color bins, ranging from 0x0 to 0xF. e.g. 'vg010200515' will sample colors for color bin #0, ranging from column 16 (0x10) through column 32 (0x20) at heights ranging from line 5 to line 21 (0x15), where line 0 is the lowest line in the image. the robot will return a string with 'vg' followed by the color bin number, then y1=Ymin, y2=Ymax, u1=Umin, u2=Umax, v1=Vmin, v2=Vmax. as an example, when sampling an area that contained an orange golf ball using the 'vg' command for color bin #0, the robot returned '##vg079B056719AC4\n'. a graphical interface for defining the "region of interest" to be sampled would be especially helpful in using this command. |
| 'vrc' | '##vrcy1y2u1u2v1v2\n' | the 'vr' command retrieves the stored color info from color bin #c. this command will return string with 'vr' followed by the color bin number, followed by y1=Ymin, y2=Ymax, u1=Umin, u2=Umax, v1=Vmin, v2=Vmax. in the above example where colors for an orange golf ball were captured using the 'vg' command for color bin #0, issuing a 'vr0' command will return the colors stored in color bin #0 - e.g. '##vr079B056719AC4\n'. |
| 'vccy1y2u1u2v1v2' | '##vcc\n' | the 'vc' command directly sets the contents of color bin #c. this command will return string with 'vc' followed by the color bin number. for example, we could save a set of colors to color bin #3 corresponding to measurements taken at another time, such as the above mentioned orange golf ball color measurement, using 'vc379B056719AC4'. we could then confirm that the colors were properly stored by issuing the command 'vr3' to retrieve the contents of color bin #3. |
| 'vsc' | '##vsc010203...\n' | same
function as the "Scan" command above for viewing raw "pixel column
vector" data , except that we can specify which color bin to use when
scanning. 01, 02, 03, etc represents hex value from 0x00-0x40 for each pixel column (80 or 0x50 columns total), so a low value indicates blockage nearby, high value indicates open column (vector). the value is roughly proportional to distance from robot to blockage. note that the "Scan" command is using the colors stored in color bin #0, so issuing the 'S' command or 'vs0' will return the same results, except for the first few characters of the response ('##Scan - ...' vs 'vs0...') |
| 'vfc' | '##vfc010203...\n' | similar to
the 'vs' scan command, except that returned values are distance to
first pixel matching the target color in each pixel column. 01, 02, 03, etc represents hex value from 0x00-0x40 for each pixel column (80 or 0x50 columns total), so a low value indicates the matching color nearby, higher value indicates matching pixels further away, and FF represents no match. the value is roughly proportional to distance from robot to matching pixel. |
| 'vbc' | '##vbcx1x2y1y2ssss...\n' | the
'vb' command searches for blobs matching the colors in color bin #c,
and returns coordinates of an x1, x2, y1, y2 rectangular region
containing the matching pixels, along with a count of matching pixels
in the blob. up to 16 blobs can be returned, and the blobs are sent in
order of pixel count, though blobs smaller than MIN_BLOB_SIZE
(currently set to 5 pixels) aren't shown. an easy way to test this function is to use the 'm' command, which is hardwired to grab color samples from columns 20-59 (0x14-0x3B) in rows 0-5 and store them in color bin #0, then try the 'vb0' command to see what blobs show up. if an object is large enough to cover that hardwired area of the image, you should get pretty good tracking, and can try moving the robot away from the object to see how the blob is tracked. |
| 'vnc' | '##vnc010203...\n' | similar to the 'vb' scan command, except that the returned values are the number of pixels matching the target color in each pixel column. |
| BASIC Language Commands | ||
| 'Q' | runs BASIC program stored in first sector of flash memory | |
| ASSIGN | A = B / 20 | |
| OPERATORS | + - * / ^ % = ; ( ) , > < & | | |
| VARIABLES | 32-bit signed integers - 'A' - 'Z' | |
| COMMENT | no processing of this line, e.g. COMMENT this is a comment | |
| prints strings, variables, constants, e.g. PRINT A, 50, "hello" | ||
| INPUT | checks the serial port (radio channel) for a single incoming character. save incoming character in 'X'. if no data is found, set X = 0 (0x00) | |
| IF ... THEN ... | IF H < 11 THEN GOTO 200 | |
| FOR ... TO ... | FOR loop, can be nested 25 deep, e.g. FOR J = 1 TO 100 FOR K = 1 to 5 PRINT J*K NEXT NEXT | |
| NEXT | end of FOR loop | |
| GOTO | jump to label, e.g. GOTO 100 | |
| GOSUB | subroutine call, can be nested 25 deep, e.g. GOSUB 300 | |
| TIME | save current time (milliseconds since startup) in 'T' variable | |
| DELAY | program delay in milliseconds, e.g. DELAY 500 | |
| MOTORS | MOTORS 50, 50 or MOTORS A, B - set left and right motor output, e.g. MOTORS 50, -50 to spin right MOTORS -50, -50 to go backwards note - the format of the MOTORS command has changed slightly from the first version of firmware, as the left and right motor speeds are now separated by a comma | |
| IR | IR <1,2,3,4> - read sensor and save in 'X' variable. IR 1 = forward, 2 = left, 3 = back, 4 = right | |
| IMGCAP | capture image at 160x128 resolution (stored as 80x64 YUV) | |
| COLORCAP | captures colors from latest image in box bounded by x1 x2 y1 y2, and stores to designated color bin, e.g. COLORCAP 0 20 40 1 5 captures to color bin #0 from x=20 to x=40, y=1 to y=5 | |
| COLORSET | sets the colors in a color bin - format is somewhat different from the "vs" command, as data is Y, U, V, Y-range, U-range, V-range, rather than min/max values | |
| COLORGET | lists the colors in a specified color bin using same format at COLORSET. to view values, PRINT Y, U, V to view ranges (for Y U V), PRINT R, S, T e.g. COLORSET 0 128 89 95 15 10 10 COLORGET 0 PRINT Y, U, V PRINT R, S, T output will be 128 89 95 15 10 10 | |
| SCAN | similar to the "vs" Scan
function above, but divides the image into 3 overlapping areas, saved
into X = front left, Y = front, Z = front right. if a region is
blocked, the value will be zero. if it's not blocked, the value will be
positive, with a higher number indicating more open space in that
region, e.g. IMGCAP SCAN 0 PRINT X,Y,Z might output 7 12 0 indicating that the right is blocked, but forward and left are both open | |
| BLOB | similar to the "vb" Blob
function above, but only returns the largest blob matching the
specified color, with results saved into X = centroid x coordinate, Y =
centroid y coordinate, Z = blob width. e.g. IMGCAP BLOB 0 PRINT X,Y,Z might output 40 30 15 for a blob centered at (40,30) with a width of 15 pixels a width of 0 would indicate that no matching blob was found | |
| BITDIR | set data direction for i/o pins, 1=output, 0=input, xx = [0 0 0 E9 E10 E11 E12 E13], e.g. BITDIR 3 sets pins E9 E10 E11 as input and E12 E13 as output | |
| BITSET | write output levels for bits on i/o pins, 1=high, 0=low, xx = [0 0 0 E9 E10 E11 E12 E13] e.g. BITSET 2 turns on pin E12 | |
| BITGET | read levels of E9 E10 E11 E12 E13 in this order - [0 0 0 E9 E10 E11 E12 E13], store result in 'X' variable | |
| BASIC code sample | A = 50 ^M^J B = -50 ^M^J 100 IR 1 ^M^J IF X < 20 THEN MOTORS A, A ^M^J IF X > 19 THEN MOTORS A, B ^M^J DELAY 500 ^M^J GOTO 100 ^M^J END ^M^J^A this program checks the front IR (IR 1) and returns the reading in 'X', moves forward if below a threshold or turns right if above the threshold. an easier way to code this would be MOTORS 50 50 and MOTORS 50 -50, but the MOTORS command can't yet handle negative values, so we put the negative value in B. available variables are 'A' through 'Z'. note that a CR LF (^M ^J) is required at the end of each line and a Null (or ^A) character is required at the end of the program | |
| C Language Commands | ||
| 'Q' | execute | runs C program stored in first sector of flash memory |
| assignments | a = b / 20; a = a - 1; | |
| operators | + - * / % & | = ( ) > >= < <= == != | |
| int, char | 'int' is 32-bit signed integer, 'char' is 8 bit unsigned chars. variables declared locally or globally - variable names can be up to 31 characters in length | |
| /* comment */ | no processing of characters, e.g. /* this is a comment */ /* this is a two line comment */ | |
| void print() | prints a set of strings and variables, followed by a newline ('\n'), e.g. print("hello"); print("test" _x _y _z); | |
| char input() | checks the serial port (radio channel) for a single incoming character. ch = input() /* if no data is found, ch = 0 */ | |
| if () ... else |
if (ir(1) > 10) /* read front IR sensor */ motors(50, -50); /* if bounced signal detected, turn right */ else motors(50, 50); | |
| for() | for() loop, can be nested 15 deep, e.g. main() { int i, j, k; for(i = 0; i < 5; i = i + 1) { for(j = 0; j < 3; j = j + 1) { for(k = 3; k ; k = k - 1) { print(i); print(j); print(k); } } } } | |
| while() while() ... do do ... while() |
count = a; do { print(count); } while(count=count-1); | |
| int|char|void function() ... return | up to 25 functions can be defined, function name length up to 25 characters, and functions can be called recursively e.g. factr(int i) { if (i < 2) { return 1; } else { return i * factr(i-1); } } | |
| int time() | get current time (milliseconds since startup) - int t1; t1 = time(); | |
| void delay() | program delay in milliseconds, e.g. delay(500); | |
| void motors() | motors(left, right) sets left and right motor output, e.g. motors(50, -50); /* spin right */ motors(-50, 50); /* spin left */ motors(-50, -50); /* go backwards */ motors(50, 50); /* go forwards */ | |
| int ir() | read ir sensor 1,2,3 or 4 1 = forward, 2 = left, 3 = back, 4 = right int signal; signal = ir(2); | |
| void imgcap() | captures image at 160x128 resolution (stored as 80x64 YUV) | |
| void colorcap() | colorcap(color_bin,
x1, x2, y1, y2); captures colors from latest image in box bounded by x1
x2 y1 y2, and stores to designated color bin (0 - 15), e.g. imgcap(); colorcap(0, 20, 40, 1, 5); captures to color bin #0 from x=20 to x=40, y=1 to y=5. stored colors can be retrieved using the colorget() function. there are 16 possible color bins, numbered 0 - 15 | |
| void colorset() | colorset(color_bin);
sets the colors for a specified color bin (0 - 15) using reserved
global variables _ymin, _ymax, _umin, _umax, _vmin, _vmax. int _ymin, _ymax, _umin, _umax, _vmin, _vmax; _ymin = 113; _ymax = 143; _umin = 75; _umax = 95; _vmin = 82; _vmax = 104; colorset(0); | |
| void colorget() | colorget(color_bin);
recovers the colors from a specified color bin (0 - 15) using same
format as colorset() with reserved global variables _ymin, _ymax,
_umin, _umax, _vmin, _vmax. int _ymin, _ymax, _umin, _umax, _vmin, _vmax; colorget(0); print(_ymin); print(_ymax); print(_umin); print(_umax); print(_vmin); print(_vmax); 113 143 75 95 82 104 | |
| void scan() | scan(colorbin); -
similar to the "vs" Scan function above, but uses matches specified
color (0 - 15) against surroundings to look for unblocked areas. the
image is divided into 3 overlapping regions, with reserved global
variables _x, _y and _z corresponding to left, center and right. if a
region is blocked, the value will be zero. if it is not blocked, the
value will be positive, with a higher number indicating more open space
in that region, e.g. int _x, _y, _z; imgcap(); scan(0); print(_x); /* left region */ print(_y); /* center region */ print(_z); /* right region */ might output 7 12 0 indicating that the right is blocked, but forward and left are both open | |
| int blob() | size = blob(colorbin); -
similar to the "vb" Blob function above, but only returns the largest
blob dimensions matching the specified color (0 - 15), using reserved
variables _x, _y and _z, where _x = centroid x coordinate, _y =
centroid y coordinate, _z = blob width. e.g. int _x, _y, _z; imgcap(); if (blob(0)) { print(_x); print(_y); print(_z); } which might output 40 30 15 for a blob centered at (40,30) with a width of 15 pixels a returned size of 0 would indicate that no matching blob was found | |
| void bitdir() | set data direction for i/o pins, 1=output, 0=input, xx = [0 0 0 E9 E10 E11 E12 E13], e.g. bitdir(3); /* E9 E10 E11 = input, E12 E13 = output */ | |
| void bitset() | write output levels for bits on i/o pins, 1=high, 0=low, xx = [0 0 0 E9 E10 E11 E12 E13] e.g. bitset(2); /* turn on pin E12 */ | |
| int bitget() | read levels of E9 E10 E11 E12 E13 in this order - [0 0 0 E9 E10 E11 E12 E13], e.g. int bits; bits = bitget(); | |
| Code sample using imgcap(), colorcap(), colorget(), scan(), print() and input() |
/* capture color sample for scan() function */ int _x, _y, _z, _ymin, _ymax, _umin, _umax, _vmin, _vmax; main() { int ix; imgcap(); colorcap(1, 30, 50, 1, 5); colorget(1); print(_ymin _ymax _umin _umax _vmin _vmax); do { imgcap(); scan(1); print("test" _x _y _z); ix = input(); } while (ix != 120); /* continue running until input = 'x' */ } | |
| Swarm Commands | ||
| 'r' | '##raa\n' | read robot ID bits (E8 E7 E6 E5) or pick a random robot ID number for swarm operation
'aa' is an 8-bit binary value that can't equal 0x00 or 0xFF. once robot ID is set, robot goes automatically into "swarm mode" and only processes '@' commands |
| 'R' | '##raa\n' | pick a different robot ID number (used if several robots picked duplicate random ID's)
'aa' is an 8-bit binary value that can't equal 0x00 or 0xFF |
| '@abc' | '#c or ##c...\n' | swarm mode command - only active after robot ID is set ('r' or 'R' commands)
ab = robot id, a=high digit, b=low digit, c=command, e.g. '@275' tells robot 27 to stop if ab = 'FF', command goes to all robots, e.g. '@FFw' tells all robots to enter "wander mode" response code is identical to non-swarm mode response for commands |