Never mind the Buzzclock

Fair warning

So far, only one person I’ve told about this project thinks it’s a good idea. Everyone else looks at me wtih a mixture of pity and puzzlement, neither of which emotions seems to be mitigated by my explanation. Clearly, the best thing to do with the project is to bury it quietly, and where better to commit something to obscurity than on my blog?

A little bit of background

My eyesight is rubbish. With glasses on, I can see perfectly. Without them, I’m as blind as a bat. When I go to bed, I take off my glasses. If I wake up in the middle of the night, I am unable to find out what time it is without putting my glasses back on and looking at an illuminated clock. The problem is, that by the time I’ve done this (and waited for my ageing eyes to focus properly), I’m fully awake. If it turns out that it’s far too early to get up, it can take ages to get back to sleep.

The usual suggestions

Most people say “Can’t you get a clock with a big display?” It’s a logical suggestion, if you can see well. For me, the digits on a bedside clock would have to be about a foot tall for me to be able to read it without glasses. Others say “Can’t you turn on a light?”, but doing so brings me to full wakefulness (and runs the risk of disturbing my wife). Fools suggest “Can’t you just use an alarm clock?” I do. But if I wake up before it goes off, I want to know if it’s three hours before, or only one. If it’s only one, I’ll get up and do something useful.

The solution

Here it is, in all its glory:

buzzclock01

No, it’s not the internet. It’s the Buzzclock. To use it, you press and hold the button on the top. It then tells you the current time by silently vibrating: one pulse for each hour, then one shorter pulse for each ten minutes past the hour. There is virtually no noise, no light and best of all no need to put on glasses. The time is not accurate to the minute, but it’s good enough to make the decision whether to get up or to go back to sleep.

Don’t laugh, it hurts my feelings.

Inside the box

buzzclock02

It’s a bit of a squeeze. The brains of the device is an arduino Nano, connected to a battery-backed real time clock. The Nano is a very useful device – more or less the same functionality of an arduino Uno or Leonardo, but in a much smaller package. It’s also dirt cheap (about three of your earth pounds). You can plug it directly into a breadboard for prototyping, and then when you want to build the final device, you can solder it in to a PCB or stripboard, or you can plug it in to a terminal block breakout board, as I did.

nano
nano adapter

The real time clock (RTC) module I used came from ebay, and also cost about £3. It uses a DS3231 chip, has a rechargeable backup battery and (unnecessarily) has 32k of flash memory on the same board. I guess the flash is there in case you want to use it for datalogging. The RTC chip also has a built in thermometer (I don’t know why).

ds3231-1

ds3231-2

The RTC and the arduino communicate over the two-wire I2C interface. This makes the wiring really simple. There are handy arduino libraries available to do all the heavy lifting. Thsi is a good thing, because the RTC chip has its own protocol for getting and setting the clock time, and the libraries wrap this into a nice simple set of commands.

The final component in the build is the vibration motor. This is one designed for mobile phones. As usual it’s from ebay and cost about a pound. This is a thing of beauty. It’s a small dc motor (it runs off 5V – the arduino can power it directly from an output pin) with an eccentric weight on its output shaft. When the motor spins, it vibrates. There is nothing special about that, except that it is tiny. The whole assembly is only about 10mm long. The engineering that goes in to mass producing those must be just staggering.

motor

How it works

THe button is just a push-to close switch. As long as you hold it down, the arduino gets power. Let it go, and the power is cut. This way, the arduino uses no power at all when not in use. The RTC has its own backup battery, so it keeps track of time without using the main battery.

Every time you press the button, the arduino boots up. It then contacts the RTC to get the time from it, and sets its own clock. The output pin connected to the motor is brought high for half a second then low for half a second for each hour in the current time. After a full second pause, shorter pulses are used to indicate the tens of minutes after the hour. And that’s all it does. At four o’clock in the morning, when all is pitch black, its a very quick way of working out it’s too early to get up.

Setting the time

