Computing stuff tied to the physical world

Archive for October 2010

Sending data TO remote nodes

In Software on Oct 31, 2010 at 00:01

Yesterday’s post described an easy way to get some data from remote battery-powered nodes to a central node. This is the most common scenario for a WSN, i.e. when reading sensors scattered around the house, for example.

Sometimes, you need more reliability, in which case the remote node can request an “ACK” and wait (briefly) until that is received. If something went wrong, the remote node can then retry a little later. The key of ACKs is that you know for sure that your data packet has been picked up.

But what if you want to send data from the central node TO a remote node?

There are a couple of hurdles to take. First of all, remote nodes running on batteries cannot continuously listen for incoming requests – the RFM12B receiver draws more than the ATmega at full power, it would drain the battery within a few days. There is simply no way a remote node can be responsive 100% of the time.

One solution is to agree on specific times, so that both sides know when communication is possible. Even just listening 5 ms every 500 ms would create a fairly responsive setup, and still take only 1% of the battery as compared to the always-on approach.

But this TDMA-like approach requires all parties to be (and remain!) in sync, i.e. they all need to have pretty accurate clocks. And you have to solve the initial sync when powered up as well as when reception fails for a prolonged period of time.

A much simpler mechanism is to let the remote take the initiative at all times: let it send out a “poll” packet every so often, so we can send an ACK packet with some payload data if the remote node needs to be signaled. There is a price: sending a packet takes even more power than listening for a packet, so battery consumption will be higher than with the previous option.

The next issue is how to generate those acks-with-payload. Until now, most uses of the RF12 driver required only packet reception or simple no-payload acks. This is built into RF12demo and works as follows:

Screen Shot 2010 10 30 at 20.17.37

That’s not quite good enough for sending out data to remote nodes, because the central JeeLink wouldn’t know what payload to include in the ACK.

The solution is the RF12demo’s “collect mode”, which is enabled by sending the “1c” command to RF12demo (you can disable it again with “0c”). What collect mode does, is to prevent automatic ACKs from being sent out to remote nodes requesting it. Instead, the task is delegated to the attached computer:

Screen Shot 2010 10 30 at 20.17.48

IOW, in collect mode, it becomes the PC/Mac’s task to send out an ACK (using the “s” command). This gives you complete control to send out whatever you want in the ACK. So with this setup, remote nodes can simply broadcast an empty “poll” packet using:

    rf12_sendStart(0, 0, 0);

… and then process the incoming ACK payload as input.

It’s a good first step, since it solves the problem of how to get data from a central node to a remote node. But it too has a price: the way ACKs are generated, you need to take the round-trip time from JeeLink to PC/Mac and back into account. At 57600 baud, that takes at least a few milliseconds. This means the remote node will have to wait longer for the reply ACK – with the RFM12B still in receive mode, i.e. drawing quite a bit of current!

You can’t win ’em all. This simple setup will probably work fine with remotes set to wait for the ACK using Sleepy::loseSometime(16). A more advanced setup will need more smarts in the JeeLink, so that it can send out the ACK right away – without the extra PC round-trip delay.

I’ll explore this approach further when I get to controlling remote nodes. But that will need more work – such as secure transmissions: once we start controlling stuff by wireless, we’ll need to look into authorization (who may control this node?), authentication (is this packet really from who it says it is?), and being replay-proof (can’t snoop the packet and re-send it later). These are all big topics!

More on this some other time…

Simple RF12 driver sends

In AVR, Software on Oct 30, 2010 at 00:01

(Whoops… this post got mis-scheduled – fixed now)

Yesterday’s post illustrates an approach I’ve recently discovered for using the RF12 driver in a very simple way. This works in one very clear-cut usage scenario: sending wireless packets out periodically (without ACK).

Here’s the basic idiom:

Screen Shot 2010 10 29 at 13.01.24

What this does is completely ignore any incoming data, it just waits for permission to send when it needs to, and then waits for the send to complete by specifying “2” as last arg to rf12_sendStart().

No tricky loops, no idle polling, everything in one place.

With a few lines of extra code, the RFM12B module can be kept off while not used – saving roughly 15 mA:

Screen Shot 2010 10 29 at 13.07.11

And with just a few more lines using the Sleepy class, you get a low-power version which uses microamps instead of milliamps of current 99% of the time:

Screen Shot 2010 10 29 at 13.09.03

Note the addition of the watchdog interrupt handler, which is required when calling Sleepy::loseSomeTime().

The loseSomeTime() call can only be used with time ranges of 16..65000 milliseconds, and is not as accurate as when running normally. It’s trivial to extend the time range, of course – let’s say you want to power down for 10 minutes:

Screen Shot 2010 10 29 at 13.11.16

Another point to keep in mind with sleep modes, is that it isn’t always easy to keep track of time and allow other interrupts to wake you up again. See this recent post for a discussion about this.

But for simple Wireless Sensor Network node scenarios, the above idioms will give you a very easy way to turn your sketches into low-power mode which can support months of operation on a single set of batteries.

Update – it looks like the above RF12_sleep() arguments are completely wrong. They should be:

  • rf12_sleep(N) turns the radio off with a wakeup timer enabled if N is 1..127
  • rf12_sleep(0) turns the radio off
  • rf12_sleep(-1) turns the radio back on

This list matches what is documented on the wiki page.

Meet the new Opto-coupler Plug

In Hardware on Oct 29, 2010 at 00:01

The plug barrage continues…

This time it’s an update of the flawed Opto-coupler Plug, which only worked properly on one channel (unless you patched it up). So here’s the new Opto-coupler Plug v2:

Dsc 2185

Wait! There’s more! It’s actually two plugs in one now:

Dsc 2186

(note: the solder jumpers need to be shorted out to use this as an output board)

Since there was enough room on this board, I decided to make it more versatile: it can now be used as dual Opto-coupled input (as before) or as dual Opto-coupled output plug. In the latter case, the JeeNode drives the IR LEDs and the output is a phototransistor which can be used as low-power (polarized) switch for some external device. The choice is determined by how the IC socket and Opto-coupler are hooked up.

The connectors are the same as before: detachable screw terminals, these are very convenient because you can prepare the wiring elsewhere and then plug / unplug / swap channels as needed.

I have no immediate use for these plugs right now, but of course I had to make sure that everything is working properly, so I hooked both of them up:

Dsc 2190

On the back you can see how things were connected together:

Dsc 2191

Here’s the updated opto_demo.pde test sketch for that – I decided to send the results by wireless for a change:

Screen Shot 2010 10 28 at 18.11.23

Sample output on my central JeeLink:

Opto Output

Yippie – looks like it’s working exactly as intended! Note the inverted signals, BTW.

Docs and shop have been updated for this new plug version. If you have version 1, please let me know and I’ll send out an updated board to you.

Meet the Current Source Plug

In Hardware on Oct 28, 2010 at 00:01

Here’s another new plug, firmly in the realm of home automation: the Current Source Plug drives two independent channels of Power LEDs with either 350 mA or 700 mA current:

Dsc 2183

As you can see, this plug was a very tight fit. These are based on high-efficiency AP8803 switching power supply chips, which also explains the two hefty inductors on the board. The 2 I/O pins are used to control both channels, and can use PWM to dim the LEDs.

The connector on the bottom is for the LED power supply (sorry for the tight fit!), and can be 8..30V. According to the specs, you can have up to 5 power LEDs in series at 30V, so the highest power this plug can theoretically switch is 5x 3W-LEDs @ 700 mA per channel!

There are some thermal limits though, due to the high amount of power involved in this small board. It is best to keep the voltage differential between what the LED needs and the input voltage fairly low. The two 3.7V LEDs I tried worked fine at 6..12V, but the board started heating up quickly with more than 12V (at full power).

Here’s the test setup I used:

Dsc 2182

The big LED is set to 700 mA, the small one to 350 mA – for a total of 1050 mA output. The nice part is the efficiency of this thing: the board draws less than 1050 mA due to the “buck” switching design. I measured roughly 960 mA @ 6V and 490 mA at 12V. At 18V it heated up a lot, I did not dare take it any higher. The main use I see for this board is two channels, each with 1 or 2 power LEDs in series, driven from a 12V supply.

At full power, the board temperature rose about 40°C above ambient after an hour, i.e. roughly 60..70°C. Hot to the touch, but not scorching hot. When dimmed, temperatures immediately went down. Note that the LED lights themselves were hotter than the board. Power LEDs need cooling!

For PWM dimming up to 500 Hz, just use the I/O pins. I haven’t tried it yet, but this could be done with the same rgbRemote.pde sketch as used for the MOSFET plugs.

The documentation and shop have been updated with this new plug.

More goodies coming, stay tuned…

Meet the Bridge Board

In AVR, Hardware on Oct 27, 2010 at 00:01

As mentioned not so long ago on this weblog, I’ve been doodling with some ideas to simplify using a JeeNode alongside a solderless breadboard. So – tada! – here’s the new Bridge Board:

Dsc 2167

As the name says, it acts as a bridge between a JeeNode (also USB or SMD variants) and a breadboard. All the I/O and power pins in one row, labeled for easy reference (including Arduino pin numbers), with two pins sticking into the power rail for ground and +3.3V. The JeeNode goes underneath, component-side up, with the radio on the right-hand side.

Two LEDs and a push button are also brought out, available for general-purpose use.

