Computing stuff tied to the physical world

Nodes, Addresses, and Interference

In Software on Jan 14, 2011 at 00:01

The RF12 driver used for the RFM12B module on JeeNodes makes a bunch of assumptions and has a number of fixed design decisions built-in.

Here are a couple of obvious ones:

  • nodes can only talk to each other if they use the same “net group” (1..250)
  • nodes normally each have a unique ID in that netgroup (1..31)
  • packets must be 0..66 bytes long
  • packets need an extra 9 bytes of overhead, including the preamble
  • data is sent at approximately 50,000 baud
  • each byte takes ≈ 160 µs, i.e. a max-size packet can be sent in 12 milliseconds

So in the limiting case you could have up to 7,500 different nodes, as long as you keep in mind that they have to share the same frequency and therefore should never transmit at the same time.

For simple signaling purposes that’s plenty, but it’s obvious that you can’t keep a serious high-speed datastream going this way, let alone multiple data streams, audio, or video.

On the 433 or 868 MHz bands, the situation is often worse than that – sometimes much worse, because simple OOK (which is a simple version of ASK) transmitters tend to completely monopolize those same frequency bands, and more often than not, they don’t even wait for their turn so they also disturb transmissions which are already in progress! Add to that the fact that OOK transmitters often operate at 1000 baud or less, and tend to repeat their packets a number of times, and you can see how that “cheap” sensor you just installed could mess up everything!

So if you’ve got a bunch of wireless weather sensors, alarm sensors, or remotely controlled switches, chances are that your RF12-based transmissions will frequently fail to reach their intended destination.

Which is why “ACKs” are so important. These make it possible to detect when packets get damaged or fail to arrive altogehter. An ACK is just what the name says: an acknowledgement that the receiver got a proper packet. No more no less. And the implementation is equally simple, at least in concept: an ACK is nothing but a little packet, sent the other way, i.e. back from the receiver to the original transmitter.

With ACKs, transmitters have a way to find out whether their packet arrived properly. What they do is send out the packet, and then wait for a valid reply packet. Such an “ACK packet” need not contain any payload data – it just needs to be verifiably correct (using a checksum), and the transmitter must somehow be able to tell that the ACK indeed refers to its original packet.

And this is where the RF12 driver starts to make a number of not-so-obvious (and in some cases even unconventional) design decisions.

I have to point out that wireless communication is a bit different from its wired counterpart. For one, everyone can listen in. Radio waves don’t aim, they reach all nodes (unless the nodes are at the limit of the RF range). So in fact, each transmission is a broadcast. Whether a receiver picks up a transmitted packet is only a matter of whether it decides to let it through.

This is reflected in the design of the RF12 driver. At the time, I was trying to address both cases: broadcasts, aimed at anyone who cares to listen, and directed transmissions which target a specific node. The former is accomplished by sending to pseudo node ID zero, the latter requires passing the “destination” node ID as first argument to rf12_sendStart().

For the ACK, we need to send a packet the other way. The usual way to do this, is to include both source and destination node ID’s in the packet. The receiver then swaps those fields and voilá… a packet ready to go the other way!

But that’s in fact overkill. All we really need is a single bit, saying the packet is an ACK packet. And in the simplest case, we could avoid even that one bit by using the convention that data packets must have one or more bytes of data, whereas ACKs may not contain any data.

This is a bit restrictive though, so instead I chose to re-use a single field for either source or destination ID, plus a bit indicating which of those it is, plus a bit indicating that the packet is an ACK.

With node ID’s in the range 1..31, we can encode the address as 5 bits. Plus the src-vs-dest bit, plus the ACK bit. Makes seven bits.

Why this extreme frugality and trying to save bits? Well, keep in mind that the main use of these nodes is for battery-powered Wireless Sensor Networks (WSN), so reducing power usage is normally one of the most important design goals. It may not seem like much, but one byte less to send in an (empty) ACK packet reduces the packet length by 10%. Since the transmitter is a power hog, that translates to 10% less power needed to send an ACK. Yes, every little bit helps – literally!

That leaves one unused bit in the header, BTW. Whee! :)

I’m not using that spare bit right now, but it will become important in the future to help filter out duplicate packets (a 1-bit sequence “number”).

So here is the format of the “header byte” included in each RF12 packet:

Screen Shot 2011 01 13 at 23.35.02

And for completeness, here is the complete set of bytes sent out:

Screen Shot 2011 01 13 at 23.34.14

So what are the implications of not having both source and destination address in each packet?

One advantage of using a broadcast model, is that you don’t have to know where to send your packet to. This can be pretty convenient for sensor nodes which don’t really care who picks up their readings. In some cases, you don’t even care whether the data arrived, because new readings are periodically being sent anyway. This is the case for the Room Nodes, when they send out temperature / humidity / light-level readings. Lost one? Who cares, another one will come in soon enough.

