Hacking the Fluke
From IPRE Wiki
The Fluke sits between software running the Myro API and a robot. In fact, you can talk to a robot (such as the Scribbler) directly. Some of the following byte codes can be used without the Fluke, as they are Scribbler commands. If using the Fluke, it will intercept any byte-code commands that it knows about, and will return appropriate responses. However, if the Fluke does not know the byte-code, it will pass it on to the Scribbler, and relay its response---thereby acting as a wireless serial cable. The Fluke handles camera commands, obstacle commands, and brightness commands. The Scribbler handles everything else (sounds, movement, IR, battery, etc). Commands such as DATA are handled by both: a DATA requested is made by the Myro API software, received by the Fluke, passed to the Scribbler, responded by the Scribbler to the Fluke, to which the Fluke adds some data and passes it back to the host Myro API software.
Contents |
Fluke
The Fluke is a small electronic board that contains wireless Bluetooth, camera, IR (infrared) sensors, LEDs (light emitting diodes) and an ARM microprocessor. By itself (with a battery), it is a complete (although immobile) robot that can receive simple commands and send back IR readings, camera images, and turn on its LED lights. Connect it to a robot and you can control the robot wirelessly, and add vision and sensors to it. More on the prototyping of the fluke can be found here.
This page is designed to get you started in exploring the advanced capabilities of the Fluke.
You can purchase a Fluke at Georgia Robotics.
Fluke Software
The Fluke has easy to use software built into Myro, using Python, for the Scribbler robot from Parallax. This page describes how to write your own software, and use it for robots other than the Scribbler.
The Byte Codes
The Fluke (and underlying robots) are controlled through sending byte codes, or messages. The interface is used in the following files:
The byte-codes are:
#SCRIBBLER-SPECIFIC
SOFT_RESET=33
GET_ALL=65
GET_ALL_BINARY=66
GET_LIGHT_LEFT=67
GET_LIGHT_CENTER=68
GET_LIGHT_RIGHT=69
GET_LIGHT_ALL=70
GET_IR_LEFT=71
GET_IR_RIGHT=72
GET_IR_ALL=73
GET_LINE_LEFT=74
GET_LINE_RIGHT=75
GET_LINE_ALL=76
GET_STATE=77
GET_NAME1=78
GET_NAME2=64
GET_STALL=79
GET_INFO=80
GET_DATA=81
GET_PASS1=50
GET_PASS2=51
#FLUKE-SPECIFIC
GET_RLE=82 # a segmented and run-length encoded image
GET_IMAGE=83 # the entire 256 x 192 image in YUYV format
GET_WINDOW=84 # the windowed image (followed by which window)
GET_DONGLE_L_IR=85 # number of returned pulses when left emitter is turned on
GET_DONGLE_C_IR=86 # number of returned pulses when center emitter is turned on
GET_DONGLE_R_IR=87 # number of returned pulses when right emitter is turned on
GET_WINDOW_LIGHT=88 # average intensity in the user defined region
GET_BATTERY=89 # battery voltage
GET_SERIAL_MEM=90 # with the address returns the value in serial memory
GET_SCRIB_PROGRAM=91 # with offset, returns the scribbler program buffer
GET_CAM_PARAM=92 # with address, returns the camera parameter at that address
GET_BLOB=95
#SCRIBBLER-SPECIFIC
SET_PASS1=55
SET_PASS2=56
SET_SINGLE_DATA=96
SET_DATA=97
SET_ECHO_MODE=98
SET_LED_LEFT_ON=99
SET_LED_LEFT_OFF=100
SET_LED_CENTER_ON=101
SET_LED_CENTER_OFF=102
SET_LED_RIGHT_ON=103
SET_LED_RIGHT_OFF=104
SET_LED_ALL_ON=105
SET_LED_ALL_OFF=106
SET_LED_ALL=107
SET_MOTORS_OFF=108
SET_MOTORS=109
SET_NAME1=110
SET_NAME2=119 # set name2 byte
SET_LOUD=111
SET_QUIET=112
SET_SPEAKER=113
SET_SPEAKER_2=114
#FLUKE-SPECIFIC
SET_DONGLE_LED_ON=116 # turn binary dongle led on
SET_DONGLE_LED_OFF=117 # turn binary dongle led off
SET_RLE=118 # set rle parameters
SET_DONGLE_IR=120 # set dongle IR power
SET_SERIAL_MEM=121 # set serial memory byte
SET_SCRIB_PROGRAM=122 # set scribbler program memory byte
SET_START_PROGRAM=123 # initiate scribbler programming process
SET_RESET_SCRIBBLER=124 # hard reset scribbler
SET_SERIAL_ERASE=125 # erase serial memory
SET_DIMMER_LED=126 # set dimmer led
SET_WINDOW=127 # set user defined window
SET_FORWARDNESS=128 # set direction of scribbler
SET_WHITE_BALANCE=129 # turn on white balance on camera
SET_NO_WHITE_BALANCE=130 # diable white balance on camera (default)
SET_CAM_PARAM=131 # with address and value, sets the camera parameter at that address
GET_JPEG_GRAY_HEADER=135
GET_JPEG_GRAY_SCAN=136
GET_JPEG_COLOR_HEADER=137
GET_JPEG_COLOR_SCAN=138
To send a message to the Scribbler, you need to put the byte into 9-byte packet, however if the command is for the Fluke, the packet will be variable length.
For example, to get the battery voltage from the Fluke, you would send the number 89 as a byte. You can test this in any language or system, including something like Hyperterm. Here is this example in Python:
>>> import serial
>>> ser = serial.Serial("COM1", 57600)
>>> ser.write(chr(89))
>>> bytes = ser.inWaiting()
>>> battery_level = ser.read(bytes)
You will need to interpret the results. For example, see the function getBattery in the Python Interface.
Or to set the IR power to full-power:
>>> import serial
>>> ser = serial.Serial("COM1", 57600)
>>> ser.write(chr(120))
>>> ser.write(chr(255))
More detail on using the Fluke on other robots can be found below.
Building the Fluke Firwmare
Firmware is another name for the software running on an "embedded system", like the Fluke. The firmware is usually written and compiled on one computer, and then transfered to the Fluke.
When you compile a program on one computer for use on another, that is called "cross-compiling" and requires a special environment and tools (often called a "toolchain"). The toolchain can be installed on Fedora9 with:
yum install arm-gp2x-linux-binutils arm-gp2x-linux-gcc
NOTE: the current arm-elf cross-compiler version 4.1.2 seems to have a bug:
/usr/lib/gcc/arm-gp2x-linux/4.1.2//libgcc.a(_dvmd_lnx.o): In function `__div0': ../../gcc-4.1.2/gcc/config/arm/lib1funcs.asm:1000: undefined reference to `raise'
The arm-elf cross-compiler version 4.1.1 seems to work fine, but you must install from source code. As root:
wget http://www.gnuarm.com/binutils-2.17.tar.bz2 bzip2 -d binutils-2.17.tar.bz2 tar -xf binutils-2.17.tar cd binutils-2.17 ./configure --target=arm-elf --prefix=/usr/local/arm-elf/ --enable-interwork --enable-multilib \ --enable-languages="c,c++" --disable-werror make all make install export PATH=$PATH:/usr/local/arm-elf/bin cd .. wget http://www.gnuarm.com/newlib-1.14.0.tar.gz tar xfz newlib-1.14.0.tar.gz wget http://www.gnuarm.com/gcc-4.1.1.tar.bz2 bzip2 -d gcc-4.1.1.tar.bz2 tar -xf gcc-4.1.1.tar cd gcc-4.1.1 ./configure --target=arm-elf --prefix=/usr/local/arm-elf/ --enable-interwork --enable-multilib \ --enable-languages="c,c++" --with-newlib --with-headers=../newlib-1.14.0/newlib/libc/include make all-gcc make install-gcc cd .. ln -s /usr/local/arm-elf/bin/arm-elf-gcc /usr/local/arm-elf/bin/arm-elf-cc cd newlib-1.14.0 ./configure --target=arm-elf --prefix=/usr/local/arm-elf/ --enable-interwork --enable-multilib # edit Makefile and change MAKEINFO to be path to makeinfo (ie, /usr/bin/makeinfo) make make install
All the fluke firmware can be found in the myro SVN repository. You can get it with:
svn export http://svn.cs.brynmawr.edu/Myro/trunk/Fluke
The SVN repository also has datasheets for the different parts on the board and other supporting tools.
The IPRE Fluke uses the LPC2106 ARM microcontroller from Phillips. We use the GNU ARM toolchain for development.
After you have installed arm gcc and downloaded fluke firmware, you'll probably have to change the Makefile to set the LIBGCC variable to point to the correct location of where libgcc.a is located. For example:
LIBGCC=-L/usr/local/arm/lib/gcc/arm-elf/4.1.1/ -lgcc
Next, you can set the PATH and compile the code:
export PATH=/usr/local/arm/bin make
Then you download the firmware over bluetooth using:
make dl2 # will run: # python update-firmware.py main.hex /dev/tty.scribbler5844 fast
Or download the firmware using a null modem serial cable. Use the IPRE version of the lpc21isp program to upload new code using the serial link (see below for binary and more info). When upgrading the firmware using the null modem cable a separate power cable will be necessary. Either using a 9 volt battery or a wall adapter (6-9 volts).
make dl # will run: # lpc21isp2 -control main.hex /dev/tty.usbserial 19200 20000)
To run plug into the scribbler or use external power connector and:
python >>> from myro import * >>> init()
Resources
- lpc21isp
- windows binary: http://myro.roboteducation.org/packages/lpc21isp-ipre-win.zip
- linux binary: Media:Lpc21isp.bin
- source: http://www.roboteducation.org/files/lpc21isp-ipre.c
- http://wiki.roboteducation.org/IPRE_Fluke_Setup
- http://wiki.roboteducation.org/DongleDetails
Building an External Power Connector
The Fluke is normally powered over the serial port of the scribbler (pin 8), but it can also be powered by an external power source (e.g. a 9V battery). The external power plugs into the 2 pin white external conector housing near the bottom of the board (below the 2 5-pin connectors). The bottom pin is ground. Part list:
- 2 pos connector housing - digikey: 455-1486-ND manufacturer: PAP-02V-S
- connector crimp terminal - digikey: 455-1325-1-ND manufacturer: SPHD-001T-P0.5
- wall transformer - digikey: T978-P7P-ND manufacturer: EPS060100-P7P
Serial Connection
The Fluke was designed to be connected to a Scribbler or PC serial port so its using PC style RS232 voltages (+/- 12V) rather than TTY (5V). The RTS/CTS pins 6 and 8 are inverted and used for programming not synchronization (since there is no RTS/CTS on the scribbler we decided to do this).
A nice USB/serial adapter (works great on mac, some others don't work so well):
http://www.newegg.com/Product/Product.aspx?Item=N82E16812156009
A female-female RS232 null modem adapter:
http://www.winfordeng.com/products/mgcnm.php
By default the Fluke talks to the underlying robot at 38400 baud, 8N1, but this can be changed in the firmware, or via a dynamic command. You can talk to the Fluke over Bluetooth at up to 460800 baud.
Pin 1: Reset (inverted) Pin 2: Receive Pin 3: Transmit Pin 4: Scribbler Reset Pin 5: Ground Pin 6: Reset (inverted) Pin 7: Not Connected Pin 8: Boot Mode (inverted) and Power Pin 9: Not Connected
Passthrough Code
There are six Fluke commands related to controlling the underlying device/robot:
- put the fluke in complete passthrough mode
- send N bytes through the Fluke to the robot
- get N bytes back from the robot
- get bytes back from robot until ending byte
- turn on passthrough so the underlying robot can send data back over the Bluetooth
- turn off passthrough so the underlying robot no longer sends data back over the Bluetooth
You can get the latest firmware (main.hex) from SVN at http://svn.cs.brynmawr.edu/Myro/trunk/Fluke/firmware/.
The codes (from ipre-bytecodes.h) are:
#define SET_PASSTHROUGH 134 #define SET_PASS_N_BYTES 139 #define GET_PASS_N_BYTES 140 #define GET_PASS_BYTES_UNTIL 141 #define SET_PASSTHROUGH_ON 143 #define SET_PASSTHROUGH_OFF 144
Loading Firmware onto Fluke
To load via Bluetooth using Myro:
- Save main.hex in directory
- Start python and upload:
- $ python
- >>> from myro import *
- >>> upgrade_fluke("main.hex")
- give Bluetooth device name (eg, /dev/rfcomm2, /dev/usbserial0, com5, etc)
or via a cable, from the terminal/console:
$ PORT=/dev/ttyS0 make download
or from any operating system:
Windows: lpc21isp -control main.hex COM1 19200 20000 Unix: ./lpc21isp -control main.hex /dev/ttyS0 19200 20000
On Unix, replace ttyS0 with your serial port's device name.
Testing
To test, using Myro Python library (needs Myro 2.8.3 or higher):
$ python
>>> from myro.robots.fluke import Fluke
>>> robot = Fluke("/dev/rfcomm2")
You should see a fluke version number echoed to the screen. If you don't then turn the fluke off and then back on, and try making the connection again (last line). Once you see a version number, you are ready to continue.
If you use Myro's Fluke interface, the serial port is robot.ser. All of the following should work talking directory to the serial port. The Fluke interface has all of the built-in functions for talking to the Fluke directly (such as processing the images from the camera).
If you are not using Myro, you can just open a serial connection to the fluke and send it the bytecode for returning the version number. Here, using pyserial in Python:
>>> import serial
>>> ser = serial.Serial("COM1", 57600)
>>> ser.write(chr(142)) # get fluke version
>>> ser.inWaiting()
# responds with number of bytes ready to read
>>> ser.readline()
NOTE: On Windows, for COM ports greater than 9, you must use a format that looks like: r"\\.\COM11" (which is COM11)
You can ser.close() and ser.open() to close and reopen the port.
Fluke Functions
To send N bytes to the underlying robot (in this example, a Scribbler):
>>> import serial
>>> ser = serial.Serial("COM1", 57600)
>>> ser.write(chr(143)) # turn on passthrough from the robot
>>> ser.write("".join(map(chr, [139, N, N1, ...]))) # send N bytes (N1, N2, ..., NN)
>>> ser.inWaiting()
20
>>> ser.read(20)
>>> ser.write(chr(144)) # turn off passthrough from the robot
When talking to the Scribbler, this will automatically give you 20 bytes back: 9 for the packet echo, and 11 for all sensors values.
If you want to read a particular number of bytes back:
>>> ser.write("".join(map(chr, [140, N]))) # read N bytes
>>> ser.inWaiting()
# should echo back N
>>> ser.read(N) # read the bytes
Or until a certain character:
>>> ser.write(chr(141) + "\n"]) # read until newline >>> ser.readline()
To change the baud rate between the Fluke and the 9-pin UART (not the PC to Bluetooth connection) then there is a command for that:
#define SET_UART0 132
This takes a magic code (1), and three parameters, given in order by the following codes.
First, the baud rate:
#define NB1200 0 #define NB2400 1 #define NB4800 2 #define NB9600 3 #define NB19200 4 #define NB38400 5 #define NB57600 6 #define NB115200 7 #define NB230400 8 #define NB460800 9 #define NB921600 10 #define NB1843200 11 #define NB3686400 12
Second, the bit settings:
#define NUART_8N1 0 #define NUART_7N1 1 #define NUART_8N2 2 #define NUART_7N2 3 #define NUART_8E1 4 #define NUART_7E1 5 #define NUART_8E2 6 #define NUART_7E2 7 #define NUART_8O1 8 #define NUART_7O1 9 #define NUART_8O2 10 #define NUART_7O2 11
and last the FIFO setting:
#define NUART_FIFO_OFF 0 #define NUART_FIFO_1 1 #define NUART_FIFO_4 2 #define NUART_FIFO_8 3 #define NUART_FIFO_14 4
So, to set the Fluke-to-robot baud rate to 1200 baud, 8N1, with FIFO off, send this:
>>> ser.write( chr(132) + chr(1) + chr(0) + chr(0) + chr(0))
To set the Fluke-to-robot baud rate to 57600 baud, 7N2, with FIFO 8, send this:
>>> ser.write( chr(132) + chr(1) + chr(6) + chr(3) + chr(3))
Fluke Projects
The Fluke as the head of a Robonova:
The Fluke on the Roomba:
The Fluke on the Tevbot:



