Sunday, September 2, 2012

i2c and the Freetronics Leostick

So I picked up some MCP23017 GPIO expanders after hearing about them from a friend. The only spare Arduino-compatible boards I had were Leosticks. It seems that the i2c pins aren't in the same places.

Uno: A4/A5
LeoStick: D2/D3


There's a good tutorial for using the MCP23017 with the Arduino programming environment here.

Sunday, June 3, 2012

Putting the Linux automounter to good use

I think filesystem automounters (eg. Linux autofs) are dramatically underused. They bring a lot of benefits to the table and can save you lots of typing. As an example, this evening I was building a VM on my laptop to be a build server for more Redhat-alike VMs, such as CentOS. I wanted it to be usable when disconnected (eg. flying), so I downloaded both of the CentOS 6.2 x86_64 DVDs and saved them in my ISO folder on the VM host (my MacBook Pro running OSX, but I'm sure it'd work equally well with a Linux or Windows host).


I figured I'd use VirtualBox's shared folders feature, rather than move or copy all the ISOs into the VM. This requires the VirtualBox guest additions to be installed, and provides a new filesystem type vboxsf. You mount a shared folder (for this example, named iso) thusly:


mkdir /mnt/iso
mount -t vboxsf iso /mnt/iso


If the stars all align nicely, you can access your iso folder in the VirtualBox guest, under /mnt/iso. Now you can loopback-mount an ISO file:


mkdir /mnt/centosdvd
mount -o loop,ro -t iso9660 /mnt/iso/centosdvd.iso


Wheeee, CentOS! This is all mildly annoying, though. Computers are supposed to make our lives easier! And going through this process over and over for lots of ISOs gets old very rapidly indeed. Thankfully, we can use the Linux automounter to simplify both tasks. First, we tell autofs about the two automount maps we're going to create; one for the shared folders, and one for the ISOs, by adding these two lines somewhere in /etc/auto.master


/vbox /etc/auto.vbox -n 5
/iso /etc/auto.iso -n 5


Then we create the two map files. They only contain one line each. This goes in /etc/auto.vbox:


* -fstype=vboxsf :&

... and this goes in /etc/auto.iso (replace iso with the name of your VBox shared folder containing ISO files, and possibly a further path inside that share, if appropriate, eg. /vbox/myshare/isofiles):


* -fstype=iso9660,ro,loop :/vbox/iso/&


Now reload the automounter:


/etc/init.d/autofs reload


... and that should be that. Try browsing your shares in /vbox. If you have an ISO file /vbox/iso/foo.iso, you should be able to see inside it by merely looking in /iso/foo.iso. Transparent, automatic, and, best of all, you only solve the problem once.

Sunday, September 25, 2011

And if your Xbee shield is behaving strangely...

If you are combining the CAN-Bus and Xbee shields from SparkFun, it can be very tempting to plonk the EM406 GPS atop the nice flat prototyping area on the Xbee shield. It's a good fit there! But if stuff suddenly and inexplicably stops working, check that the GPS chassis isn't bridging the terminals on the Xbee shield's RESET switch. I felt like a real idiot :-(

Arduino: combining CAN-bus and Xbee shields


A little box of Arduino, originally uploaded by indigoid.

So I created a simple little sketch, based on the TimeGPS sample that comes with the TinyGPS library, that waits for a "p" over the Xbee interface and upon receiving it, sends back the date, time, latitude and longitude data from the GPS. The CAN-bus shield uses pins 4 and 5 for the GPS serial interface. I found that the Xbee modules I have (as supplied in the SparkFun Xbee retail kit) have rather shorter range than I'd hoped for, but at least they work and I am learning about their usage. Here's the sketch:


#include <TinyGPS.h>        //http://arduiniana.org/libraries/TinyGPS/
#include <NewSoftSerial.h>  //http://arduiniana.org/libraries/newsoftserial/
// GPS and NewSoftSerial libraries are the work of Mikal Hart

TinyGPS gps; 
NewSoftSerial serial_gps =  NewSoftSerial(4, 5);  // receive on pin 3