In the most basic form, the Bridge Board has just 4 6-pin male haders to push into the JeeNode ports, and 29 (+ 2 power-rail) pins to push into a medium or large size breadboard.

The generality of this setup increases if you hook up more headers between the JeeNode and the Bridge Board. With the SPI/ISP connector included, you get the ability to hook it up to an Ether Card, for example:

Dsc 2165

The reason this works, is that the 20 pins on the right are compatible with a Carrier Board – with the “BTN” and “LED2” pins extra. Note that with an Ether Card hooked up, all four ports (i.e. 8 DIO/AIO pins) are still fully available for your own use.

If you connect the 8-pin PSIX header on a JeeNode v5 (or both PSI and SPI/ISP on the other variants), plus a 0.1 µF capacitor, then the FTDI header on the left side can be used. This is paricularly useful for the JeeSMD, which doesn’t have an FTDI connector of its own.

Some I/O signals are brought out on more than 1 pin on the breadboard: DIO2/AIO2 and DIO3/AIO3. This maintains compatibility with the Carrier Board and also means that Port 2 is available on the breadboard in the standard port header layout: PWR, DIO, GND, +3V, AIO, IRQ if you want to insert any of the Jee Plugs.

Another way to combine plugs with the breadboard is to use stacking headers, so that the 4 ports can be re-used on the top of the Bridge Board. See the setup I plugged into the lower left:

Dsc 2166

Evidently, I had to make sure that all the I/O pins work properly, so I pre-loaded the SMDdemo.pde sketch onto a JeeNode and hooked up lots of LEDs:

Dsc 2161

Yeay – it works!

(note how the push-button has been turned into a reset button – this requires either the SPI/ISP or the PSIX headers to be hooked up)

I expect this new setup to be very convenient for all the endless experimentation going on here at Jee Labs. I’ll be updating the documentation site and shop shortly to reflect this addition to the Jee product line-up. I’ll also be adding 6- and 8-pin stacking header 10-packs.

Long live the breadboard!

Meet the Heading Board

In Hardware, Software on Oct 26, 2010 at 00:01

Here’s another plug which didn’t work initially, but as always it was a simple mistake in the software (and a not-so-clear datasheet) which prevented me from using this thing:

Dsc 2157

The Heading Board is based on a somewhat unusual HDPM01 combination sensor by HopeRF, containing a 2-axis compass / magnetometer and a … temperature + pressure sensor. My interest in this thing was the compass, which is relatively low-cost compared to most other options out there.

There’s now a HeadingBoard class in the Ports library to make this thing sing. Note that it’s called a “board” and not a “plug” because it requires two ports and sits as a mini-board on top of a JeeNode (same as the Room Board):

Screen Shot 2010 10 24 at 17.39.20

This board is a somewhat awkward match for the ports concept, because it needs a 32 KHz clock to function. I’ve hooked that up to the IRQ pin, which is reprogrammed by HeadingBoard::begin() to generate that clock using Timer 2, so you may have to jump through some hoops to use this if other ports use the IRQ pin for a different purpose. A more general approach would be to generate the required 32 KHz on-board with an NE555, as is done in an upcoming Infrared Plug – but that requires extra board space (or components on both sides of the pcb).

Here is the “heading_demo.pde” sketch, now added to the Ports library as example:

Screen Shot 2010 10 24 at 17.40.20

Sample output:

Screen Shot 2010 10 24 at 17.17.02

I haven’t figured out the conversion from X-/Y-axis values to compass heading yet. There is some sensitivity to how the board is positioned horizontally – this could be compensated by detecting the angular position using a Gravity Plug. But as you can see, there is a clear variation in readings as I turned the JeeNode + Heading Board around the Z axis.

So if you’re into robots: a Heading Board plus a Gravity Plug is all you need to determine your absolute orientation in all the 3 axes in space, i.e. X, Y, and Z.

Onwards!

PS. Here’s a crazy idea: we could use the Heading Board to create a door-open sensor. Simply attach this thing to a door, and track the Z-axis orientation!

Meet the Proximity Plug

In Hardware, Software on Oct 25, 2010 at 00:01

The Proximity Plug was created a while back, but at the time I couldn’t get the chip to respond properly. Turns out that this was just some silly mistake in the code, so now all is well and ready for use:

DSC_1267.jpg

This plug uses an MPR084 to support up to 8 capacitive touch sensors. These can be created in any shape you like, using some conductive board, film, or tape. There’s a solder jumper to set one of two I2C addresses, so up to 16 sensors can be hooked up to a single port.

Here’s a little test setup:

Dsc 2154

Capacitive sensing can be fairly tricky to get right – the sensors may respond slightly differently, cross-talk between each sensor, electromagnetic noise pick-up, etc. But this chip does a lot of the work for us.

There are many configurations settings, and I’ve only started to scratch the surface so far. The current setup is configured to only report a single touch at a time, and does auto-calibration on startup. I’m still seeing some cases where things lock up and may have to be reset (in software), so the interface class for this thing is very basic for now – simply giving acces to the individual registers from I2C.

Screen Shot 2010 10 24 at 13.01.33

I’ve added a “proximity_demo.pde” sketch to the Ports library to demonstrate the use of this plug:

Screen Shot 2010 10 24 at 13.10.36

It will print a message whenever a “key-press” is detected. The commented-out code prints out the following ID string extracted from the chip:

    #reescale,PN:MPR084,QUAL:EXTERNAL,VER:1_0_0

Note that the MPR084 chip wants a 100 KHz I2C bus.

One thing I’d like to try with this thing, is to create some input buttons with it using the Carrier Board box. It would be nice if the sensors can be made sensitive enough to reliably work with a bit of copper on the inside of the box, then you wouldn’t even have to drill holes or make any cutouts to be able to control what’s inside. Otherwise, perhaps a slit for adhesive / conductive copper tape, covered up with plastic foil?

More detective work needed…

Parsing input commands

In Software on Oct 24, 2010 at 00:01

I often need some way to get a bit of data and a few commands into an Arduino-type sketch from the serial port. Trivial but tedious stuff if you need to write the code for it, each time again.

Trouble is, the ATmega has very limited RAM space and string processing capabilities, so writing a super duper fancy string input parser is too wasteful of resources to be practical, in most cases.

In the RF12demo sketch, I used a very simple postfix notation, which lets you enter some bytes of data and a one-letter command. The syntax is:

<arg1>,<arg2>,... <cmd-char>

It works fairly well, but arguments are limited to single bytes and have to be entered as decimal values.

Here’s another attempt to simplify this sort of task. I’ve added an “InputParser” class to the Ports library, which takes care of basic parsing, while remaining flexible enough to allow use in different sketches. It supports input of bytes, ints, and longs in decimal or hex format, as well as short strings. It’s not JeeNode specific, and should work with any Arduino.

Here is the InpurtParser class definition (minor details omitted):

Screen Shot 2010 10 23 at 20.11.12

Note that many choices were made to keep the code overhead low, while allowing enough flexibility to input data in different ways. As a consquence, the syntax is a bit strict and limited:

  • args are separated by spaces or commas, with the command code typed last
  • plain numbers are interpreted as bytes: 123
  • negative values can be entered using a trailing minus sign: 123-
  • append a decimal point to enter 2-byte ints: 12345.
  • append a colon to enter as 4-byte longs: 123456789:
  • prefix with a dollar sign to use hex mode: $1A / $1A2B. / $123456:
  • enter strings between double quotes: “this is a string”

I’ve added a “parser_demo.pde” sketch to illustrate its use:

Screen Shot 2010 10 23 at 20.13.05

When initialized, the parser must be given a buffer it can use to collect all argument data and input strings in. In this simple example, a 50-byte buffer is allocated dynamically.

Each command is a separate function, which pulls its variables from the parser object when called. The parser is initialized with a table of these commands, listing the command code and minimum number of expected bytes, along with the function to call.

Here are some examples of input:

h
?
v
1234. v
"Hello, there!" s
123456789: "abc" $100. "defgh" 12345. c

Here is the output, corresponding to each of the above commands:

[parser_demo]
Hello!
Known commands: h v l s c
Not enough data, need 2 bytes
value = 1234
string = <Hello, there!>
complex = 123456789 <abc> 256 <defgh> 12345

Note that you get a list of known commands when entering a bad command (or “?”).

That last example illustrates how to pass a variety of input argument types to a command. The code for this is:

Screen Shot 2010 10 23 at 20.25.51

This demo requires about 5 Kb, including some 850 bytes for the command functions. 600 bytes for malloc (this is optional), and 600 bytes for the Serial class. The parser itself uses some 1.7 Kb.

By default, the parser object is attached to the “Serial” stream, but it can be hooked up to something else if necessary, such as an LCD or Ethernet.

Enjoy!

3D printing again

In Hardware on Oct 23, 2010 at 00:01

Finally found some time to fix the clogged extruder Mk4 I had on the CupCake. A new heater + extrusion head did the trick. Well, almost… watch the leaked blob of ABS on top of the extruder heat barrier:

Dsc 2138

As a result, the first part I printed did not contain enough material, and ended up too fragile for actual use. That’s part of a micro-lathe I’m printing for someone else, btw.

So I disassembled the extruder again, and replaced the PTFE rod with a new black one:

Dsc 2141

Yippie, now it’s working again. I’ve also upgraded to a heated build platform, which works great – no warping and the parts come off real easy, with raft and all:

Dsc 2148

Here’s a component from the Wade extruder which I’ll need for the Mendel:

