Adding analog inputs to BeagleBoard

Now that we can power our BeagleBoard through the expansion header (http://papermint-designs.com/community/node/223), it is time to go a step forward and power picoFlamingo on batteries. Using the expansion header we can easily include the batteries inside the case to power the system and keep it pretty small. But, what is still missing, is a way to make the system aware of the battery charge.

We would need some analog inputs to achieve that goal but, unfortunately, the BeagleBoard doesn't have this kind of inputs (BeagleBone users lucky you :). So we came up with the idea of using an ATtiny85 microcontroller for that purpose. The ATTiny85 is inexpensive, small, power efficient and easy to program, being perfect for our purposes.

We use Arduino as ISP to program the ATTiny85 following the well-known instructions from MIT Low-High Tech website (http://hlt.media.mit.edu/?p=1695). Just follow the instructions there and do not forget to change the delay(40) to delay(20) in the ArduinoISP sketch as the instructions says (that is for Arduino SW 1.0).

Arduino ISP setup to program ATTiny85Arduino ISP setup to program ATTiny85

The sketch we wrote was very simple. Read all the available analog inputs (3 for the ATtiny, actually they are 4 but we left AIN0 just in case we want to also transmit data through the serial port later on) and send the data through a SoftwareSerial channel. The idea is to use the UART02 on the expansion header to get the data in the Beagle (http://papermint-designs.com/community/node/218). In order to use the SoftwareSerial library, the ATTiny85 needs to run at 8MHz (no need of external oscillator tough). You can easily select this configuration from the Arduino IDE.

This is our final sketch:

#include 

#define rxPin 0
#define txPin 1

// We are only using the txPin right now
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);

void setup()  {

  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  mySerial.begin(9600);
}



void loop() { 
  int value1 = analogRead (1);
  int value2 = analogRead (2);
  int value3 = analogRead (3);

  mySerial.print ("A1:");  mySerial.print (value1);
  mySerial.print ("\tA2:"); mySerial.print (value2);
  mySerial.print ("\tA3:");  mySerial.println (value3);
  delay (50);
} 

So, the sketch sends data through a serial port with the following format:

A1:val1\tA2:val2\tA2:val3

We quickly tested the sketch with our FTDI Breakout Reloaded (http://papermint-designs.com/community/node/212) and minicom, getting the data as expected. Next step was to write a small application that reads data from the serial port, parses the string coming from the ucontroller and translates them into picoFlamingo useful commands. For that, we started with the great arduino-serial-c from this page (http://todbot.com/blog/2006/12/06/arduino-serial-c-code-to-talk-to-ardui...) and made a minimal modification to the code for the -r (continuous read) command line flag.

        case 'r':

	  while (1)
	    {
	      int r;
	      int a1, a2, a3;

	      memset (buf, 0, 256);
	      r = serialport_read_until(fd, buf, '\n');
	      fprintf (stderr, "VAL: %s -->", buf);

	      if (r >= 0)
		{
		  sscanf (buf, "A1:%d\tA2:%d\tA3:%d", &a1, &a2, &a3);
		  fprintf (stderr, "(%d)(%d)/%d)\n", a1, a2, a3);
	      
		  printf("SET_ROT model %f 0.0 0.0 \n", 
			 (float)a2 / 1024.0 * 3.1415 * 2);
                  if (a1 < 450)
                        printf ("UPDATE_TEXT val DARK (%d)\n", a1);
                  else
                        printf ("UPDATE_TEXT val BRIGHT (%d)\n", a1);
		}
	      fflush (0);
	      usleep (10000);
	    }
            break;
        }
    }

The change is very simple. Just read one line from the serial port, parse it with sscanf and send picoFlamingo commands to stdout so we can redirect them to picoFlamingo using netkitty (http://www.papermint-designs.com/dmo/prj-netkitty.html) or netcat. The commands sent rotate a 3D model named model and updates a text item named val.

During testing in the PC we experienced some "Resource unavailable" errors when reading from the serial port. We do not know yet what was the problem but it was solved with a small modification of the serialport_read_until function. These are the changes:

int serialport_read_until(int fd, char* buf, char until)
{
    char b[1];
    int i=0;
    do { 
        int n = read(fd, b, 1);  // read a char at a time
        if( n < 0) 
	  {
	    while (( n < 0 && errno == EAGAIN))
	      {
		usleep (10000);  // wait a little bit
		n = read(fd, b, 1);  // read a char at a time
	      }
	    if( n < 0 && errno != EAGAIN) 
	      {
		return -1;    // couldn't read
	      }
	  }
        if( n==0 ) {
	  usleep( 1 * 1000 ); // wait 10 msec try again
	  continue;
        }
        buf[i] = b[0]; i++;
    } while( b[0] != until );

    buf[i] = 0;  // null terminate the string
    return i;
}

So with those modifications we can just try our analog inputs. For the demonstration we had connected a potentiometer to analog input 1 and an LDR (Light Dependent Resistor) to analog input 2. The first one can be connected directly to the ATTiny (we used PIN 3 -AN1- in the ATtiny85). For the LDR we need a pull-up resistor. We used 10K but you may need to use a different value depending on the amount of light you want to detect. Here is a great tutorial on the topic (http://www.ladyada.net/learn/sensors/cds.html). This is a picture of the final setup:

BeagleBoard Analog Inputs test setupBeagleBoard Analog Inputs test setup

The final component is the picoFlamingo slide. For this test we added a 3D model we want to rotate using the potentiometer and a text we want to update when the light conditions detected by the LDR change. Something like this:

ADD_MODEL 3D5.3ds
NAME model
POSITION 0.0 0.0 -2.5
; A title on top of the slide
ADD_STEXT champb
NAME title
ADD_DATA BeagleBoard Analog Inputs
POSITION -2.5 2.0 -4.5
SCALE 120.0
COLOR 1.0 1.0 1.0 1.0
; The text item we want to update with light data
ADD_TEXT text03
NAME val
ADD_DATA Light Value
POSITION -2.5 1.2 -4.5
SCALE 100.0
COLOR 1.0 1.0 1.0 1.0
FX_START
set_focus model
generic_events 0
FX_END
; EOF

Now it is just a matter of launching picoFlamingo to open the slide above and then our modified version of the arduino-serial-c (which we had called mserial). The command line for mserial should be:

./mserial -p /dev/ttyO1 -r | nc localhost 5000

And this is the result:

Some final words.

First, you can use other uControllers with more capabilities and interface to them very easily through the BeagleBoard UART02. We could also use the I2C bus for the data interchange but that requires a logic-level translator. The serial port can be used for transmission with just two resistors.

Second, for our initial battery monitoring scenario we need a voltage reference. Fortunately the ATTiny85 provides two internal voltage reference 1.1V and 2.56V that should be used when reading battery voltage with an analog input. The internal references can be chosen with the function:

analogReference (INTERNAL);

This selects the 1.1V reference by default for the ATTiny85. The 2.65V is not supported in the Arduino IDE for this uController, however it can be activated using the number 3 as parameter for the analogReference function.

Finally, for battery monitoring it is not necessary to acquire data that fast. Probably, sampling the battery every minute would be enough. That would save a lot of power... I guess.... Now we just need to get a battery :)

Do not miss our other articles about the BeagleBoard expansion header:

* Beagleboard LEDs and Buttons (http://papermint-designs.com/community/node/205)
* BeagleBoard I2C. Interfacing to the WiiChuck (http://papermint-designs.com/community/node/210)
* BeagleBoard UART2. Interfacing to RFID reader ID-12 (http://papermint-designs.com/community/node/218)
* BeagleBoard to ID-12 Revisited. 1 Euro Interface (http://papermint-designs.com/community/node/220)
* Powering the BeagleBoard through the Expansion Header (http://papermint-designs.com/community/node/223)

cheers
The picoFlamingo Team

Comments

At tiny power

It looks like you have a separate rail powering the 85 there. Is it a 5v or 3.3 v? The data sheet seems to indicate you could use 3.3v. Thanks for the idea here though. I'm putting a beagleboard into a dog shaped robot.

5V from Beagleboard

I'm using the 5V pin from the BeagleBoard header connector to power the tiny, as that was the easier and more straightforward way. I'm also aiming for 3.3V (less power) but I had not tried yet. Just remember that when powering with 3.3V that is your maximum level for the ADC pin...

A dog shaped robot sound very interesting... Is there a website to follow the project?

cheers