At the moment, you can only set the time by connecting the arduino to a PC and sending a string over the serial port. This is not a big deal, because the RTC keeps time over a long period. It’s only an issue when the clocks change to or from daylight saving time, and I can cope with the effort twice a year.

Cracking the cube

I can’t take any credit for this.

Earlier this summer, I built a Rubik’s cube solver from a Lego Mindstorms set. I simply followed the plans for the Mindcuber design. It seemed to work quite well, but my Rubik’s cube had one face which was much stiffer to rotate than others, and the power available from the Lego motors was insufficient to reliably turn it. So it’s been sitting in my office for a while doing nothing. Today, however, Rob lent me a speed cube he bought from Amazon. It’s designed to take as little torque as possible to rotate, and has nicely chamfered edges so it doesn’t jam if it’s slightly out of alignment when you try to turn it. In the picture, the speed cube is the one on the left.

rubiks_cubes

The cube-solver robot loves it. I’ve posted a video of it on the YouTubes at http://youtu.be/iDMrePmmNA0 .

The whole thing is a supremely pointless exercise, but it is rather hypnotic to watch.

…and we’re back!

As a close follower of my blog, you will doubtless have noticed that it has been off the air the last few days. I didn’t. Rob drew my attention to its non-existence. It turns out that there were hosting troubles, and to cut a dull story short I’ve had to move the blog to a different hosting provider.

It’s more or less fixed now, but still has a few niggles to sort out. Sorry for any inconvenience.

Creating 3D models is hard

3D printing is easy. You can buy a 3D printer off the shelf for a few hundred of your Earth pounds, download patterns from thingiverse and be printing solid stuff straight away. Creating your own 3D models is harder, and it seems to me that this is now the bottleneck (at least, if you don’t want to spend a lot of money). There are several options. You can scan a real item, if you have a 3D scanner, and then use really awkward tools to manipulate the mesh. You can persuade powerful and confusing tools for animation and modelling like Blender to create models. You can use infuriatingly limited free versions of commercial tools like Sketchup. Or if you have really deep pockets, you can buy a proper CAD system.

I don’t like any of the above. I’m a programmer, and have a mechanical engineering background. I want to create precise, preferably parametric, models of components which I can then print out and fit together with other components to make machines. Up till now, I’ve been using OpenSCAD, and it’s been pretty good. OpenSCAD allows you to define shapes precisely using numbers, and combine them exactly (wrong word, I know) to create useful things. I love it. But it’s always had one major flaw (and a few little ones, but that’s another story). Building a model in OpenSCAD is like writing a program: it supports functions and loops, but it doesn’t support variables. At least not variable variables. You can assign a value to a variable and use it later, but that value cannot change. This is a bit of a pain, and it limits what you can do. Now there is an alternative, and that makes me happy.

The new kid on the block

OpenJSCAD is an entirely browser-based (yes, you read that right) editor and renderer for 3D models. It uses a language quite similar to OpenSCAD (indeed, it can import OpenSCAD files), but more powerful and a bit like C. And it supports proper variables. Hurrah! Here’s a screenshot of a little something I knocked up in it:

screenshot_4

Try doing that in OpenSCAD. I did, and the spiral ramp was not easy. Here’s an assembly of a few of them, printed out and stacked together. A ball bearing runs around them very nicely:

ball chute

Try OpenJSCAD. If you don’t like it, I’ll give you your money back.

Here’s my .jscad file which created the ball chute. You can simply cut the text and paste it into OpenJSCAD if you want to try it.

// title: Spiral ball bearing chute
// author: Peter Robinson
// license: None.  Free for all.
// description: A stackable spiral chute for ball bearings.

var radius = 50;
var slotwidth=6;
var wallthickness=1;


function main(params) {

    var a=2;
    return union(
        section(),
        section().translate([0,0,20]).rotateZ(90),
        section().translate([0,0,40]).rotateZ(180),
        section().translate([0,0,60]).rotateZ(270)
        );

}

function section(){
    return union(
        ramp(1,11,radius-4,radius-4,4),
        ramp(6,11,radius-3,radius-3,1),
        ramp(1,11,radius+3,radius+3,6),
        hub()
        );

}