Dsc 2151

Alas, not all is well yet. This was supposed to be the other half of that gearwheel pair:

Dsc 2150

Hmm, looks more like a cupcake to me…

The other nasty problem is that the main body of the Wade extruder I’m trying to build is too large for the CupCake. I can’t print it! Now I’ll either have to buy a complete extruder for the Mendel or find some other extruder which works with it. So as far as the next-generation “Mendel” is concerned, I still need to assemble the electronics and find some good extruder for it. Drat, it’s always those last 20% that bite…

Wireless mousetrap

In Hardware on Oct 22, 2010 at 00:01

Mathias Johansson recently sent me a description of his project which is just too neat to pass up. So here goes – photos by him and most of the text is also adapted from what he told me in a few emails.

I’ll let Mathias introduce his project:

It is late autumn here in Sweden and the mice starts to search for a winter home. They do normally stay outside modern constructions but I have a croft that is over 100 years old and they tend to like my attic. Mice are pretty cute, and I wish them no harm, but they damage my ceilings! Therefore I have to catch them in traps and transport them deep into the forest and release them near the brink of a stream.

Some properties of each of the three traps built so far:

  • Does not harm the mouse
  • Immediately reports which trap is closed on a webpage
  • Disables itself if the alarm system is turned on for longer periods of absence

Here’s the mousetrap, ready to go:

Mouse Trap

With a guest…

Mouse in Trap

And here the status page indicating which traps have been sprung:

Homepage

The schematic was implemented on what looks like a mini breadboard, here’s the Fritzing version of it:

Musetrap v0 1 bb

The infrared receiver was salvaged from a BoeBot and is used to detect the presence of a guest to spring the trap. Note that by the time it detects something, the tail of the mouse will be mostly inside the trap, so this is a gentle as it gets – well, if you’re a mouse…

Mathias concludes with:

Feel free to publish the pictures (and text) in your “success story” forum or elsewhere on your web-page if you think they are of interest to others or inspire new uses for the JeeNode.

Thanks, Mathias, for sharing your ideas and your delightful rodent-friendly project!

Reporting motion

In AVR, Software on Oct 21, 2010 at 00:01

Yesterday’s post presented a new sketch which did everything the old sketch did, except report motion. The reason was that the requirements for reporting motion are quite different from the rest: it has to be reported right away – using ACKs, time-outs, and retries to make sure this message is properly received.

The latest version of roomNode.pde now adds the missing logic. And it does indeed get a lot messier – doubling the total number of lines in the source code.

Here is the new loop() code:

Screen Shot 2010 10 19 at 22.37.41

The key change is that there is now a check for “pir.triggered()” which will be called outside all normal scheduling actions. Note that this code is still using scheduler.pollWaiting(), so the code is still spending most of its time in power-down mode.

Except that now, we’re also setting up a pin-change interrupt for the PIR sensor:

Screen Shot 2010 10 19 at 22.40.16

The new code to handle these PIR triggers is as follows:

Screen Shot 2010 10 19 at 22.42.14

So instead of folding this complicated case into the rest of the code, when a PIR trigger goes off, we now simply send that packet out and wait for the ACK, repeating it a few times if necessary. The normal measurement and reporting tasks are not affected by any of this, other than that the measurement scheduling is postponed a bit to avoid triggering another report right away.

The new PIR motion sensor turns out to be quite convenient, because it has an on-board trimpot to set the re-trigger timeout. As long as motion is detected more often than this threshold, the PIR output will remain 1, so there is no need to play tricks in software to avoid constant triggers. We’ll get one pin change for the start of motion, and another one when no motion has been detected for a preset amount of time.

Having said that, I’ve implemented a similar re-triggerable one-shot mechanism in software anyway, because my older nodes use the ELV PIR sensor, which send out a pulse for each motion trigger. So all ON pulses within 30 seconds of each other get coalesced into one.

To illustrate that the system is still doing almost nothing most of the time, I added a debug mode which prints a “.” on each iteration of loop(). In normal Arduino sketches, this would cause an incessant stream of characters to be printed out, but in this sketch there are just a few:

Screen Shot 2010 10 19 at 22.12.35

Motion detection now works more or less independently of the normal measure / report tasks.

There are still some rough edges, but I expect this new code to perform considerably better in terms of battery lifetime already. The dreaded battery rundown problem when the central node is not reachable should be gone. All that remains are a few attempts (I’ve set it to 5) whenever the PIR sensor turns on or off. In both cases the ACK has to be received within 10 milliseconds – after that the sketch enters power-down mode again.

The new code should also make it much easier to add sensor types (switches, hall-effect, 1-wire, barometer).

FWIW, this code needs 8238 bytes (without serial I/O), so it’ll still easily fit in an ATmega168. Without SHT11 (which uses floating point) that drops to 5682 bytes, including the RF12 driver. How’s that for a WSN node!

New roomNode code

In AVR, Software on Oct 20, 2010 at 00:01

It’s time to start putting the pieces together now: sensor readout, scheduling of measurements and packet sends, and low-power mode. Looks like the code in the Ports and RF12 libraries is now making this easier than ever.

There’s a new roomNode.pde sketch which illustrates the whole shebang. At 145 lines, it’s a bit too long to include here in full, but I’ll show some of the interesting pieces.

Note that this version implements everything except motion reporting, which is a bit more complex.

Following the good ol’ top-down tradition, first the setup() and loop() code:

Screen Shot 2010 10 19 at 14.06.12

It starts the measurement loop, which then keeps itself running periodically. The report activity is started every once in a while. Note also the “now” variable, which will make it easier to use 2-byte ints in the logic which will decide later about when to report motion, etc.

The measurement code depends completely on what sensors are supported, and is pretty straightforward:

Screen Shot 2010 10 19 at 14.10.36

No surprises, we just have to be careful to do things in an energy-efficient manner. All the readings end up in the “payload” struct.

And here’s the reporting code:

Screen Shot 2010 10 19 at 14.14.24

Here’s some sample output on the serial port:

Screen Shot 2010 10 19 at 14.18.17

I still need to add the logic for motion detection, but with the new scheduling capabiltities, I expect that extra complexity to stay within a small portion of the code – unlike the current rooms.pde sketch, where everything seems to affect everything else.

The best part? My multimeter stays mostly under 60 µa, i.e. the low-power logic is automatically kicking in!

Room Node – next steps

In AVR, Software on Oct 19, 2010 at 00:01

First of all: thanks to everyone who commented on the recent posts, both online and by direct email. Fantastic feedback, lots of ideas, and several valuable corrections.

In yesterday’s post, I agonized about how hard it is to track time in some sort of reasonably continuous way when most of it is spent in comatose state. Fortunately, a Room Node won’t need that awareness very much. I just wanted to show how things get complex in terms of watchdogs running-but-not-yet-expired, and multiple interrupt sources.

For the next version of the rooms.pde sketch, my plan of attack is to simply ignore the issue. The watchdog will be used for guaranteed wake-up, while PIR motion detection and radio reception interrupts will simply cause the millis() clock to lose time, occasionally.

For ACKs, I’m going to start simple and wait for up to 2 milliseconds in idle mode, before resuming lower-power options again. One interesting suggestion was to slow down the clock while doing so (through the system clock pre-scaler), but that has to be done with care because a slower-running ATmega will also respond more slowly to RF12 driver interrupts – and there is not that much slack there.

Here’s the updated Scheduler class, now included in the Ports library:

Screen Shot 2010 10 18 at 22.54.27

Only a minor extension on the API side: by using pollWaiting() instead of poll(), you can tell the system to enter low-power mode until the next scheduled task. If another interrupt pre-empts this wait cycle, then it’ll break out of power-down mode and go through the loop and re-enter the low-power state the next time around.

The other change I’m currently testing is that a few Scheduler functions can be called from interrupt code, so this provides a way for interrupt code to safely schedule, resume, or cancel a task “via the main thread”.

This is the tiny change needed to make the schedule.pde demo energy efficient:

Screen Shot 2010 10 18 at 23.01.24

However, because it now uses the watchdog, you also need to add the following boilerplate to the sketch:

ISR(WDT_vect) { Sleepy::watchdogEvent(); }

The demo now draws 25 µA when I remove the LEDs.

So here’s the deal: if you can manage to write all your code is such a way that it never calls delay() – or delayMicroseconds() with large values – and instead uses this Scheduler-with-tasks approach, then you’ll get a fairly low power usage almost for free… i.e. without having to do anything else! (just don’t forget to turn the radio on and off as needed)

The code has been checked into subversion, and is also available as ZIP archive – see the Ports info.

Update – more changes checked in to better handle watchdog vs other interrupts.

Tracking time in your sleep

In AVR, Software on Oct 18, 2010 at 00:01

No, this isn’t a story about bio-rhythms :)

One of the challenges I’ll be up against with Room Nodes is how to keep track of time. The fact is that an ATmega is extraordinarily power efficient when turned off, and with it a JeeNode – under a few microamps if you get all the little details right. That leads to battery lifetimes which are essentially only determined by self-discharge!

But there are two problems with power off: 1) you need to be 100% sure that some external event will pull the ATmega out of this comatose state again, and 2) you can completely lose track of time.

Wireless packets are of no use for power-down mode: the RFM12B consumes many milliamps when turned on to receive packets. So you can’t leave the radio on and expect some external packets to tell you what time it is.

Meet the watchdog…