void setup()
{
  Serial.begin(9600);
  serial_gps.begin(4800);
  Serial.println("setup...");
}

void dump_lat_long(float flat, float flong) {
  Serial.print("lat : "); Serial.println(flat);
  Serial.print("long: "); Serial.println(flong);
}

#define pdec(x) { Serial.print(x,DEC); }
#define p(x) { Serial.print(x); }
#define s() p(" ")
#define d() p("-")
#define c() p(":")
void dump_datetime() {
  int year;
  byte month, day, hour, minutes, second, hundredths;
  unsigned long fix_age;
  gps.crack_datetime(&year, &month, &day, &hour, &minutes, &second, &hundredths, &fix_age);
  pdec(year); d(); pdec(month); d(); pdec(day);
  s();
  pdec(hour); c(); pdec(minutes); c(); pdec(second); p("."); pdec(hundredths);
  Serial.println();
}

void loop() {
  float flat, flon;
  unsigned long fix_age;
  String msg;
  byte havedata = 1;
  byte polled = 0;
  while (serial_gps.available() && !polled) {
    if(gps.encode(serial_gps.read())) {
      // returns +- latitude/longitude in degrees
      gps.f_get_position(&flat, &flon, &fix_age);
      if (fix_age == TinyGPS::GPS_INVALID_AGE) {
        msg = "No fix detected";
        havedata = 0;
      } else if (fix_age > 5000)
        msg = "Warning: possible stale data!";
      else
        msg = "Data is current.";
      polled = 1;
      if (Serial.available() && Serial.read() == 'p') {
        Serial.println(msg);
        if (havedata) {
          dump_datetime();
          dump_lat_long(flat,flon);
        }
        delay(100);
      }
    }
  }
}

I also wrote a small Perl script that (via Device::SerialPort from CPAN) interrogates the Arduino every 5 seconds or so, using a USB-attached Xbee Explorer. For Linux you will need to change the serial port device filename to /dev/ttyS0 or similar. No idea about Windows, sorry. Again, I started out with some sample code (this time from the Device::SerialPort distribution) and hacked most of it off. Code follows:


#!/usr/bin/perl

use strict;
use warnings;
use Device::SerialPort;

my $file = "/dev/tty.usbserial-A700fbpg";
my $ob = Device::SerialPort->new ($file) || die "Can't open $file: $!";

$ob->baudrate(9600)     || die "fail setting baudrate";
$ob->parity("none")     || die "fail setting parity";
$ob->databits(8)        || die "fail setting databits";
$ob->stopbits(1)        || die "fail setting stopbits";
$ob->handshake("none")  || die "fail setting handshake";
$ob->write_settings || die "no settings";
$ob->error_msg(1);              # use built-in error messages
$ob->user_msg(1);

while(1) {
  $ob->write("p");
  print $ob->input;
  sleep 5;
}

Monday, September 12, 2011

stairwell sensor light: Arduino!

So I wanted a small light at the bottom of the short set of stairs that lead from the door of my apartment into the main living area. I've been learning about Arduino lately, so I figured this might be a practical experiment. I decided to use a reed switch to sense when the door had been opened.

After getting frustrated at the reed switch functioning just fine when closed (Arduino digitalRead() returning HIGH) but bouncing around randomly when it should have been staying open, I did some Googling and found that I should have used a pullup resistor to coax the current in the right direction. I don't pretend to understand why this works, but I intend to find out.

Anyway, I used a circuit based very much on this one, plus of course an RGB LED to do the actual lighting. The next step is to grab a couple more RGB LEDs (I only had one on hand that had been supplied in the Sparkfun Inventors Kit) and make it brighter.

Learning about and experimenting with Arduino has been a lot of fun so far. Am working on a larger project for the bike. Along the way I've dramatically improved my soldering skills, though they are still pretty terrible!

#include <Time.h>

// pins
const int reedswitch = 2;
const int red = 9;
const int green = 10;
const int blue = 11;

// door states
const int DOOR_OPEN = 0;
const int DOOR_CLOSED = 1;

// minimum time the courtesy light will stay on for (seconds)
const int MIN_OPENTIME = 10;

