Amazon Banner

Monday, March 18, 2013

Cacheberry Pi

As an avid Geocacher, when I was thinking of what to do with my Raspberry Pi, I couldn't help but wonder what geocaching related devices I could make.  I considered building a geocache that had some kind of electronics, controlled by the Pi, but decided that powering the Pi long term would be an issue.  I searched for other ideas online, and came across a video of the Cacheberry Pi project, by Jeff Clement.  The perfect mix of geocaching, electronics, and programming, I had found my first project!

The Cacheberry Pi is designed to be used in the car.  Place the small box on the dashboard, connect it to power, and while you're driving, the Raspberry Pi will search a pre-loaded database of geocaches for the nearest cache in the direction you're travelling.  This is different from most GPS receivers or applications because it searches only a narrow area ahead, and will not return caches that you've already passed by.

I've spent the last few weeks getting it working.  I used some slightly different hardware from the original, so it wasn't quite as simple as dropping his image onto my Pi and running it.  Here's what I used:
The Cacheberry-Pi displays a dashboard screen when no
nearby caches are found.
Getting the Raspberry Pi up and running was easy.  Getting the other hardware working right took a little bit of time.  The LCD that I used didn't work with the lcdproc driver included in the original version of the Cacheberry Pi.  I struggled for a while to get the lcd working right.  For more info on that, and to download the modified driver if you need it, see my previous post on the subject here.

The GPS module I used doesn't connect via USB, but instead connects directly to the GPIO pins on the Raspberry Pi and communicates via serial.  By default, the serial port on the Raspberry Pi is set up as a serial console, which must be disabled before it can be used by the GPS.  This can be done by making small changes in 2 files.

In /etc/inittab scroll to the end of the document, where you should add a # sign before this line:
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100
Next, edit /boot/cmdline.txt - This file is just one long line of text.  Find and remove the following from that line:
console=ttyAMA0,115200 kgdboc=ttyAMA0,115200

GPSD must also be reconfigured for the serial port instead of the USB. To do this, run:
sudo dpkg-reconfigure gpsd
This will start a wizard to configure settings for gpsd.  Set gpsd to run automatically at startup, then accept the default settings on each screen until prompted for the port that the gps unit is connected to.  Enter the following in the port field:
/dev/ttyAMA0
I've added an extra LED to my cacheberry pi, which is connected directly to the LED pin on the +Adafruit GPS unit.  This makes it easy to tell whether the GPS has a signal lock yet.  The other LED is controlled by the python code and activates based on the cache search pattern and distance.

I've also forked the Cacheberry Pi project on github and made a few changes to the code.  I added some missing steps to the instructions in the readme, to make it easier for others to reproduce the project. I've added configuration settings to display measurements in Metric or Imperial units, localize the time displayed on screen, adjust the scroll speed of geocache data on screen, changed what information about a geocache is displayed on the screen and how it's formatted, and made a few other small changes.  I hope these changes can be of help to someone else who is inspired by Mr Clement's project and wants to give it a try.

The updated code with these changes can be found here github.

Still on my to-do list for this project:

  • Adjust the behavior and triggers for the software controlled LED
  • Add a push button or keypad to allow simple interaction with the Cacheberry-Pi
  • Add a method for initiating a safe shutdown of the OS
  • Add some kind of backup power system which will kick in when the vehicle power is turned off, triggering a safe shutdown of the Pi's OS and powering the Pi long enough for that shutdown to complete. 
  • ???

Saturday, February 2, 2013

Using a 16x2 LCD with i2c on the Raspberry Pi

I got a Raspberry Pi for Christmas, and have been playing with it ever since. For one project, I needed to display a couple of lines of text. I ordered a 16 Character x 2 Line LCD display based on an hd44780 compatible controller. From what I had read, I wanted one with an i2c i/o expander. By using i2c, the lcd can be controlled using just 4 GPIO pins from the Raspberry Pi instead of 8. I ended up ordering the SainSmart IIC LCD1602 Display from amazon for just $12.