Fortunately, the ATmega has a watchdog, which runs on an internal oscillator. It isn’t quite as accurate, but it’ll let you wake up after 16 ms, 32ms, … up to 8 seconds. Accuracy isn’t such a big deal for Room Nodes: I don’t really need to know the temperature on that strict a schedule. Once every 4 .. 6 minutes is fine, who cares…

There’s a Sleepy class in the Ports library, which manages the watchdog. It can be used to “lose time” in a decently accurate way, and will use the slowest watchdog settings it can to get it out of power-down mode at just about the right time. To not disrupt too many activities, the “millis()” timer is then adjusted as if the clock had been running constantly. Great, works pretty well.

It’s not enough, though.

As planned for the next implementation, a Room Node needs to sleep one minute between wakeups to readout some sensors, but it also needs to wake up right away if the motion sensor triggers.

One solution would be to wake up every 100 ms or so, and check the PIR motion sensor to see whether it changes. Not perfect, but a 0.1s delay is not the end of the world. What’s worse though is that this node will now wake up 14,400 times per day, just to check a pin which occasionally might change. This sort of polling is bound to waste some power.

Meet the pin-change interrupt…

This is where pin-change interrupts come in, They allow going into full power-down, and then getting woken up by a change on any of a specified set of pins. Which is perfect, right?

Eh… not so fast:

Screen Shot 2010 10 17 at 22.05.30

Q: What time is it when the pin-change occurred?

A: No idea. Somewhere between the last watchdog and the one which will come next?

IOW, the trouble with the watchdog is that you still don’t really track time. You just know (approximately) what time it is when the watchdog fires again.

If the watchdog fires say every 8 seconds, then all we know at the time of a pin-change interrupt, is that we’re somewhere inside that 8s cycle.

We can only get back on track by waiting for that next watchdog again (and what if the pin change fires a second time?). In the mean time, our best bet is to assume the pin change happened at the very start of the watchdog cycle. That way we only need to move the clock forward a little once the watchdog lets us deduce the correct moment. FYI: everything is better than adjusting a clock backwards (timers firing again, too fast, etc).

Now as I said before, I don’t really mind losing track of time to a certain extent. But if we’re using 8-second intervals to get from one important measurement time to the next, i.e. to implement a 1-minute readout interval, then we basically get an 8-second inaccuracy whenever the PIR motion detector triggers.

That’s tricky. Motion detection should be reported right away, with an ACK since it’s such an important event.

So we’re somehere inside that 8-second watchdog cycle, and now we want to efficiently go through a wireless packet send and an ACK cycle? How do you do that? You could set the watchdog to 16 ms and then start the receiver and power down. The reception of an ACK or the watchdog will get us back, right? This way we don’t spend too much time waiting for an ack with the receiver turned on, guzzling electrons.

The trouble is that the watchdog is not available at this point: we still want to let that original 8-second cycle complete to get our knowledge of time back. Remember that the watchdog was started to get us back out in 8 seconds, but that it got pre-empted by a pin-change.

Let me try an analogy: the watchdog is like throwing a ball straight up into the air and going to sleep, in the knowledge that the ball will hit us and wake us up a known amount of time from now. In itself a pretty neat trick to keep track of the passage of time, when you don’t have a clock. Well, maybe not for humans…

The scenario that messes this up is that something else woke us up before the ball came down. If we re-use that ball for something else, then we have lost our way to track time. If we let that ball bring us back into sync, fine, but then it’ll be unavailable for other timing tasks.

I can think of a couple solutions:

  • Dribble – never use the watchdog for very long periods of time. Keep waking up very frequently, then an occasional pin-change won’t throw us off by much.

  • Delegate – get back on track by asking for an ack which tells us what time it is. This relies on a central receiving node (which is always on anyway), to tell us how to adjust our clock again.

  • Fudge it – don’t use the watchdog timer, but go into idle mode to wait for the ack, and make that idle period as short as possible – perhaps 2 ms. IOW, the ACK has to reach us within 2 milliseconds, and we’re not dropping into complete powerdown during that time. We might even get really smart about this and require that the reply come back exactly 1 .. 2 ms after the send, and then turn off the radio for 1 ms, before turning it on for 1 ms. Sounds crazy, until you realize that 1 ms of radio time uses as much energy as 5 seconds of power down time – which adds up over a year! This is a bit like what TDMA does, BTW.

All three options look practical enough to consider. Dribbling uses slightly more power, but probably not that much. Delegation requires a central node which plays along and replies with an informative ack (but longer packets take longer to receive, oops!). Fudging it means the ATmega will be in idle mode a millisec or two, which is perhaps not that wasteful (I haven’t done the math on that yet).

So there you go. Low power stuff isn’t always trivial, once you start pushing for the real gains…

Scheduling multiple tasks

In Software on Oct 17, 2010 at 00:01

Since Room Nodes are going to become more sophisticated in terms of timing, I’m adding some support code to simplify my work later on. In most cases, I think it’s not a good idea to start generalizing too early, but this is a pretty common utility: scheduling multiple activities in parallel. No rocket science, and badly needed…

So here’s a little “Scheduler” class I’m going to add to the Ports library:

Screen Shot 2010 10 17 at 00.00.53

Nothing fancy. My main concern is to keep RAM usage low. So the idea is that you can have a fixed number of tasks, each one with (at most) one timer running. Timers can be started and cancelled at will. The term “task” is used very loosely here: anything that needs to have an independent timer mechanism can be treated as a separate task. This is not multi-tasking or threading – just a way to manage activities which need to be performed some time into the future.

Unlike the Millitimer class, which works for durations up to 60000 milliseconds, the Scheduler class works in tenths of seconds, and supports durations from 0 to 6000 seconds, i.e. over an hour and a half. A zero duration means: run the associated task as soon as possible.

Probably best to show this in action with an example:

Screen Shot 2010 10 16 at 23.56.53

The way to use the scheduler, is to define an enum with all the tasks there can be, plus a “TASK_LIMIT” value, which is in fact simply the number of tasks.

Then you declare a “Scheduler” instance, and give it that TASK_LIMIT value, so it can allocate the proper amount of memory (each task needs only 2 bytes).

The only remaining thing to do is call the “poll()” member and handle each task request in a big switch statement.

The demo will blink two LEDs at different rates, the classical (and simplest) example of doing two different things at the same time. Eh… almost the same time.

I’m still putting the finishing touches on this code and making sure that this will play nicely with low-power and power-down modes, so it hasn’t been checked in yet – it should all be ready in at most a day or two. At which time this will become part of the Ports library, along with the above “schedule.pde” example sketch.

Modular nodes, revisited

In Software on Oct 16, 2010 at 00:01

As pointed out in the comments yesterday, “nodes” in a WSN should to be more parametrized. With ports, it’s very easy to mix and match different sensors – creating nodes which are not all the same should be equally easy.

I’ve touched on a related topic before in a post titled Modular nodes.

Ideally, you want to write interface code for say a PIR motion sensor once, and then re-use it in different nodes. Same for an SHT11 temperature/humidity sensor, an IR send/receive sensor, a barometer, door switches, an OOK receiver, and so on – the list is bound to grow considerably over time.

Even “more ideally” (heh), you probably would like someone else to already have written that interface code, so you can just fill in the parameters and incorporate it into your own room-or-other node.

In fact, the whole (modular!) Plugs & Ports concept of JeeNodes is yearning for this type of modularity to be carried through to the software.

To achieve such modularity all the way through, several questions need to be answered:

  • are these interface code “snippets” always very small and self-contained, or do they need additional C/C++ source files?
  • can interfaces depend on other interfaces / is a class hierarchy the best way to modularize such dependencies and derivations?
  • can we have multiple instances of the same interface in a single node? (answer: yes, for example multiple door-open sensors, attached to different I/O pins)
  • how do we deal with a mix of interfaces which use different timing periods for readout?
  • how do we compose packets to send, if the information types vary?

One way to implement this modularity, is what I’ve been doing in the Ports library until now: define and implement C++ classes for each interface, and then create (static) instances of each interface needed in a particular node.

This is an extract of the Ports.h library header file:

Screen Shot 2010 10 15 at 21.54.25

It works – and I think it’s a decent start – but it doesn’t go far enough:

  • Many configuration parameters are variables (and data members inside C++ objects), even though they are essentially contant (the port number, an I2C device ID, I/O pin choices, etc). This eats up scarce RAM space, and prevents the compiler from fully optimizing the code. The “heavy” solution to this is C++ templates, as I’ve written about in threeolderposts. Trouble is: C++ templates are “viral”, once you start on that path, everything tends to become a template. Not my idea of simplicity…

  • I want to figure out what a good set of reporting periods is, to minimize the number of packets sent, for example. This task comes back with every type of node, so having some automated tool to help with that effort would be useful.

  • There can be severe resource constraints in low-power nodes. I’d like to see what the RAM and EEPROM (and FLASH) usage is when choosing a specific mix of interfaces. I’d also like to find out whether the interrupts can co-exist and still service everything sufficiently quickly. And I’d like to get estimates for battery life. None of this is impossible, even if unnecessary for a first implementation.

  • Implementing pin-change interrupt handlers is not easy to fit into C++ as run-time mechanism, even though for any given interface mix it is very simple to generate the interrupt handler code for it.

  • The result of a choice of interfaces is not just a sketch – it also implies specific packet structures, as used for getting data across. And indirectly, it also means there has to be something node-specific at the central node (not necessarily in that receiving node, it could be code that runs on an attached PC).

  • If the number of interfaces grows considerably, and if more people were to start implementing such interfaces, then the management and versioning of all these interface definitions (code, data, docs) needs to be addressed.