///////////////////////////////////////////

int door = DOOR_CLOSED;
int last_open_at = 0;

void setup() {
  pinMode(reedswitch, INPUT);
  setTime(0);
}

void rgbled(int r, int g, int b) {
  analogWrite(red,r);
  analogWrite(green,g);
  analogWrite(blue,b);
}

void loop() {
  int reedswitch_state = digitalRead(reedswitch);
  if (reedswitch_state == HIGH && now() >= last_open_at + MIN_OPENTIME) {
    door = DOOR_CLOSED;
  } else if (reedswitch_state == LOW) {
    last_open_at = now();
    door = DOOR_OPEN;
  } else {
    // no change in state, do nothing
  }
  if (door == DOOR_OPEN) {
    rgbled(255,255,255);
  } else {
    rgbled(0,0,0);
  }
  delay(500);
}

Monday, December 27, 2010

K1200GT tyre pressure adjustment technique

Note that this probably also works with other BMW models with the tyre pressure monitoring (RDC) option fitted, but I have only tried it on my K1200GT.

If you need to adjust your tyre pressures and you don't have a tyre pressure gauge with you:

  1. ride the bike until the dash starts displaying the pressures
  2. stop the bike and then stop the engine, without touching the key in the ignition. Use the kill-switch
  3. adjust pressures, noting that as you do so, the dash display changes
  4. ride the bike :-)

This may be obvious to people smarter than me.  RDC is a wonderful feature to have.

End of year roundup

A quick blog post to wrap up 2010...

Work: Happy, challenged, excited. No serious complaints. Learning about AIX and Puppet, and of course Linux sysadmin continues to be my main role. Looking forward to the SAGE-AU conference in Melbourne, in September 2011. Didn't take as much time off as I should have, but riding my bike to and from Hobart for the 2010 SAGE-AU conference was extremely satisfying and gave me a good chance to be out of the office and clear my head.

Not-work: In May I started living and working in Sydney full-time. Have been appreciating commuting by train. I ditched my Nokia E71 for an iPhone 3GS and am loving it; it has been the single most satisfying tech purchase I have ever made. Haven't spent as much time in the gym as I should have, but this sorry state of affairs will not continue. I haven't spent nearly as much quality time with Anna as I'd like (we do live in different cities, after all), but I am hoping that this can improve in 2011.

Motorcycling, overall: I put about equal kilometres on the Dakar and K1200GT this year, and in total, rather fewer than last year. I don't have an odometer figure for the K-bike as of January 1 this year, but I do for the Dakar. A combined total of about 35000km, I think. The K1200GT odometer currently reads 51610km, and the Dakar odometer tells a very similar tale. My BMW Roadside Assistance subscription proved worthwhile as I achieved four punctured tyres in three months of riding.

K1200GT: This year saw a lot of warranty repair work on the K-bike, mostly at the time of the 40000km service, where it was at the dealer for a month or more. It now has a K1300 gearbox and clutch, and this does appear to be a bit better than the old units, but still not nearly as good as your average Japanese bike, such as a friend's Blackbird that I had the significant pleasure of borrowing.

F650GS Dakar: 2010 saw this bike back on the road after a bit of a hiatus, and I still have a deep, abiding love for it, especially the delightful little Rotax engine. 40000 and 50000km services were done, and I with the aforementioned Blackbird owner's help, I finished the Pro-Oiler install. The bike still needs more work, though, needing new chain/sprockets, new tyres and (for the second time) new steering head bearings. Michelin's perennial supply problems caused me to get Pirelli's gimmicky new Angel ST tyres instead of my usual Pilot Road2, and this was a mistake that I won't repeat.

Projects: In 2010 I acquired a Honda XL250 K0 (early 1970s model) and the other day I also acquired (Free! Thanks, Norm!) a Honda CT110 "postie" bike. The XL250 has a long road ahead, as I'd like to fully restore it. The CT110 on the other hand I would like to have registered and ridable as soon as possible. I don't think it will cost very much at all to get there. Job #1 is to transport it to my Sydney garage from its current location.