When I received the LCD, I hooked it up to my Pi and tried using it with a tutorial I found on the raspberry pi blog. The tutorial I was following mentioned that some of the i2c expansion 'backpack' boards connected the i2c chip's pins to the lcd's pins in a different way than others, and that the code has to be modified to use it with other versions.  When I couldn't get it working, I looked through the 'documentation' sainsmart offered for download on their website and in the product description on amazon. Unfortunately, the documentation was basically just some sample code for arduino. (As it turns out, the sample arduino code didn't even work.  It was written for an old, pre 1.0 version of the arduino IDE.) I contacted sainsmart support to ask for any further documentation available and a schematic of the i2c expander board, but the best they could do is point me to a post on someone's blog about using an i2c controlled lcd with the Raspberry Pi. After examining the path of traces on the backpack board, I was able to map out which pins of the i/o expander chip were connected to which pins of the lcd:

CHIP  LCD
P0       RS
P1       RW
P2       EN
P3       BL
P4       D4
P5       D5
P6       D6
P7       D7
Armed with this information, I was able to get assistance from the lcdproc help to modify the hd44780-i2c driver used by lcdproc.  Since I had seen many posts from others with the same problem, I wanted to share the solution.  Here is the patch code code that I used to modify the hd44780 driver:


Index: server/drivers/hd44780-i2c.c =================================================================== RCS file: /cvsroot/lcdproc/lcdproc/server/drivers/hd44780-i2c.c,v retrieving revision 1.14 diff -u -r1.14 hd44780-i2c.c --- server/drivers/hd44780-i2c.c 30 Oct 2010 18:04:21 -0000 1.14 +++ server/drivers/hd44780-i2c.c 27 Jan 2013 14:39:31 -0000 @@ -76,10 +85,10 @@ void i2c_HD44780_backlight(PrivateData *p, unsigned char state); void i2c_HD44780_close(PrivateData *p); -#define RS 0x10 -#define RW 0x20 -#define EN 0x40 -#define BL 0x80 +#define RS 0x01 +#define RW 0x02 +#define EN 0x04 +#define BL 0x08 // note that the above bits are all meant for the data port of PCF8574 #define I2C_ADDR_MASK 0x7f @@ -168,43 +214,43 @@ // powerup the lcd now /* We'll now send 0x03 a couple of times, * which is in fact (FUNCSET | IF_8BIT) >> 4 */ - i2c_out(p, 0x03); + i2c_out(p, 0x30); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, enableLines | 0x03); + i2c_out(p, enableLines | 0x30); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); + i2c_out(p, 0x30); hd44780_functions->uPause(p, 15000); - i2c_out(p, enableLines | 0x03); + i2c_out(p, enableLines | 0x30); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); + i2c_out(p, 0x30); hd44780_functions->uPause(p, 5000); - i2c_out(p, enableLines | 0x03); + i2c_out(p, enableLines | 0x30); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); + i2c_out(p, 0x30); hd44780_functions->uPause(p, 100); - i2c_out(p, enableLines | 0x03); + i2c_out(p, enableLines | 0x30); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, 0x03); + i2c_out(p, 0x30); hd44780_functions->uPause(p, 100); // now in 8-bit mode... set 4-bit mode - i2c_out(p, 0x02); + i2c_out(p, 0x20); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, enableLines | 0x02); + i2c_out(p, enableLines | 0x20); if (p->delayBus) hd44780_functions->uPause(p, 1); - i2c_out(p, 0x02); + i2c_out(p, 0x20); hd44780_functions->uPause(p, 100); // Set up two-line, small character (5x8) mode @@ -240,8 +284,8 @@ i2c_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch) { unsigned char enableLines = 0, portControl = 0; - unsigned char h = (ch >> 4) & 0x0f; // high and low nibbles - unsigned char l = ch & 0x0f; + unsigned char h = ch & 0xf0; // high and low nibbles + unsigned char l = (ch << 4) & 0xf0; if (flags == RS_INSTR) portControl = 0; @@ -277,7 +321,7 @@ */ void i2c_HD44780_backlight(PrivateData *p, unsigned char state) { - p->backlight_bit = ((!p->have_backlight||state) ? 0 : BL); + p->backlight_bit = ((p->have_backlight && state) ? BL : 0); i2c_out(p, p->backlight_bit); }

A copy of the modified source code and a compiled, ready to use, copy of the driver file can be downloaded here.

The sainsmart backpack board seems to be a clone of a similar board made by DFROBOT and others, so if your i2c backpack matches the pinouts I listed above, give the modified driver for lcdproc a try.

I hope this post is able to save others from going through the trouble I did to get this LCD working.

Hello World

Recently, I've found myself wanting to share the occasional information related to my work and hobbies. Thus, a new blog.