What this points to IMO, is the need for a “configurator” or “wizard” type tool, which knows about a large number of interfaces, and which produces a sketch when given a bunch of configuration choices. An even more convenient tool would let me manage my entire collection of nodes, so I can make most configuration choices once, and then manage all node definitions together. It’d let me add and update interfaces and nodes as needed, over time:

Screen Shot 2010 10 15 at 22.30.14

What comes out is still a C/C++ coded sketch, since that’s what needs to be uploaded to the node.

What should also come out (not included in the above diagram), are one or more packet structure definitions, as well as the code (or data definitions) needed to decode those packets again.

With this approach, you can pick the hardware needed for a specific node, enter your choices into the configurator, and be done with it. Upload the sketch it generated, turn the node on, and launch the central server with the information it needs to understand the new incoming data packets. For other nodes, or to make changes, simply rinse and repeat…

I haven’t decided yet whether I’ll actually go for this. It’s fairly ambitious, even for a simple first implementation. But it sure would scratch an itch of mine…

Room Node redesign

In Software on Oct 15, 2010 at 00:00

Room nodes were one of the first reasons I came up with the JeeNode in the first place. It has all evolved a bit since then (and it will evolve further until there is a good enclosure):

Dsc 2134

It’s now time to start redesigning the software for Room Nodes. The main reason being that the code needs to take more advantage of all the low-power savings achievable with JeeNodes. Current battery lifetimes are 1..2 months, using 3x AA alkaline batteries. That’s not nearly good enough – I really do not want to go through the house replacing tons of batteries every month or so (even rechargable ones).

I can think of two reasons why the current rooms.pde sketch isn’t doing that well:

  1. The “easy transmission” mechanism does retries when no ACK is received – this is a good idea in general, but there is no exponential backoff mechanism in place in case the central node is off, mal-functioning, out of range, or if there is simply too much interference at times. What’s even worse is that the node sits there waiting for an ACK for many seconds, guzzling electricity like crazy with the RFM12B and the ATmega full on!

  2. The code sends out a fresh packet on each transition from the PIR motion detector. If the sensor is in a room where motion is very common, then new packets may get sent out far more often than necessary – and quickly drain the battery.

So the question is how to improve on this. One thing I’m going to do is side-step the rf12_easyPoll() etc. interface for the next Room Node implementation, and go back to rf12_recvDone() etc. Coding at this slightly lower level is more work, but also gives me substantially more control in return.

Next, some decisions need to be made about how often and when to send out packets, and when to work with acknowledgements. Here are some of my considerations for that – evidently not everyone will agree with this set of choices, but I think they are sufficiently general to work in many cases:

  • Temperature, humidity, and light levels need only be sent out once per five minutes. Perhaps averaging the values once a minute to smooth out measurement variations.

  • No need to use ACKs for this. Not knowing the exact temperature for the past hour is not the end of the world. The new logic can just send out readings once every five minutes, with the expectation that most of them will usually come in just fine.

  • The PIR motion sensor is a completely different matter: I’d like to be told when new motion is detected as quickly as possible, i.e. within less than a second.

  • Then again, once motion has been detected, I don’t really care too much about frequent vs. infrequent motion. Telling me once a minute whether any motion was detected in that past minute should be enough.

  • Once motion ceases to be detected for a minute, the system goes back into its highly responsive mode, i.e. the moment new motion is detected, I want to hear about it again, right away.

  • The system could send different packets for different triggers, but I don’t want to complicate things unnecessarily. My expectation is that in a room with no motion, there will be one packet going out every 5 minutes, with one “wasted” bit for the motion detector state. In a busy room, there will be a packet going out up to once a minute due to the motion detector firing all the time. The number of bytes saved is probably not worth the extra trouble of having to deal with different types of packets at the receiving end.

  • The last reason to send out packets, is when the battery voltage of the sensor node is getting low. This can be checked once a minute, along with the temp/humid/light cycle.

  • Changes in motion or battery level are important events. These should use the acknowledge mechanism to make sure the event gets to its destination even with occasional packet loss.

  • The mechanism for acks needs to be more sophisticated than it is now. The first big optimization is to only wait a few milliseconds for the ACK. If it doesn’t come in, go back to sleep, and try again a second later. That should by itself reduce the current worst-case current draw by two orders of magnitude.

  • Refinements such as exponential back-off would be nice, but I don’t expect them to make that much of a difference, in a home monitoring setup where all serious failures are likely to be noticed and resolved within a day.

  • Another refinement I don’t care too much about, is to adjust the 5-minute reporting interval depending on the measured light levels. Note that this does not apply to motion (which must always remain alert) – it’s just a way to reduce packet transmissions even further at times when very little happens anyway. I’m not sure it will increase battery life that much, though: brief packet transmissions are not the main power drain, the always-on PIR is the main determinant for battery life, as far as I can tell.

The highest packet frequency for this new approach is almost two packets per minute: motion is detected, then one minute later a packet comes in reporting that it is no longer being detected, and then immediately after that new motion is detected again.

So if you sit still in front of a Room Node, and move exactly once every 61 seconds, you’ll get extra brownie points and trigger twice as many packets as when you move around all the time. I’m willing to dismiss that scenario as being almost hypothetical :) – I can’t prove it, but my hunch is that this worst-case scenario will always exist, no matter what the algorithm is.

IR decoding with pin-change interrupts

In AVR, Hardware, Software on Oct 14, 2010 at 00:01

Yesterday’s post described a new “InfraredPlug” class which handles the main task of decoding IR pulse timings. The “irq_recv.pde” example sketch presented there depended on constant polling to keep the process going, i.e. there has to be a line like this in loop():

    ir.poll();

Worse, the accuracy of the whole process depends on calling this really often, i.e. at least every 100 µs or so. This is necessary to be able to time the pulse widths sufficiently accurately.

Can’t we do better?

Sure we can. The trick is to use interrupts instead of polling. Since I was anticipating support for pin-change interrupts, I already designed the class API for it. And because of that, the changes needed to switch to an interrupt-driven sketch are surprisingly small.

I’ve added a new irq_send_irq.pde sketch to the Ports library, which illustrates this.

The differences between using polling mode and pin-change interrupts in the code are as follows. First of all, we need to add an interrupt handler:

Screen Shot 2010 10 13 at 00.26.10

Second, we need to enable those interrupts on AIO2, i.e. analog pin 1:

Screen Shot 2010 10 13 at 00.26.44

And lastly, we can now get rid of that nasty poll() call in the loop:

Screen Shot 2010 10 13 at 00.27.51

That’s all there is to it. Does it still work? Of course:

Screen Shot 2010 10 13 at 00.29.16

Note: I made some small changes in the InfraredPlug implementation to tolerate interrupts and avoid race conditions.

This all seems like an insignificant change, but keep in mind that this completely changes the real-time requirements: instead of having to poll several thousands of times per second to avoid missing pulses or measuring them incorrectly, we can now check for results whenever we feel like it. Waiting too long would still miss data packets of course, but this means our code can now continue to do other lengthy things (or go into a low-power mode). Checking for incoming packets a few times a second is sufficient (IR remotes send out a packet every 100 ms or so while a button is pressed).

So the IR decoder now has the same background behavior as the RF12 driver: you don’t need to poll it in real-time, you just need to check once in a while to see whether a new packet has been received. Best of all, perhaps, is that you can continue to use calls to delay() even though they make the main loop less responsive.

There is another side effect of this change: if your code includes a call to “ir.send()”, then the receiver will see your own transmission, and report it as an incoming packet as well. Which shows that it’s running in the background. This could even be used for collision detection if you want to build a fancy IR wireless network on top of all this.

So there you go: an improved version of the InfraredPlug class, which lets you use either explicit polling or pin-change interrupts. The choice is yours…

Decoding IR pulses

In Hardware, Software on Oct 13, 2010 at 00:01

After the last few posts, it must come as no surprise that I’ve been working on a new Infrared Plug – so now it’s time to start exploring the software side of things. Note that IR reception doesn’t really need a plug at all, I simply inserted a TSOP32238 IR decoder chip into port 2 while debugging the code:

Dsc 2129

Note: I’ll be using the TSOP34838 for the planned Infrared Plug. It only differs in pinout (!) – and both can be used at 3.3V, which is essential.

In preparation of that new plug (atoms need time!), I’ve added a new “InfraredPlug” class to the Ports library, with the following interface:

Screen Shot 2010 10 12 at 17.30.37

This allows receiving IR codes on the AIO pin of any port, as well as sending out IR bit patterns on the DIO pin.

There’s a new ir_recv.pde sketch to demonstrate reception of arbitrary IR signals:

Screen Shot 2010 10 12 at 17.33.59

Here is some sample output, using two different Apple remotes which send using the NEC protocol, as described on this excellent site by San Bergmans:

Screen Shot 2010 10 12 at 16.49.22

You’re looking at a decoded bit stream – some minor processing will be needed to extract the actual data bits from each packet. This was done to make the decoder as flexible as possible – allowing it to handle all sorts of remotes.

