Digital Dowsing report 3

Old PS2 trackball mouse, snootlab SD shield on a borrowed Arduino Uno (SMD Edition)

Old PS2 trackball mouse, snootlab SD shield on a borrowed Arduino Uno (SMD Edition)

The Digital Dowser took another step forward last night. Backstory here and then here. It seems that my Snootlab Memoire shield was somehow not friends with the old Arduino Diecimila I borrowed from Martin, so relying once more on the kindness of strangers it seems my duty to do as a wannabe hacker, I got in touch with Bruno Sinou, recently moved to Berlin from Paris who mentioned he had a few knocking about when we met each other at Martin’s last earthcode Berlin performance.

And so with a more modern Arduino on hand, I found that the shield performed as it should do with no hiccups or having to delve into alternative SDfat libraries (which are actually quite interesting, however, having many more examples than the SD library bundled with the current Arduino IDE).

What I’ve hacked together is the PS2 Mouse library and the AnalogLogger Example from the SdFat library. The wires from the PS/2 Mouse are connected to the Arduino pins thus:

Orange: 5V
Red: Gnd
Yellow (Clock): Digital 6
Black (Data): Digital 5

NB: The Snootlab Memoire shield has a handy LED-resistor combo hanging on digital pin 9 which I set to flash when data is being written to the card.

Here, for the curious, is the Arduino sketch (this will change when I get my head around this Arduino/C++ stuff)

// A hack of the following scripts:
// ps2_mouse in the examples folder of the ps2 library (
// AnalogLogger in the SdFat library (
// The AnalogLogger uses RTClib from
// Daniel Belasco Rogers Oct 2012

#include   // define FreeRam()

#define CHIP_SELECT     SS  // SD chip select pin
#define LOG_INTERVAL  1000  // mills between entries
#define ECHO_TO_SERIAL   1  // echo data to serial port if nonzero
#define WAIT_TO_START    1  // Wait for serial input in setup()

// file system object
SdFat sd;

// text file for logging
ofstream logfile;

// Serial print stream
ArduinoOutStream cout(Serial);

// buffer to format data - makes it eaiser to echo to Serial
char buf[80];

// define the Real Time Clock object
RTC_DS1307 RTC;  

// initialise the ps2 mouse
PS2Mouse mouse(6, 5);

int posx;   // a variable to hold cumulative position for x
int posy;   // a variable to hold cumulative position for y

// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))

// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
    DateTime now =;

  // return date using FAT_DATE macro to format fields
  *date = FAT_DATE(now.year(), now.month(),;

  // return time using FAT_TIME macro to format fields
  *time = FAT_TIME(now.hour(), now.minute(), now.second());
// format date/time
ostream& operator < < (ostream& os, DateTime& dt) {
  os << dt.year() << '/' << int(dt.month()) << '/' << int( << ',';
  os << int(dt.hour()) << ':' << setfill('0') << setw(2) << int(dt.minute());
  os << ':' << setw(2) << int(dt.second()) << setfill(' ');
  return os;
void setup() {

  // set up LED on logging shield
  pinMode(9, OUTPUT);
  // start mouse

  // pstr stores strings in flash to save RAM
  cout << endl << pstr("FreeRam: ") << FreeRam() << endl;

  cout << pstr("Type any character to start\n");
  while ( < 0) {}
#endif  // WAIT_TO_START

  // connect to RTC21
  if (!RTC.begin()) error("RTC failed");

  // set date time callback function
  DateTime now =;
  cout  << now << endl;

  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  if (!sd.begin(CHIP_SELECT, SPI_HALF_SPEED)) sd.initErrorHalt();

  // create a new file in root, the current working directory
  char name[] = "LOGGER00.CSV";

  for (uint8_t i = 0; i < 100; i++) {
    name[6] = i/10 + '0';
    name[7] = i%10 + '0';
    if (sd.exists(name)) continue;;
  if (!logfile.is_open()) error("");

  cout << pstr("Logging to: ") << name << endl;

  // format header in buffer
  obufstream bout(buf, sizeof(buf));

  bout << pstr("millis");

  bout << pstr(",date,time");

  bout << pstr(",mousex,mousey");

  logfile << buf << endl;

  cout << buf << endl;
#endif  // ECHO_TO_SERIAL
void loop() {
  uint32_t m;

  // wait for time to be a multiple of interval
  do {
    m = millis();
  } while (m % LOG_INTERVAL);

  // use buffer stream to format line
  obufstream bout(buf, sizeof(buf));

  // start with time in millis
  bout << m;

  DateTime now =;
  bout << ',' << now;

  // get mouse data
  MouseInfo mouseInfo;

  // increment positions from x y
  posx += int(mouseInfo.x);
  posy += int(mouseInfo.y);

  // push positions to buffer
  bout << ',' << posx;
  bout << ',' << posy;
  bout << endl;

  // log data and flush to SD - flash led
  digitalWrite(9, HIGH);
  logfile << buf << flush;
  digitalWrite(9, LOW);

  // check for error
  if (!logfile) error("write data failed");

  cout << buf;
#endif  // ECHO_TO_SERIAL

  // reset position if left mouse button clicked
  if (mouseInfo.leftClick){
  posx = posy = 0;

  // don't log two points in the same millis
  if (m == millis()) delay(1);

Now 'all' I have to do is design and build a way of attaching the black plastic encoder wheels to the dowsing rods - reliably, mind. No pressure.

This entry was posted in Diary, Linux, Walking and tagged , , . Bookmark the permalink.

1 Response to Digital Dowsing report 3

Comments are closed.