### Definition of the SRV-1 Control Protocol (Blackfin Version) - as of 17 October 2008

All commands from the host to the SRV-1 robot are comprised of ASCII characters or ASCII followed by 8-binary or ASCII decimal characters. 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 program with TCP / telnet capability. For example, you can connect using the 'netcat' command via 'nc 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 2 second delay after startup before the robot can accept any commands while the camera and other sensors are initialized - you should see the yellow LED's flash when the processor reboots. After startup, just to test that there is 2-way communication, send an 'V' to access the firmware version string. 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.
The firmware has two small interpreters - one is a prototype Lisp interpreter and the other is the Little C interpreter. The 'Q' command will execute the C program that has been stored in the robot's flash buffer. The 'P' command will run a Lisp program from the flash buffer, and the '!' command will run Lisp interactively, terminated with an ESC. The flash buffer can be set by the 'zr' command which transfers the contents of the user flash segment to the flash buffer, or via the 'X' command which transfers a file from the host via XMODEM protocol. Before executing a program, the contents of the flash buffer can be examined using 'zd'. When the program finishes (assuming the 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 |  |
except for 'q' command, all parameters are sent as 8-bit binary characters (0x00 - 0xFF) |  |
'7' | '#7' | note that keypad commands ('1' - '9') don't become active until an 'Mxxx' motor control command has been received 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
'+' | '#+' | increase motor/servo level
'-' | '#-' | decrease motor/servo level
'<' | '#<' | trim motor balance toward left
'>' | '#>' | trim motor balance toward right
'a' | '#a' | set capture resolution to 160x120
'b' | '#b' | set capture resolution to 320x240
'c' | '#c' | set capture resolution to 640x480
'd' or 'A' | '#A' | set capture resolution to 1280x1024
'E' |  | launches flash buffer line editor - (T)op (B)ottom (P)reviouse (N)ext line (L)ist (I)nsert until ESC (D)elete (H)elp (X)exit
'Fab' | '#F' | Enables Failsafe mode for motor control 'ab' parameters sent as 8-bit binary a = left motor/servo failsafe level, b = right motor/servo failsafe level. sets motor/servo levels for 'M' and 'S' commands in case no command is received via the radio link within 2 seconds.
'f' | '#f' | disables Failsafe mode
'g0' | '##g0' | grab reference frame and enable frame differencing
'g1' | '##g1' | enable color segmentation
'g2' | '##g2' | enable edge detection (threshold changed with 'T' command)
'G' | '#G' | disable frame differencing / color segmentation / edge detection
'h' | '#h' | switch serial channel to high baud rate (2500kbps)
'I' | '##IMJxs0s1s2s3....' | grab JPEG compressed video frame x = frame size in pixels: 1 = 80x64, 3 = 160x120, 5 = 320x240, 7 = 640x480, 9 = 1280x1024 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
'irab' | '##ir cc' | I2C register read ('ab' parameters sent as 8-bit binary) a is device id, b is register, cc is 8-bit return value from register displayed as decimal value
'iRab' | '##iR cc' | I2C register read ('ab' parameters sent as 8-bit binary) a is device id, b is register, cc is 16-bit return value from register displayed as decimal value
'iwabc' | '##iw' | I2C register write ('abc' parameters sent as 8-bit binary) a is device id, b is register, c is value written to register
'l' | '#l' | turn on lasers
'L' | '#L' | turn off lasers
'Mabc' | '#M' | direct motor control 'abc' parameters sent as 8-bit binary a=left speed, b=right speed, c=duration*10milliseconds speeds are 2's complement 8-bit binary values - 0x00 through 0x7F is forward, 0xFF through 0x81 is reverse, e.g. the decimal equivalent of 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)
'o' | '#o' | enable caption overlay
'O' | '#O' | disable caption overlay
'p' | '##ping xxxx xxxx xxxx xxxx\n' | ping ultrasonic ranging modules attached to pins 27, 28, 29, 30 with trigger on pin 18 - tested with Maxbotics EZ0 and EZ1 modules. xxxx return value is range in inches * 100 (2500 = 25 inches)
'qx' | '##quality x\n' | sets JPEG quality between 1-8 ('x' is an ASCII decimal character). 1 is highest, 8 is lowest
'Sab' | '#S' | direct servo control (TMR2 and TMR3) 'ab' parameters sent as 8-bit binary a=left servo setting (0x00-0x64), b=right servo setting (0x00-0x64) servo settings are 8-bit binary values, representing timing pulse widths ranging from 1ms to 2ms. 0x00 corresponds to a 1ms pulse, 0x64 corresponds to a 2ms pulse, and 0x32 is midrange with a 1.5ms pulse
'sab' | '#s' | direct servo control of 2nd bank of servos (TMR6 and TMR7) 'ab' parameters sent as 8-bit binary a=left servo setting (0x00-0x64), b=right servo setting (0x00-0x64) servo settings are 8-bit binary values, representing timing pulse widths ranging from 1ms to 2ms. 0x00 corresponds to a 1ms pulse, 0x64 corresponds to a 2ms pulse, and 0x32 is midrange with a 1.5ms pulse
't' | '##time - millisecs: xxxx\n' | outputs time in milliseconds since reset
'Tx' | '#T' | changes threshold in 'g2' edge detection - T4 is default, range is T1 to T9
'V' | '##Version ...\n' | read firmware version info response is terminated by newline character
'X' | '#Xmodem transfer count: bytes' | Xmodem-1K file transfer - receive file via xmodem protocol - store in flash buffer
'y' | '#y' | flip video capture (for use with upside-down camera)
'Y' | '#Y' | restore video capture to normal orientation
'zc' | '##zclear\n' | clear contents of flash buffer
'zC' | '##zCRC xxxx\n' | compute crc16_ccitt for flash buffer
'zd' | '##zd...\n' | flash buffer dump - dump contents of flash memory buffer to console
'zr' | '##zr\n' | flash memory read - read 65kb from user flash sector to flash buffer (e.g. read C program from flash sector before running C interpreter)
'zw' | '##zw\n' | flash memory write - write 65kb from flash buffer to user flash sector
'zZ' | '##zZ\n' | flash memory boot sector update - writes contents of flash buffer to boot sectors of flash memory - used to replace u-boot.ldr or srv1.ldr - checks first that a valid LDR format image is in the flash buffer
Special Commands |  |
'$!' |  | reset Blackfin
'$R' |  | SVS command - configures slave Blackfin to receive SPI transfer to flash buffer
'$X' |  | SVS command - configures master Blackfin to transfer contents of flash buffer via SPI
'x?' |  | SRV1-X menu
'xs' |  | SRV1-X setup
'xb' |  | SRV1-X boot loader
'xf' |  | SRV1-X flash
'xA' |  | SRV1-X dump analog data
'xG' |  | SRV1-X GPS
'xC' |  | SRV1-X console
Vision Commands |  |
all parameters are sent as ASCII decimal characters ('0' - '9') |  |
'vbc' | '##vbc x1 x2 y1 y2 ssss...\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 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.
'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 'vc3127176086111154200'. we could then confirm that the colors were properly stored by issuing the command 'vr3' to retrieve the contents of color bin #3.
'vh' | '##vhist y u v\n' | computes and lists the distribution of Y, U and V pixels over the entire range of possible values, divided into bins of 0-3, 4-7, 8-11, ... 248-251, 252-255
'vm' | '##vmean yy uu vv\n' | computes mean values for Y, U and V over the entire image.
'vnc' | '##vnc 01 02 03 ...\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.
'vpxxxxyyyy' | '##vp yyy uuu vvv\n' | the 'vp' command samples a single pixel defined by coordinates xxxx (column 0000-0159, 0000-0319, 0000-0639, 0000-1279 depending on resolution) and yy (row 0000-0127, 0000-0255, 0000-0511, 0000-1023, where 0000 is top of image). This is functionally equivalent to using the 'vg' command to sample of the range of 1 pixel, but somewhat less complicated to call. 'vp01600128' will sample a pixel in the middle of the image at 320x256 resolution, 'vp01600000' will sample a pixel in the middle of the top row, etc...
'vrc' | '##vrc y1 y2 u1 u2 v1 v2\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. '##vr0 127 176 86 111 154 200\n'.
'vzx' | '##vzero\n' | vz0 zeros out all of the color bins, vz1 / vz2 / vz3 / vz4 /vz5 segments colors into various color spaces which can be used by enabling 'g1' color segmentation function ('G' turns it off)
Lisp Commands |  |
'P' | execute Lisp from flash buffer | runs Lisp program stored in flash buffer, which got there via the 'zr' command (which reads user flash sector into flash buffer) or 'X' command (XMODEM file transfer). Lisp interpreter description and sample code found here - http://www.umcs.maine.edu/~chaitin/rov.html Current version of embedded Lisp code includes neither garbage collection nor any control functions for the robot, but these extensions are in development.
'!' | execute Lisp interactively | runs Lisp interactively from console; ESC character (0x1B) terminates interpreter and returns to main firmware control loop
C Language Commands |  |
'Q' | execute C program | runs C program stored in flash buffer, which got there via the 'E' line editor, the 'zr' command (which reads user flash sector into flash buffer) or 'X' command (XMODEM file transfer)
C primitives |  |
| assignments | a = b / 20; a = a - 0x55;
| 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 */
| 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); } } } }
| 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); } }
| if () ... else | int x; x = sonar(1); /* read sonar range */ if (x < 500) { motors(50, -50); /* if obstacle detected, turn right */ } else { motors(50, 50); }
| char input() | checks the serial port (radio channel) for a single incoming character. ch = input() /* if no data is found, ch = 0 */
| void print() | prints a set of strings and variables, followed by a newline ('\n'), e.g. print("hello"); print("test" x y z);
| while() while() ... do do ... while() | count = a; do { print(count); } while(count=count-1);
C - robot control/sense |  |
| void delay(milliseconds) | program delay in milliseconds, e.g. delay(500);
| int get(location) | pointer operation - gets int data from memory location int S; S = get(0x00100000); /* sets S from memory location 0x00100000 */ int S; int T = 0x00100000; S = get(T); /* sets S from memory location pointed to by T */
| void laser(on/off) | laser(1); turns on laser pointers, laser(0); turns them off
| void 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 rand() | returns a pseudo-random number between 0 and 65535
| int readi2c(channel, register) | same as 'ir' command - returns 8-bit value
| int readi2c2(channel, register) | same as 'iR' command - returns 16-bit value
| void servo(left, right) | sets left and right servo output, e.g. servo(50, 50); /* stop */ servo(25, 75); /* spin left */ servo(25, 25); /* go backwards */ servo(75, 75); /* go forward */
| void servo2(left, right) | same as servo() command, but supports a 2nd set of servos on timer ports 6 & 7
| int sonar(channel) | if sonar transducers are installed, returns measured range in channels 1-4. return value of 0 means there is no active transducer on that channel
| void set(location, value) | pointer operation - write int data to memory location set(0x00100000, 555); /* writes 555 to memory location 0x00100000 */ int S = 0x00100000; set(S, 555); /* writes 555 to memory location pointed to by S */ int T = 555; set(0x00100000, T); /* writes value of T to memory 0x00100000 */ int S=0x00100000; int T = 555; set(S, T); /* writes value of T to memory location pointed to by S */
| int time() | get current time (milliseconds since startup) - int t1; t1 = time();
| int writei2c(channel, register, value) | same as 'iw' command
C - robot vision |  |
| int blob(color, num) | size = blob(colorbin, blobnum); - similar to the "vb" Blob function above, but only returns the selected blob[blobnum] matching the specified color (0 - 9), using reserved variables x, y and z, where x = centroid x coordinate, y = centroid y coordinate, z = blob width. Note that calling blob() with blobnum=0 will compute a new blob search, but calling blob() with blobnum>0 will only retrieve previous located blobs rather than triggering a new search e.g. main() { int x, y, z; color(2, 100, 140, 90, 110, 130, 160); imgcap(); if (blob(2, 0)) { print("blob 0" x y z); } if (blob(2, 1)) { print("blob 1" x y z); } } which might output blob 0 40 30 15 blob 1 60 25 8 for one blob centered at (40,30) with a width of 15 pixels and another blob centered at (60,25) with a width of 8 pixels a returned size of 0 would indicate that no matching blob was found
| void color(bin, y0, y1, u0, u1, v0, v1) | sets the y, u, v color range for a color bin, e.g. color(0, 100, 140, 90, 110, 130, 160); would set color bin #0 with y ranging 100-140, u 90-110, v 130-160. functionally equivalent to 'vc' color set function, and results can be confirmed with 'vr' command
| void count(color) | similar to the "vn" color count function above, but divides the image into just 3 non-overlapping regions, with reserved variables x, y and z corresponding to the count of matching pixels in the left, center and right regions, e.g. main() { int x, y, z; color(0, 100, 140, 90, 110, 130, 160); imgcap(); count(0); print(x); /* left region */ print(y); /* center region */ print(z); /* right region */ } might output 15 85 40 that the center area has the largest number of matching pixels
| void imgcap() | captures image at default resolution
| void imgrcap() | captures and stores reference frame at default resolution
| void imgdiff(flag) | enables image differencing on captured images at default resolution. imgdiff(1) causes imgcap() to compute difference between latest captured frame and reference frame, imgdiff(0) turns off frame differencing
| void resolution('abcA') | changes capture resolution 'a' = 160x128, 'b' = 320x256, 'c' = 640x512, 'A' = 1280x1024
| void scaling(flag) | scaling(0) disables / scaling(1) enables - 80x64 image scaling in vision processing functions. If scaling is enabled, coordinates returned by vision are scaled to 80x64 pixel resolution
| void scan(color) | similar to the "vs" Scan function above, but uses matches specified color (0 - 9) 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. main() { int x, y, z; color(0, 100, 140, 90, 110, 130, 160); 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

last updated 17 October 2008 - 18:50 GMT