The basic idea is that you set up the InfraredPlug instance with “slot” and “gap” parameters. The slot value (1..255) specifies the granularity of the time slots used by the decoder (in units of 4 µs). The default slot value is 140, this corresponds to time slots which are 560 µs wide. De gap value tells the driver when to consider a data packet as being complete (in units of 256 µs). The default gap value is 80, i.e. treat a series of pulses as one packet once 20 ms have elapsed after the last pulse.

The values can be changed with the “configure()” method. In fact, ir_demo will change the slot value when it receives an integer followed by lowercase “s” on the serial port (not echoed). The default setting on startup is “140s”. For RC5 codes, use “222s”, for RC6 “111s”, and for Nokia remotes “125s”, to name a few.

Each time a packet has been received, ir_demo will send the decoded data to the serial port. The data consists of a series of hex digits, each representing one 4-bit nibble of data, as returned by the InfraredPlug class:

  • 0..9 = 1..10 slots
  • A = 10 = 11 or 12 slots
  • B = 11 = 13 or 14 slots
  • C = 12 = 15 or 16 slots
  • D = 13 = 17 or 18 slots
  • E = 14 = 19 or 20 slots
  • F = 15 = 21 or more slots

The nibbles at even positions correspond to pulse ON widths, the nibbles at odd positions are pulse OFF widths – both as a multiple of the configured slot time, with the above adjustment of longer pulses applied.

The “send()” method uses a different format. You give it a bit pattern and the number of bits to send. Each bit represents an ON or OFF signal value. The duration of each bit is the same slot value as used in the receiver.

That’s it. A simple design which should be able to support lots of different appliances and remotes.

JeeMon device discovery

In Software on Oct 12, 2010 at 00:01

Ok, I must admit that JeeMon has been a bit too ambitious in its original inception. It works quite nicely here at Jee Labs, but there are just too many hoops you have to jump through to make it happen on your own.

I’ll first explain why things are the way they are, and how that is supposed to work, and then I’ll present a different setup for the OOK Scope which jettisons all that machinery and lets you use the OOK Scope with nothing but a single source file and JeeMon.

The idea behind the “Serial” and “JeeSketch” rigs (code modules) in JeeMon, is that it should be possible to respond to changes in interfaces dynamically. So there’s a way to scan for USB interfaces periodically:

Serial periodicScan <cmd>

This will compare the list of USB devices it sees with the list it saw last time (once every 5 seconds by default). And then call the specified <cmd> whenever an interface is added or has gone away. Only FTDI interfaces are detected, by the way.

The next step is to decide what to do when a new USB device is attached. I’ve been using a convention for some time now, whereby every sketch starts by sending out its own name, with optional version and configuration details. For example, RF12demo will send out a string like this to the USB connection when it starts up:

[RF12demo.6] A i1 g5 @ 868 MHz

The trick is to wait for such a string when JeeMon detects the device and opens it. This is handled by the “JeeSketch” rig. Once the sketch type is known, JeeMon then tries to locate a “host.tcl” driver for it. It does this by looking in a directory, as configured at start up. I’ve been placing all my drivers in a directory called “sketches”, so my startup includes the following line:

JeeSketch register ./sketches

When RF12demo connects, JeeMon checks whether “./sketches/RF12demo/host.tcl” exists, and runs it.

Similarly, when plugging in a JeeNode running the OOK Scope sketch, it announces itself as:

[ookScope]

The script “./sketches/ookScope/host.tcl” then gets started, it creates a GUI window, takes over the communication link to process all incoming (binary) data bytes, and does its pulse histogram thing.

So far so good. It’s a nicely modular mechanism. I can add a new sketch, i.e. a “blah.pde” file for use in a JeeNode, and add a matching “host.tcl” script alongside to deal with the communication in any way it likes. Then, all I need to do is plug the device in and everything starts up. With a bit of care, everything is also shut down and cleaned up again when the device is removed.

Unfortunately, that’s not the end of the story. One of the important devices I want to support is a JeeNode or JeeLink running RF12demo. But how can JeeMon deal with remote nodes? After all, all they do is send packets to the central device. Each of these nodes will be running a sketch, and not all of them are necessarily the same. So we either need some sort of auto-discovery or some central configuration file. For a first implementation, I decided to use a configuration file to try and keep things, eh, simple. Which is why my startup code also contains these two commands:

set appDir [file dir [dict get [info frame 0] file]]
Config setup $appDir/config.txt

That’s a tricky way of making sure that the “config.txt” file will be picked up from the same directory as the source code, i.e. the “application.tcl” file.

I’ll refrain from describing the config.txt file in full detail. Let me just include an example which I’ve been using around here:


Screen Shot 2010 10 11 at 22.52.15


As with any such type of “registry”, you can see lots of little config details, for use in different modules and parts of the code. Even some obsolete stuff, in fact.

Does it work? Oh, sure, it works great and it’s very easy to extend for new modules and usage scenarios. Even node discovery works nicely, both coming on-line and dropping off-line, as seen in the voltmeter demo.

But there’s a problem with what I’ve described so far…

… there’s too much rope – to hang yourself. It’s brittle, it needs lots of documentation to use this stuff (unless you’re willing to dive into the JeeMon Tcl code), and it’s just too much trouble if you want to do something simple with JeeMon, like run the OOK Scope and nothing else. The entry curve is way too steep.

I can’t say I’ve figured out an alternative. There is a lot of ground to cover, and it is fairly hard to implement a system which dynamically adapts to interfaces getting plugged in and nodes coming (wirelessly) online.

But at the end of the day, all that extra bagage is unnecessary for simple cases.

Fortunately, JeeMon is flexible enough to adapt in any way I want. I don’t have to use any of the above machinery. So here’s the OOK Scope logic as a single “application.tcl” file. No scanning, no config, nothing:

Screen Shot 2010 10 11 at 23.05.06

The full code is available here. To run this version of the OOK Scope, download that file, make sure it is called “application.tcl”, and place it next to your JeeMon executable. Then launch JeeMon. Just make sure to have the JeeNode running ookScope.pde plugged in.

If more than one FTDI interface is found, you will be asked to pick one:

Screen Shot 2010 10 11 at 23.22.45

That’s it: ookScope.pde, application.tcl, plus JeeMon – should work on Windows, Mac OS X, and Linux.

IR pulse pickup

In Hardware, Software on Oct 11, 2010 at 00:01

With the sending of IR pulses out of the way, the next step is picking them up. That’s a lot simpler since there are various sensors which do this.

But unfortunately I only have a QSC113 IR photo transistor at hand right now. It doesn’t have any sort of 38 kHz filtering, it just senses IR light. Then again, it still seems to work – I don’t understand why, to be honest:

Dsc 2123

Anyway, this seemed like a good test case to throw at the OOK Scope. The name is a bit confusing actually – it was used to analyze OOK-encoded radio signals a couple of months ago, but it’s really more general than that. What the OOK Scope does, is create a histogram of incoming pulse widths (20 .. 4604 µs with the current code).

As a refresher, here’s some OOK Scope output with a 433 MHz radio attached, after pressing buttons on my KAKU remote control:

Screen Shot 2010 10 10 at 22.06.54

The histogram runs sideways: at the top are the short pulses, at the bottom the long pulses. The longer the bar, the more pulses of that length have been picked up.

Now the fun part is that this same setup can also be used for IR pulses:

Dsc 2122

I simply replaced the OOK radio in port 2 by my IR photo transistor, with the short lead to GND and the long lead to AIO2. Here’s what comes out when using the Apple remote:

Screen Shot 2010 10 10 at 22.47.36

The pulses are a lot sharper, which is not surprising since it’s picking up direct light pulses now, not radiomagnetic waves of a much lower frequency and intensity that has to be detected and converted into an electrical signal by the radio.

Reading these values is a bit more work, because the ookScope.pde does some trickery to increase the range of pulse widths it can report in a single byte:

if (width >= 128) {
    width = (width >> 1) + 64;
    if (width >= 192) {
        width = (width >> 1) + 96;
        if (width >= 224) {
            width = (width >> 1) + 112;
            if (width >= 240) {
                width = (width >> 1) + 120;
                if (width >= 248) {
                    width = (width >> 1) + 124;
                    if (width >= 252) {
                        width = (width >> 1) + 126;
                        if (width > 255)
                            width = 255;
                    }
                }
            }
        }
    }
}

See the OOK Scope post for details on how this works.

Back to the readings. The values reported are two strong bands centered around ≈ 105 and 158, respectively, with another set of pulses at 224. The pulse widths corresponding to these are ≈ 420 µs, 652 µs, and 1536 µs if I got my calculations right. That last one might be the time between retransmissions.

I’ll have to revisit this with a real 38 kHz filtering IR sensor when I get them in – but that sort of looks right to me. Another remote sending out RC5 codes ended up with very similar pulse widths, but with more variation.

Tomorrow, I’ll describe the OOK Scope setup in more detail, since it doesn’t seem to be working for everyone…

Update – I just figured out the pinout of a 5V sensor with IR filtering (TSOP1138) – here’s what comes out:

Screen Shot 2010 10 10 at 23.32.07

Hm, more variation now. Then again, also a lot more sensitive, it seems. And it looks like it should still be possible to discriminate between the two pulse widths at position 135, i.e. around 568 µs.

The pulse trains are now more consistent on the scope:

Dsc 2124

Note that I’m driving the JeeNode I/O pin to nearly 5V, which isn’t really such a good idea…

PS. That’ a DSO Nano scope, in case you’re wondering…

Generating IR pulses

In Hardware on Oct 10, 2010 at 00:01

