Friday, May 28, 2010

Orangutan LV168, Bluetooth, BlueSMiRF

I'm still taking baby steps towards equipping Pokey's ATmega168-based Orangutan LV168 with a BlueSMiRF bluetooth modem. By the end of this article the foundation will be laid for telemetry/data collection for troubleshooting.  Not to mention command/control and image capture which I have planned after the firefighting competition is done.

Step 6: ATMega168 MCU Serial Communication

Having achieved success with the Basic STAMP, it was time to switch over to the final platform, Pokey's Orangutan LV168 board with an ATmega168 microcontroller.  The older orangutan-lib library from Pololu includes some routines for serial communications over the 168's PD0 and PD1 pins. (Incidentally, Pololu now provides the Pololu AVR C/C++ Library).  Thanks to the LEDs on the level shifter, I was quickly able to diagnose an issue and establish communications between the PC and the Orangutan. First I got the 'tan to send data to the PC.

The Orangutan LV168 says hello

Then I set up character-based echo with the following C program (some details are omitted here):

#include "util.h"
#include "uart.h"

int main()
  uint8_t c;

  uartInit();                // initialize UART (serial port)
  uartSetBaudRate(9600);        // set UART speed to 9600 baud

  while (1) {

    if (uartReceiveByte(&c)) {

    //sleep for a bit
  } // for

  return 0;
} // main