function hub(){
    return  difference(
        union(
            CSG.cylinder({
            start:[0,0,0],
            end:[0,0,10],
            radius: 10,
            resolution:36
            }),
            CSG.cylinder({
            start:[0,0,10],
            end:[0,0,15],
            radiusStart: 8,
            radiusEnd: 7,
            resolution:36
            }),
            spoke().rotateZ(-27.5),
            spoke().rotateZ(-27.5-45).scale([1,1,0.5])
        ),
        union(
            CSG.cylinder({
            start:[0,0,-1],
            end:[0,0,17],
            radius: 6,
            resolution:36
            }),
            CSG.cylinder({
            start:[0,0,-0.5],
            end:[0,0,5.5],
            radiusStart: 7.9,
            radiusEnd: 6.9,
            resolution:36
            })
        )

    );
}

function spoke(){
    return CSG.cube()
        .scale([radius/2-slotwidth/2,1,5])
        .translate([-radius/2,0,5]);
}

function spiral(){
    var hex = CSG.Polygon.createFromPoints([
            [0,slotwidth/2, 0],
            [0,-slotwidth/2, 0],
            [0,-slotwidth/2, radius],
            [0,slotwidth/2, radius]
    ]).setColor(
        [0, 0.8, 0]
    );
    var angle = 5;
    return hex.solidFromSlices({
        numslices: 365 / angle,
        callback: function(t, slice) {
            var coef = 1 - t * 0.8;
            return this.
            translate([0 , radius, t*10]).
            rotateZ(angle * slice);
        }
    });

}

function ramp(slotwidth,climb,innerradius_start,innerradius_end,basethickness){
    var hex = CSG.Polygon.createFromPoints([
            [0,0, 0],
            [0,slotwidth, 0],
            [0,slotwidth, 1],
            [0,0, 1]
    ]).setColor(
        [0, 0.8, 0]
    );

    var base = CSG.Polygon.createFromPoints([
            [0,0, 0],
            [0,slotwidth, 0],
            [0,slotwidth, 1],
            [0,0, 1]
    ]).setColor(
        [0, 0.8, 0]
    );
    var angle = 5;
    var radiuschange = innerradius_end-innerradius_start

    var bottom = base.solidFromSlices({
        numslices: 95 / angle,
        callback: function(t, slice) {
            return this.
            translate([0 , innerradius_start +t*radiuschange, 0]).
            scale([1,1,basethickness]).
            rotateZ(angle * slice);
        }
    });

    var spiral = 
        hex.solidFromSlices({
        numslices: 95 / angle,
        callback: function(t, slice) {
            return this.
            translate([0 , innerradius_start +t*radiuschange, 0]).
            scale([1,1,climb*(0.1+t*0.9)]).
            rotateZ(angle * slice);
        }
    });


    return union(
        bottom,
        spiral.translate([0,0,basethickness])
    );

}

More tiny WiFi success

As I have posted before, I have been playing with the super-cheap WI07C WiFi module based on the ESP8266 chip. I’ve now had sufficient success with it that I can publish a post on a working project. This simple setup uses an Arduino nano to read temperatures from to 18BS20 sensors, formats the data as JSON and then sends it over WiFi to a server on my home network. It’s cheap and simple. Here’s the fritzing diagram:

WI07C_bb

You may notice the Adafruit level shifter board in there too. That’s because the digital IO from the arduino is 5V, but the WiFi module needs 3.3V. The Adafruit module is a dead easy way of joining the two. The temperature sensors use a three-wire protocol which allows you to connect many in parallel and address each one individually. there’s a software library which takes care of this.

Here’s the Arduino sketch. It uses Miles Burton’s temperature control library to read from the sensors, so you’ll need to download that. NB: this code is not a shining exaple of style or completeness. It’s a quick hack to get something working. It does no error checking or reconnection if there are problems. You may find yourself pressing the reset button a lot.