There are lots of projects and schematics floating around the web for encoding and decoding IR remote-control pulses. Many MPU-based ones use one of the built-in hardware timers for this, which is understandable since you can’t easily bit-bang your way out of a 13.158 µs time between switching flanks.

But I don’t want to be constrained to a specific pin, nor dedicate a hardware timer to this task.

Instead, I’ve been experimenting with the venerable NE555. Its normal operating voltage is 4.5 .. 16V, but there’s a CMOS version which will easily go down to 3.3V, as preferred by JeeNodes.

So here’s the circuit (from the ICM7555 docs by NXP):

Screen Shot 2010 10 09 at 14.06.34

The RESET pin can turn this thing on and off. It’ll also need an extra transistor to drive a bright IR LED.

Had to try it out, of course (the chip I used wants at least 4.5V, hence the USB power):

Dsc 2118

Great. It works, but at 35.1 kHz the frequency is a bit off.

Here’s a Logic Analyzer screen shot (warning: MDI toolbar madness, flash from the past!):

Screen Shot 2010 10 09 at 23.11.14

(FWIW: my USB Scope and Logic Analyzer now both work properly on Mac OS X under Parallels 6 emulation – I no longer need a dedicated Windows setup.)

Let’s do the math for the components used in the above test setup, with RA = 1.2 kΩ, RB = 18 kΩ, C = 1 nF:

Screen Shot 2010 10 09 at 14.05.11

f = 37.09 kHz  
∂ = 51.6 %

Let’s use the 1 nF capacitor, smaller would make the circuit more sensitive to stray capacitance. Then I get:

RA + 2 RB = 36.315 kΩ

I don’t want to raise RA much, because that would change the duty cycle in the wrong direction: more LED-on time (i.e. higher current draw). I also don’t want to lower it much further, because that would draw more current in the discharge phase (pin 7 pulled low).

Using 1% resistors, RA = 1.5 kΩ and RB = 17.4 kΩ will do:

f = 38.02 kHz  
∂ = 52.1 %

The 1 nF capacitor will have to be 1% too, of course.

I think I’ll try this. What remains – as always! – is the software, to send out the proper IR bit patterns and to decode the ones coming in. It’d be nice if that could be done fully interrupt-driven like the RF12 driver, because then the whole real-time aspect of IR communication would be taken out of the loop(), so to speak.

Bridge Board it is

In Hardware on Oct 9, 2010 at 00:01

Yesterday’s post triggered some great comments and email exchanges. I came up with this 29-pin design:

Jlpcb 116

There’s a lot more to say about the board and the choices that ended up being made for this particular setup, but I’ll refrain from doing so until the pcb is ready and comes back for testing.

Let me just point out the two uncommitted LEDs with current-limiting resistors, as well as the sideways push-button at the top – again uncommitted, but it can easily be tied to the RESET pin.

Note again that this board is for male pins pointing down, so this effectively holds a JeeNode, JeeNode USB, or JeeSMD together with a half- or full-sized breadboard.

Attentive readers will have noticed the list of Arduino pin numbers along almost the entire length of the board. No more guessing or doc searching if you live in the Arduino ecosystem most of the time – Uno, Due, whatever. A few signals come out on more than one pin, but there’s a reason for that…

Onwards!

Experimenter’s setup

In Hardware on Oct 8, 2010 at 00:01

I keep looking for ways to make it easier to try out stuff – since that’s what I tend to do a lot, here at Jee Labs.

Here’s a trial with a graphics LCD I was mucking about with recently:

Dsc 2111

I don’t like it. Even if the JeeNode’s pins were facing down into the solderless breadboard, it eats up a lot of real-estate, while only a few pins are actually used. Part of the reason is that the ports have a lot of duplicated power pins (that’s the whole point when you use them independently).

I’d much rather use the JeeNode as follows:

Dsc 2109

Then you develop, upload, and test things while tethered. And when it’s ready to use elsewhere, just replace the BUB with an AA Power Board:

Dsc 2110

Now I’m wondering if it wouldn’t be useful to create a little “breadboard interface panel”, like this:

Screen Shot 2010 10 07 at 14.43.48

It’s a bit like the Breadboard Connector that is included with each Expander Plug, as described in this post.

The panel would re-route all pins to the pins along the top row of the breadboard, as well as hook up to the two power rails along the top.

The top of the panel could have extensive labeling for reference. Even some port headers to hook up plugs, if I can figure out which orientation might work best. No components, it’d just be a little back, eh, I mean, front-plane.

Over-packaging

In Hardware on Oct 7, 2010 at 00:01

I know I’ve sometimes “under-packaged” things…

But this is sort of the other extreme. A package with 80+ PCB relays from Conrad came in the following box:

Dsc 2009

That’s a 50 x 40 x 30 cm box, i.e. 60 liters of (mostly air).

The payload was this, which is admittedly a bit awkward in size:

Dsc 2010

And this is how I’m storing it at Jee Labs, until the plug PCB’s come in:

Dsc 2011

That’s a 11 x 7 x 5 cm box (they barely fit), or 0.385 liter.

A 155-fold reduction in size. Pfff…

Room Node battery life

In AVR, Hardware on Oct 6, 2010 at 00:01

The current Room Node sketch only gets 1..2 months of life out of a 3x alkaline AA battery pack. Not enough – by far – for practical use around the house.

The good news is that it’s almost entirely a software issue. There have been JeeNodes running for many months now, some up to 10 months, so there is no hardware limitation to achieve such lifetimes.

In fact, I’d like to push it a bit further and see how long one could run a Room Node off a single rechargable AA battery using the AA Power board. If it’s not that long, I could still opt for the 3x AA pack.

Let’s estimate the idle current draw of a JeeNode first.

The big consumer is the PIR sensor. I recently switched to a new one, because it only needs 3.3V and because of its low current draw. Note that the PIR motion sensor is the only component in the Room Node which should not be disabled during sleep: the whole point is to be able to detect motion at all times, after all. Also, a PIR sensor needs time to stabilize, in the order of a minute, so turning it on briefly is no option.

Here’s the good news:

Dsc 2077

That’s 41 µA idle current.

The JeeNode draws ≈ 3.3 µa, let’s round it up to 4 µA.

The SHT11 draws 2..5 µW, let’s round it up to 2 µA.

So total idle draw is 47 µA.

As it turns out, transmissions consume a neglegible amount of current – if the frequency of transmission is 5 minutes, for example (i.e. 288x per day). The motion detection is different, this needs to go out as soon as there is motion, but this probably won’t happen more than a dozen times a day, on average).

For a transmission, the RFM12B needs to be on for about 2 ms, at which point it draws around 25 mA. With 2 ms once every 300 seconds, that’s a duty cycle of 1:150000, i.e. under 2 µA when averaged out.

So let’s round up and assume that the average current draw of a Room Node is 50 µA @ 3.3V.

A 3x AA battery pack of 2500 mAh would last 50,000 hours, i.e. over 5 years if we ignore the self-discharge rate … assuming that the low-power code is perfect, that is!

Now for the AA Power Board lifetime estimate. At very low current levels, the efficiency of the LTC3525 regulator is 75..80%, according to the datasheet. But first, we need to estimate the current draw. Keep in mind that the power source will be 1.2 .. 1.3V, so we basically need a 3-fold step up. Let’s calculate the input current draw, assuming 1.2V in, 3.3 V out @ 50 µA, and 75% efficiency:

input current = 50 x 3.3 / 1.2 / 0.75 = 183 µA

With an Eneloop battery, I’ll assume it has 1900 mAh capacity, and loses 15% of its charge in two years. Let’s assume that it’ll be used no more than 2 years, and that it lost that 15% charge right at the beginning. Then this is effectively nothing more than a 1600 mAh battery.

Ok, how long can it power a JeeNode plus Room Board?

lifetime = 1600 / 0.183 = 8743 hours = 364 days

So all in all this setup should be able to run just about one year off a single rechargable AA battery. Note that there was some rounding in several places in these calculations, so these estimates are probably a bit conservative.

One year battery life… that’s in fact exactly what I was hoping for!

Now the “only” remaining challenge is to optimize the “rooms.pde” sketch enough to make this happen.

Low-end light box

In Hardware on Oct 5, 2010 at 00:01

Yesterday’s post was about trying to make better pictures for this weblog. The jury is still out on whether the results are dramatically better, but here’s the setup I used – first an add-on for the Nikon D40 built-in flash:

Img 20101003 11

What it does is place a small piece of mirror (extracted from a flatbed scanner) in front of the pop-up flash to reflect all the light up. It’s made of a few little scrap pieces of foam board, glued together to keep the light from directly reaching the object, reflecting the light upwards instead. It’s held in place by friction:

Screen Shot 2010 10 03 at 21.10.03

That solves one half of the problem. The other issue is to get light all around the object to avoid excessively sharp shadows. I made a little “light box” for that, from a little wooden storage box with the interior covered entirely in white foam board:

Img 20101003 12

I can now place the object on the bottom in the back, and sort of peek inside with the camera. The trick is to make sure that the flash sends its light inside the box, bouncing up against the top foam board.

That’s basically it!

The reason I chose this setup, is that I need the height to get the flash inside, and I wanted something that could be easily dismounted and stored away. Like this:

Img 20101003 13

All the foam pieces were cut from five A4-sized panels, because I’ve got lots of ’em lying around. Everything is held together purely by friction, so it’s trivial to assemble and disassemble, but also very easy to replace one of the form boards if it ever got dirty or damaged.