With the PIR motion detector on Room Nodes, we do want to get immediate reporting, especially if it’s the first time that motion is being detected. So in this case, the Room Node code is set up to send out a packet and request an ACK. If one doesn’t come in very soon, the packet is sent again, and so on. This repeats a few times, so that motion detection packets reach their destination as quickly as possible. Of course, this being wireless, there are no guarantees: someone could be jamming the RF frequency band, for example. But at least we now have a node which tries very hard to quickly overcome an occasional lost packet.

All we need for broadcasts to work with ACKs, is that exactly one node in the same netgroup acts as receiver and sends out an ACK when it gets a packet which asks to get an ACK back. We do not want more than one node doing so, because then ACKs would come from different nodes at the same time and interfere with each other.

So normally, a WSN based on RFM12B’s looks like this:

Screen Shot 2011 01 13 at 23.35.09

The central node is the one sending back ACKs when requested. The other nodes should just ignore everything not intended for them, including broadcasts.

Note that it is possible to use more than one receiving node. The trick is to still use only a single one to produce the ACKs. If you’re using the RF12demo sketch as central receiver, then there is a convenient (but badly-named) “collect” option to disable ACK replies. Just give “1c” as command to the second node, and it’ll stop automatically sending out ACKs (“0c” re-enables normal ACK behavior). In such a “lurking” mode, you can have as many extra nodes listening in on the same netgroup as you like.

To get back to netgroups: these really act as a way to partition the network into different groups of nodes. Nodes only communicate with other nodes in the same netgroup. Nodes in other netgroups are unreachable, and data from those other nodes cannot be received (unless you set up a relay, as described a few days ago). If you want to have say hundreds of nodes all reporting to one central server, then one way to do it with RF12 is to set up a number of separate netgroups, each with one central receiving node (taking care of ACKs for that netgroup), and then collect the data coming from all the “central nodes”, either via USB, Ethernet, or whatever other mechanism you choose. This ought to provide plenty of leeway for home-based WSN’s and home-automation, which is what the RF12 was designed for.

So there you have it. There is a lot more to say about ACKs, payloads, and addressing… some other time.

Another topic worth a separate post, is using (slightly) different frequencies to allow multiple transmissions to take place at the same time. Lots of things still left to explore, yummie!

  1. Thanks for these thoughts. I always enjoy reading them. What exactly are the frequencies ? Saying 900 mhz in the usa is somewhat vague. I have also been thinking about relaying data, but having been thinking more like Ethernet or perhaps insteon more exactly. I was thinking any station could relay, like mesh, but I see that then the radio would need to always be listening. Lots of power needed !

    • No the radio do not need to bee on all the time to do that! Ther are metodes like; X-MAC (1.4% on time), ContikiMAC (0.45% on time). Who do not need synchronisation. If you can achieve synchronisation you can use Dozer (0.16% ontime). My source is the book “Interconnecting smart objects with IP” on page 144. The same book also conclude that due to the design of RF circuit and the low transmission power listing is as power expensive as transmitting!!!

    • The EtherNode demo sketch in the EtherCard lib could be a starting point for this. It collects incoming data and lets you “scrape” it off from the built-in web-server.

  2. I was just wondering, why limit the number of nodes to just 31 ?

  3. As BMJ points out, there are ways to save power even when acting as listener. The idea of TDMA is to agree exactly when to listen. Get that right across all nodes, and the nodes will indeed be able to communicate in any way they like. This requires a stable sense of time across all nodes (fairly well achievable with the JN’s on-board 16 MHz resonators, but not perfect).

    My impression is that keeping a few central nodes always on is a small price to pay to obtain nearly the same level of service at a fraction of the complexity. Keep in mind that the RF12 design was built for use in the home, i.e. an area which can often be covered with a single centrally-placed node, requiring perhaps one or two relays to deal with exceptionally remote (or shielded) spots around the house. At JeeLabs, I expect to be able to cover every spot inside the house and into the garden with at most 2 relays.

    Stay tuned for more on this in tomorrow’s post…

    • I agree fully on that desision! I just wanted to inform the curious of the alternatives. IF I rememberer right the next “generation” of RFM12B (the RFM22B) has some support for the non synchronous algorithms in hardware. Non synchronous algorithms dose not need a central clocking source just local sense of approximately past time sins last “on” period making it easer than TDMA. The “ATmega128RFA1” definitely has such hardware. But both is more expensive than RFM12B and even ZigBee or 6LoWPAN tend to use grid-powered nodes as repeaters/collectors/routers and are more used for there product-intercompatibility then for there efficiency in forwarding other nodes data. The also have concepts as full and source nodes etc. The only battery powered repeater on the market using 868Mhz I know of i NEXA:s

Comments are closed.