Line-at-a-time echo, like I did with the BS2, didn't work at first.  The orangutan-lib uart code is interrupt driven, working in the background, while the BS2 command only completes after data is sent (or the timeout is reached). So, on the '168, you set up the receive first, specifying a buffer and a flag, then wait for the flag to get set, then you can look at the buffer.  Only after that can you call the receive function again.   Here's the code:
  uartInit();                // initialize UART (serial port)
  uartSetBaudRate(9600);        // set UART speed to 9600 baud
  uint8_t recvBuf[32];
  uint16_t rxBytes=0;
  uint8_t recvflag=0;
  uint8_t flag=0;
  uint8_t done='\r';

  while (1) {
    // setup to receive data
    uartReceiveBuffer(recvBuf, 15, &rxBytes, done, &recvflag); // set up receive

    while (!recvflag) {

      //sleep for a bit
    } //while

    if (recvflag) {
      // echo back what we got
      uartSendBuffer(recvBuf, rxBytes, &flag);

  } //while 

Step 6: ATMega168 MCU BlueSMiRF Communication

It was now time to leap forward to establish communication between the Mac application and the Orangutan LV168 over bluetooth.  One thing I haven't mentioned is that one has to get the TX and RX lines right and that this can be tricky depending on what type of components you're dealing with.

Some devices, like PCs and MCUs transmit on their TX line and receive on their RX line as you'd expect. Other equipment like modems, label their lines with respect to the computer talking to them. They receive data from a PC on the PC's TX line and send data back to the PC on its RX line.

In RS-232 speak, the modems are called Data Communications Equipment (DCE) while computers or terminals like the PC or MCU are called Data Terminal Equipment (DTE)

So if you have a DTE connected to a DCE, just connect TX to TX and RX to RX. If you are trying to get two DTEs to talk, connect TX to RX and RX to TX. 

You've heard of a null modem cable?  That's what it does, swaps the TX and RX lines (among other things)

The BlueSMiRF acts as a DCE and the AVR MCU acts as a DTE. So you just use a straight cable. (I later found out that my Sparkfun FTDI breakout board also acts like a DTE).

At any rate, I implemented code on the MCU to send the +++ and AT+BTSRV=1 commands prior to performing the line-by-line echo (note that I'm not verifying the receipt of the "OK" message sent by the modem; I'll do that later).

  strcpy((char *) buf, "+++");
  uartSendBuffer(buf, strlen((char *) buf), &flag);

  // AT+BTSRV=1
  strcpy((char *) buf, "AT+BTSRV=1\r\n");
  uartSendBuffer(buf, strlen((char *) buf), &flag);

I connected the BlueSMiRF to the MCU fired everything up and was able to connect. The Mac application successfully sent data and displayed the echo sent back by the MCU.  Right on!  With the baby steps finally done, next up is controlling the robot from the Mac.


Pokey's DIY Serial PCB

I since put together a simple breakout board for serial communications with the LV168.  The board accepts either the BlueSMiRF modem, or my Sparkfun FTDI 5V breakout board so I can go wired or wireless. 

I tossed a couple of LEDs on the board to indicate data transmit and receive.  Although my DIY "silkscreen" layer was severely cockeyed and though I goofed up the schematic and had to hack the board, I'm pretty happy with the results. This is my smallest PCB to date at only 1.00" x 0.75" ! :)

Friday, May 21, 2010

Simple Serial Mac AppleScript App

I'm working towards getting AVR-powered Pokey equipped with a bluetooth modem.  While working on prototyping communications using the BASIC Stamp 2, I needed a simple, line-at-a-time serial communications application on my MacBook.

Having recently finished playing with Xcode and AppleScript I decided to write the comm program this way, too. Eventually this application will be evolved to gather telemetry data and send remote commands.

Incidentally, serial communications isn't native to AppleScript so I chose Serialport X to extend AppleScript for serial communications.

The AppleScript application interface consists of a pulldown menu to select a serial device to use, a button to connect to (and disconnect from) the serial device, a status indicator, a text field for data received, and a text field and send button to send data.  The GUI enforces basic, state-driven behavior by enabling and disabling objects on the interface based on the connection state.

Connecting to BlueSMiRF serial port

So in other words, you can't connect until you've selected a device.  Once you are connected, you can't pick a new device.  If you're disconnected the button is labeled "Connect" and clicking it connects to the selected device.  If you're connected the button is renamed "Disconnect" and clicking it disconnects.  Likewise, the send button and text fields are controlled by connection state. Here's a state diagram that covers the device selection and connect/disconnect button.

State Diagram of  Serial Comm App

With the first incarnation of the AppleScript app, I was able to successfully connect to the BlueSMiRF through the MacBook bluetooth transciever, receive, and display data from the BS2.  The second incarnation permitted two-way communications.

Here's the version of the source code as of this writing:

So with the Mac and BS2 communicating back and forth, it was time to get the ATmega168 on the Orangutan LV168 controller board talking through the BlueSMiRF to the Mac serial program I wrote.

To be Continued...

Friday, May 14, 2010

BASIC Stamp, Bluetooth, BlueSMiRF

About a year ago, I bought a BlueSMiRF Silver bluetooth modem from SparkFun Electronics so I could equip my robot, Pokey, with the ability to send telemetry data for troubleshooting.

Over the past year, the bluetooth module has been sitting on the shelf, collecting dust, and judging me harshly for not using it.  I couldn't take the disapproval any longer--and there's the firefighting competition coming up--so I decided to get the thing working.

The next few articles will detail all the baby steps to getting this going.  Along the way I'll provide a smorgasbord of information -- plus code -- for getting this working on various platforms: MCUs, PC, and Mac.

Step 1: Establish Communications With MacBook

After soldering on a 6 pin header, I plugged it into my Basic STAMP 2 prototyping board (that came with the book, 123 Robotics Experiments for the Evil Genius) and powered it up with 5V to test connectivity with my MacBook's built in bluetooth transceiver. Et voila, it worked.

BlueSMiRF Silver on BS2 protoboard

The BS2 is a great tool for rapidly testing and prototyping microcontroller projects, like this one.  Many tasks become ridiculously simple, like serial communication. But, I had no joy trying to get the BS2 to communicate with the BlueSMiRF. I decided to come back to this part later. 

Step 2: Communicate with BlueSMiRF Using PC

To talk to the BlueSMiRF, connect to it over COM1, using the BS2's serial DB9 cable and using HyperTerminal on the PC (I later found out that I like Termite a lot better). But first, one needs an RS-232 to TTL level shifter, like the one Sparkfun sells. Being cheap and impatient, I decided to make my own.  Once I had this impromptu device built and working, the PC was communicating with the BlueSMiRF.  Yay!

Eureka! The PC can talk to the BlueSMiRF!

The next trick was to use the BlueSMiRF to enable my PC to talk back and forth with my MacBook.  Using ZTerm on the Mac and HyperTerminal on the PC talking through the level shifter to the BlueSMiRF, the two could communicate. Shazam!

Step 3: Communicate Between BS2 Microcontroller and MacBook

After getting some basic bluetooth communication working, next up was coercing the BS2 to communicate with my MacBook using the BlueSMiRF Silver.  It took a few code tweaks but eventually I could use Zterm on the Mac to successfully send data to the BS2.  The key was selecting the correct communications mode (9600 bps inverted vs. non-inverted).  Here's the code:

mytext VAR Byte

loop: SERIN 14,84,[mytext]
      DEBUG mytext
      GOTO loop

Sending data from the BS2 to the MacBook went very well, too.

loop: SEROUT 14,84,["hello world",10,13]
      GOTO loop

I was having a hard time getting the BS2 to force the bluetooth modem into config mode (via escape sequence "+++"), recognize it was in that mode, configure the modem, and return to data mode. This turned out to simply be a question of sending the correct line termination (carriage return, ASCII 13 / 0x0D) at the end of AT commands.

To find out what was going on, I set up the RS-232-to-TTL level shifter as a serial sniffer. To see what the BlueSMiRF was receiving, I connected its receive (RX) pin to the level shifter/PC RX pin with a 22K resistor.  Switch the resistor to see the other side of the conversation.  To see both at once, at TTL levels, ... well, I'm not sure. I'll have to get back to you on the best way to do that.

I finally got the line termination and wait commands (to wait for specific text) worked out. Here's the code.


DEBUG "trying to enter config mode",13

'baudmode 84 is 9600,8,N,1 inverted
SEROUT 1,84,200,["+++"]

'wait for "OK" response from modem"
SERIN 0,84,[WAIT("OK",13)] 

'13 = CR = Carriage Return, \r, 0x10
DEBUG "config mode",13     

'get modem version info
SEROUT 1,84,["ATI",13]     
SERIN 0,84,[WAIT("OK",13)]
DEBUG "done",13
'server mode, channel 1
SEROUT 1,84,["AT+BTSRV=1",13]
DEBUG "server mode",13

I took the serial communications a baby step farther, programming the BS2 to receive and echo a whole string of text at once, terminated by a carriage return. I played around with timeouts, and use of the SERIN WAIT modifier to wait for specific text strings before continuing.

' {$STAMP BS2}
' {$PORT COM1}
string VAR Byte(16)

      ' stop reading at 15 chars or CR (0x10); 3sec timeout
loop: SERIN 0,84,3000,idle,[STR string\15\CR] 
      ' echo back the entire string
      SEROUT 1,84,[STR string,CR]             
      ' send string to debug window on PC
      DEBUG STR string,CR                    
      GOTO loop                             
      ' timeout means no strings waiting
idle: DEBUG "."                              
      GOTO loop

Step 4: Two-Way Communication with BS2

Prototyping two way communication was next, in anticipation of needing a query/response protocol for exchanging data and commands with the robot.  I wrote a simple AppleScript application to do line-by-line two way communications (I'll write about that in the next article). Once completed, the application successfully sent data to the BS2 over bluetooth and displayed the echo response from the BS2 on the screen.

Line by line echo from BS2

To be continued...

Friday, May 7, 2010

Vision-Based Candle Detection

Updated 9/9/2010: Source Code is now available on Google Code.

The Cliffhanger

Having previously interfaced a Game Boy camera to an AVR (Ardweeny / ATmega328P) and successfully capturing an image, the next step in detecting a candle flame was, well, detecting the candle flame.

Would the camera be able to capture an image of a distant flame? Would an IR filter work to block out everything but a source of flame?

For that matter, the flame detection software hadn't been tried on an actual Game Boy image yet. And the code hadn't been ported to the memory-constrained AVR yet either.

IR Candle Detection

Using exposed film as an IR filter I got good image results for a distant candle, below, sitting about 170cm from the lens, a typical distance in the real competition. The candle flame is left of center. The center bright spot is the candle's reflection in a glass-covered picture hanging on the wall (but, in the competition, mirrors cannot be placed in the same room as the candle).

The captured image

I added a feature to the client software allowing me to save the captured picture to a file on the PC. Then I processed it into a BMP that my prototype flame detection program could read, and the program it spit out the data for the real candle. It worked!

The detected object

Running Detection Code on the AVR

The flame detection software would have to run on the robot so I redesigned the code to fit into the tiny 2K of RAM on the ATmega328P.

Recall that the software essentially performs a flood fill on every pixel brighter than a set threshold. Since it's only purpose is to spit out a set of bounding boxes around detected objects, it really doesn't need to remember the entire image or the flood fills (assignment of pixels to objects) already performed, just the object assignment for the current and prior rows' pixels, from which it can calculate the bounding boxes.

Code Details

The only reason the code needs to remember the prior row is to know if the pixel above the current pixel belongs to an object. Like so:

.. .. 01 01 01 .. .. 02 02 .. 03 03 03
01 01 01 01 01 .. .. 02 02 .. .. 03 ..

It turns out that we never need to look more than one row above, so we only need to keep two rows of object assignments. That's an array of 2 rows, and (in the case of the Game Boy camera) 128 columns.

With the added bonus that we can use a simple XOR operation to toggle back and forth between the two rows: the first time through, row 0 is current, row 1 is previous and the next time through, row 1 is current, row 0 is previous.

Here's the excerpted AVR C code that does the "flood fill".

For what it's worth all the camera and object detection code is just over 4K in size so there's no reason it wouldn't fit in a lower-end AVR.

The Results

Forgetting to take baby steps in program re-factoring, the first attempt was a disaster. The second attempt, however, wasn't.  I revised the client code to receive and display the bounding boxes in bright green...

Target Flame Acquired! Distance 185cm

Target distance 100cm

Detection worked well even without the IR filter.  With the filter, object detection will probably be more reliable. You'll notice some extraneous objects detected.  One is the candle's reflection in a glass holding the remains of an iced latte I made.  The other is... a reflection off the computer mouse, I think?  Of what, I don't know.

The vision-based detection has come along really nicely.  It's pretty darned close to usable right now. Without too much more work, I could hook up Pokey's Orangutan controller to the Ardweeny and it could request and retrieve detected objects and then do something with them.

What's Next?

One of the concepts in iterative development is to focus on solving the hard problems first and leave refinement and easy features for later.  I think that makes a lot of sense so I'm going to put the flame detection on the back burner and work on fixing Pokey's navigation problems.

But you won't hear about that for awhile. Instead, the next few articles will share the steps involved in proving out how to equip Pokey with a Bluetooth modem.

Updated 9/9/2010: Source Code is now available on Google Code.

Thursday, May 6, 2010

Working with Vacuum Tubes

I've got an update for you on the vision system cliffhanger... tomorrow.

Today, let's talk about vacuum tubes.  In need of a bit of a break from robotics, I decided to tackle troubleshooting my Knight KG-250 vacuum tube (valve) amplifier.

With a new set of "Winged C" Russian 6Ф3П (6F3P) output tubes installed (equivalent to the stock 6BM8 tubes), I fired it up and... oh no!  Red plating!  That's bad!

6F3P vacuum tube very similar to 6BM8

What the heck is red plating you may ask?  It's simply thermal overload of a tube, manifested visually. Being housed in glass, you can see the guts of vacuum tubes. The guts are metal: plate (anode), grid, and cathode. When too much current is drawn through the tube than can be dissipated, the metal parts get very hot. Red hot. Literally dull cherry red hot. The visible, outer plate glows red. Hence, red plating. That much heat reduces the tube's lifespan significantly.

Being a solid state kind of guy, the world of vacuum tubes is a little bit foreign but somewhat familiar, too. We know about anodes and cathodes from solid state diodes. And we can understand your basic tube as roughly analogous to a Junction Field Effect Transistor (JFET). Voltage controls the current flow. And there are still resistors and capacitors in the circuits. Basic electrical troubleshooting still applies. But there's a twist. Most of the old tube gear uses point to point wiring, rather than printed circuit boards.

The machine had been previously refurbished, with new capacitors and resistors on the power supply and amplifier circuits. So verifying the wiring of components to the output tube sockets was the first troubleshooting task and it immediately revealed several big wiring errors.  Once fixed, the little amplifier powered up and played music -- no redplating! Yay!

 Knight KG-250 fed by iPod and CD Player

Next up in the fixit queue is my old home theater receiver. It's been broken for years and I figured it was about time I dive in and either fix it or give up and strip it for parts. Robot parts, most likely. :)