I can also rearrange things, and put the wooden box flat on the table, with the camera looking down into it for shots straight from above.

One detail I’d still like to improve is the amount of diffuse light striking the object at the front. There is currently still a bit of a shadow. One idea is to cover the top with aluminum foil, and perhaps also a surface inside which is slanted forward. Here is a cross section:

Screen Shot 2010 10 03 at 16.27.41

Here is the current setup (no foil yet), with the slanted top panel showing on the left:

Img 20101003 14

Note that foam board is very easy to use for “broken” panels – simply don’t cut them all the way through:

Img 20101003 15

Simple. Now I just need to understand all the adjustments and photo stuff a bit more…

Update – here’s the last trial – different angle, slightly more interesting surfaces, but the FTDI pins are too washed out:

Img 20101004 31

Better pictures?

In Hardware on Oct 4, 2010 at 00:01

Almost all the pictures on this daily weblog are taken with a Nikon D40 + 18..55 mm “kit” lens. I bumped into a fantastic deal two years ago for that setup and have never looked back since then.

Pictures matter on this weblog. In fact I try to get a picture, drawing, or code snapshot image into every single post. It’s simply more fun – to make, to read, and to look back to later.

And until now, almost all pictures were taken in plain daylight (indoor, on a table next to one of the windows). This has been a mixed blessing really – gorgeous light at times, but a widely varying white balance due to the different times of day at which I decide to take some snapshots. And with winter nearing, good daylight conditions are going to get scarce again.

Seeing some of the pictures uploaded to the new “JeeLabs” Flickr group (check it out!), I felt that I really need to beef up the images on future weblog posts a bit. Better close-ups, and more importantly: more consistent lighting conditions and while balance. I’m hoping to do this without killing the low-key basic approach to everything done at Jee Labs.

After some lengthy conversations with Steve Evans and with many thanks for his tips, I’m going to try doing a bit more with flash. At first I wanted to try something with RGB strips, but it simply makes no sense to light up a little scene like a theater (requiring substantial amounts of light!) while the shot only takes a fraction of a second.

There are three problems with using the built-in flash, though:

  • it causes horrible reflections
  • it causes horrible shadows
  • it’s still fairly weak

For decades, I’ve routinely turned off flash for any picture I took. It seemed so ill-suited to capture anything meaningful in a pleasant way, especially with people.

The good news: project / product shots are different…

First of all, everything I shoot for the weblog tends to be fairly small. So a “lightbox” is definitely an option: a micro-studio set up to photograph a very small area with all the lighting in place.

Ok, time for some examples (sorry if it looks a bit like a JeeNode commercial). This is the JeeNode v3, Jul 2009:

Dsc 0424

This is the JeeNode v4, Nov 2009:

Dsc 0767

And here’s the JeeNode v5, Sep 2010:

Dsc 1968

All of them shot out of hand, in daylight, most of them tweaked a bit for exposure, white balance, and shadows, and cropped / rotated for proper framing. No big setups, no comparisons, just some tweaks until it “looks right”, each time.

Here’s a shot of the JeeNode v5, as it came out today, while spending a lot more time on lighting, setup, histograms – but still essentially just some quick ad-hoc tweaking:

Img 20101003 7

Basically, I adjusted the exposure until the background is fully white, and I’ve boosted both color and the sharpness a fair bit (using Nikon’s View NX2 instead of my usual iPhoto).

That last image is definitely closer to the real thing. Much more detail in the shadows and in the highlights. I’m also pretty certain that this new setup can deliver results which are far more repeatable (and at any time of day).

But it is “better”? I’m not convinced. The crystal on the RFM12B is a good example of how you gain detail, but also lose some “vibrance”. Somehow, that JeeNode isn’t jumping off the page anymore … it just sits there.

Oh, here’s another fun shot:

Img 20101003 10

Maybe I’ve simply been staring at too many JeeNodes today. Comments welcome.

Tomorrow, I’ll show the setup I made for this.

Software PWM at 1 KHz

In AVR, Software on Oct 3, 2010 at 00:01

While pondering about some PWM requirements for a new project here, I was looking at the rgbAdjust.pde sketch again, as outlined in the Remote RGB strip control weblog post from a few months back. It does PWM in software, and plays some tricks to be able to do so on up to 8 I/O pins of a JeeNode, i.e. DIO and AIO on all 4 ports. The main requirement there, was that the PWM must happen fast enough to avoid any visible flickering.

The rgbAdjust sketch works as follows: prepare an array with 256 time slots, each indicating whether an I/O pin should be on or off during that time slot. Since each array element consists of one byte, there is room for up to 8 such bit patterns in parallel. Then continuously loop through all slots to “play back” the stored PWM patterns.

There is one additional refinement in that I don’t actually store the values, but only store a 1-bit during the change of values. That shaves off some overhead when rapidly changing I/O pins (see the Flippin’ bits post).

There are some edge cases (there always are, in software), such as dealing with full on and full off. Those two cases require no bit flipping, whereas normally there are always exactly two flips in the 256-cycle loop. But that’s about it. It works well, and when I simplified the code to support only brightness values 0..100 instead of the original 0..255, the PWM rate went up to over 250 Hz, removing all visible flicker.

So what rgbAdjust does, is loop around like crazy, keeping track of which pins to flip. ATmega’s are good at that, and because the RF12 driver is interrupt-driven, you can still continue to receive wireless data and control the RGB settings remotely.

But still, a bit complex for such a simple task. Isn’t there a simpler way?

As it turns out, there is… and it’ll even bump the PWM rate to 1 KHz. I have no idea what our cat sees, but I wouldn’t be surprised if cats turned out to be more sensitive than us humans. And since I intend to put tons of LED strips around the house, it better be pleasant for all its inhabitants!

What occurred to me, is that you could re-use a hardware counter which is always running in the ATmega when working with the Arduino libraries: the TIMER-0 millisecond clock!

It increments every 4 µs, from 0 to 255, and wraps around every 1024 µs. So if we take the current value of the timer as the current time slot, then all we need to do is use that same map as in the original rgbAdjust sketch to set all I/O pins!

Something like this, basically:

Screen Shot 2010 10 01 at 01.41.11

(assuming that the map[] array has been set up properly)

No more complex loops. All we need to do is call this code really, really often. It won’t matter whether some interrupts occur once in a while, or whether some extra code is included to check for packet reception, for example. What might happen (in the worst case, and only very rarely) is that a pin gets turned on or off a few microseconds late. No big deal, and most importantly: no systematic errors!

It’s fairly easy to do some other work in between, as long as the main code gets called as often as possible:

Screen Shot 2010 10 01 at 01.51.18

I’ve applied this approach to an updated rgbRemote.pde sketch in the RF12 library, and sure enough, the dimming is very smooth for intensity levels 25..255. Below 25, there is some flickering – perhaps from the millis() timer? Furthermore, I’m back to being able to dim with full 24-bit accuracy, i.e. 8 bits on each of the RGB color controls. Which could be fairly important when finely adjusting the white balance!

So there you have it: simpler AND better! – all for the same price as before :)

Poor Henry

In Hardware on Oct 2, 2010 at 00:01

The new AA Power Board is working very nicely, but it turns out that the ferrite-core inductor is a little fragile.

This is the 10 micro-Henry inductor core, as it should be:

Inductor

… and this is what happened to one of the shipments “all the way” to the UK:

Sje 3911

(photo courtesy Steve Evans – great close-up!)

Whoops, not good!

This happened to two of the five boards shipped as part of a “5-pack”, where I placed all the boards together in a single plastic bag, along with the metal AA clips. The fact that the inductor is placed near the outside edge also probably doesn’t help…

I’ll package the boards differently from now on. But if you got these boards, please check them and let me know if they got damaged (they may still work, depends a bit on the breakage) – I’ll send out replacements for any bad boards out there, of course.

Live and learn!

Save data to a logfile with JeeMon

In Software on Oct 1, 2010 at 00:01

I’ve added a little demo application called “SaveToFile” to JeeMon which saves data from an attached JeeNode or JeeLink to file, complete with timestamps.

When started, you’ll need to specify which device you want to log (unless there is only one):

Screen Shot 2010 09 30 at 21.01.18

Click on one of the lines, and you’ll get this dialog on Mac OS X (Windows and Linux look a little different):

Screen Shot 2010 09 30 at 21.01.31

Once you click “Save”, the main window changes to show the last received line:

Screen Shot 2010 09 30 at 21.02.07

Here’s the contents of the log file at this point:

Screen Shot 2010 09 30 at 21.02.55

You can just leave it running to collect more data.

The following code implements all this and shows a bit of Tcl and Tk scripting in action:

Screen Shot 2010 09 30 at 21.22.40

This code is now included in the JeeMon on-line demos, so all you need to do is get JeeMon, launch it, and then click on “Run web-based demo”:

Screen Shot 2010 09 30 at 21.04.34

(make sure you don’t have a file called “application.tcl” next to JeeMon)

A window will open, just select the “SaveToFile” link, and it’ll be downloaded to the “JeeMon-demos” folder and then launched.

To run this code from the downloaded copy, launch JeeMon as:

    ./JeeMon JeeMon-demos/SaveToFile.zip

To view the code, unpack that ZIP file and you’ll get what is shown above. You can adapt it to your needs, of course. It’s all open source software!