You might also note that the hardware serial port is required for the WiFi module, which needs 115200 baud. This means that you can’t upload a new sketch to the arduino while it’s connected to the WiFi module. I just whip out the wires to the TXD and RXD pins on the arduino while I’m uploading, and all is well.

The sketch tries to join the WiFi network, and then tries to establish a simple TCP connection to a server IP address and port of your choice. Once the connection is established, it checks the temperature sensors every 10 seconds or so and sends the temperatures to the server in JSON format, thus: {"temp":[22.63,22.81]}. That’s all it does. You’ll need a TCP server listening on your chosen IP address and port, of course. It seems to work quite reliably for me.

#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define SSID        "MyHomeSSID"
#define PASS        "MyPassword"
#define TARGET_IP   "192.168.1.xx"
#define TARGET_PORT 5000
#define TEMPERATURE_PIN 9

SoftwareSerial dbgSerial(10,11); // RX,TX
OneWire wire(TEMPERATURE_PIN);
DallasTemperature sensors(&wire);

void setup()
{
   // WiFi module needs fast serial, so must use the hardware port which is also used for
   // uploading sketches
   Serial.begin(115200);
   Serial.setTimeout(5000);

   // For debugging, we therefore need a software serial port.  This can be much slower.
   dbgSerial.begin(9600);
   dbgSerial.println("Starting");

  delay(1000);

  // Connect to the wirelsess network
  dbgSerial.println("Joining network...");
  Serial.print("AT+CWJAP="");
  Serial.print(SSID);  
  Serial.print("","");
  Serial.print(PASS);
  Serial.println(""");
  receive();

  // Just check that the WiFi module is joined to the network
  dbgSerial.println("Check connection...");
  Serial.println("AT+CWJAP?");
  receive();

  dbgSerial.println("Initialising sensors...");
  sensors.begin();


  dbgSerial.println("Connecting to server...");
  Serial.print("AT+CIPSTART="TCP","");
  Serial.print(TARGET_IP);
  Serial.print("",");
  Serial.print(TARGET_PORT);
  receive();
  delay(5000);

  dbgSerial.println("Ready to rumble!");
}

int incomingByte=0;
bool echoLocal = true;

// Get the data from the WiFi module and send it to the debug serial port
void receive(){
  delay(500);
  while (Serial.available() >0) {
    incomingByte = Serial.read();
    dbgSerial.write(incomingByte);
  }
  dbgSerial.println();
}

char temp1[10];
char temp2[10];

void loop()
{

  // call sensors.requestTemperatures() to issue a global temperature
  // request to all devices on the bus
  dbgSerial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  dbgSerial.println("DONE");

  dtostrf(sensors.getTempCByIndex(0),1,2,temp1);
  dtostrf(sensors.getTempCByIndex(1),1,2,temp2);  

  String json="{"temp":[" + String(temp1) + "," + String(temp2) + "]}";
  dbgSerial.print("Sending ");
  dbgSerial.println(json);

  // Send the data to the WiFi module
  Serial.print("AT+CIPSEND=");
  Serial.println(json.length());
  delay(500);
  Serial.print(json);
  receive();


  delay(10000);
}

This is a work in progress. I’ll be updating it soon. But for now, I’m very pleased with the simplicity of the WiFi modules, and even more pleased with their low cost (I am a Yorkshireman, after all).

Wifi success, for a change!

I’m actually having success in connecting the super-cheap WI07C wifi module to my home network, so that an arduino can send data anywhere.

WI07C module featuring esp8266 chipset

WI07C module featuring esp8266 chipset

I can now reliably establish a TCP connection and send data back and forth. It works rather well, with some limitations. It helps that I came across some slightly better documentation, sourced from this esp8266.com forum post which lists a few more AT commands and some more illuminating explanations.

AT+CIPMODE

AT+CIPMODE=1 or 0 (1 is default) sets the data receiving mode of the socket. If it’s 0, received data is simply sent to the serial port. If it’s 1, data gets “+IPD,c,n,” prepended to it, where c is the channel number and n is the number of bytes received. c is omitted if you are in single-channel mode. If you have multiple connections going in, this mode is logical. If you have only one, it may be simpler to use the transparent mode (AT+CIPMODE=0). But see AT+CIPSEND below, because this is affected by AT+CIPMODE!

AT+CIPSEND

The usual documentation about this is a bit pants. Here’s how it works. When you issue an AT+CIPSEND command, you normally tell it the channel you want to send it over (the chip can keep four IP connections going at once) and the number of bytes you want to send (call it n). The module then responds with a “>” character. It will then take the next n bytes you give it and send them over the TCP link. Then it responds with “SEND OK” and returns to normal, waiting for your next command. There are three variants of the AT+CIPSEND command, however:

AT+CIPSEND=channel,length is used if you have multiple connections open (AT+CIPMUX=1)
AT+CIPSEND=length is used for a single channel (if you have previously issued AT+CIPMUX=0 to tell it that you will only use one connection at a time)
AT+CIPSEND can be used without any parameters if you are using a single channel and transparent data mode (AT+CIPMODE=0). Note that there is no channel or length specified in this variant. After you issue the command, it will simply send every byte you throw at it directly to the receiving socket. This includes AT+ commands. Note that I have as yet found no way of exiting this mode other than resetting the module.

Also note that if you are in transparent data mode (AT+CIPMODE=0) and you try to use the variant of AT+CIPSEND which uses a length value, it won’t just fail or ignore it, it will actually reboot the module.

Lesser known AT commands not in other documentation

AT+GMR

AT+GMR retrieves the firmware ID of the module. There are at least two versions in the wild.

AT+CIPSTO

AT+CIPSTO=60 Sets the socket timeout period to 60 seconds
AT+CIPSTO? gets the current timeout value
You might want to change this value because if the server closes the socket, and your timeout value is too high, there appears to be nothing you can do from the client end other than do a hardware reset. I’m thinking it’s probably going to be necessary to tie the CH_PD line of the module to an output from the arduino, as I’m bound to want to reset from software at some point.

It’s good to make some progress. I’m going to look at the using the module as a server next.

WiFi for less than a fiver

Last week, the excellent hackaday ran a story about a new WiFi module (the Wi07c) based on the ESP8266 chip. It is eminently suitable for attaching to an arduino or similar, but it only costs $5. As I’ve been whining for some time about the high cost of WiFi shields for arduino, this piqued my interest. I bought a couple from the electrodragon store and have now had a bit of time to play with them. It seems that for once I’m a little ahead of the game – other people seem to be waiting a long time to receive theirs. The documentation is a little sparse, but enough to be going on with. There are three main sources, mostly community-supported: electrodragon, a hackaday.io project and nurdspace. The device is serial-driven, using a limited set of AT commands which will feel familiar to anyone who has worked with GPRS modems.

I’ve connected one of the modules to an arduino, and done some testing. I’ve also driven it directly from a serial terminal on my PC. These are my findings so far:

  1. The module runs at 3.3V, not 5V. The 3.3V available from an arduino can’t provide enough current to power it (though it may seem to). The WiFi module won’t even respond to commands without a separate power supply. Powering it from one of these works fine.
  2. In the version of the module I have, you must connect the CH_PD pin to +3.3V. Don’t be put off by the suggestion in the diagrams on Nurdspace.com that the four pins in the middle of the connector are not connected to anything. CH_PD is the pin next to the TXD pin.
  3. The AT commands mostly work. AT+CWLAP briskly returns a list of visible access points. AT+CWJAP connects to my home router (or claims to). Beyond that, things get flaky. Actually setting up a TCP connection to a running server does not seem to work. Nor does sending UDP. both allow me to get to the point of sending data, but then simply respond ‘busy’ to any further command or data until the device is rebooted (by unplugging it from the power supply). I’m not convinced that the device is ever genuinely connected to my router: the router doesn’t show it in the list of active clients.

I’ll keep experimenting with it, but I’m frustrated. It seems so close to being functional, but isn’t quite there yet. It feels like the firmware is missing some useful commands and diagnostic information. Or maybe it’s the documentation. Perhaps if my Chinese was better…