Skip to content
codemonkeyingPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mesh-433

A self-healing mesh network for cheap 433 MHz ASK radio modules (the ~$2 FS1000A / XY-MK-5V pair), built on Arduino Uno/Nano.

Every board runs the same sketch and speaks the same standard packet. Nodes with PIR motion sensors send alerts to a master, which shows them on a 16x2 LCD and sounds a buzzer. If a node can't reach the master directly, its packets go through other nodes. When a relay drops out, the node finds a new one by itself.

   [node 3] ))) [node 2] ))) [node 1] ))) [MASTER 0]  LCD: "Motion! node 3"
       \                                    /
        ))) [node 5] ))) [node 4] ))) ------      <- used automatically if node 2 dies

Why

433 MHz ASK modules are about as cheap and simple as radios get: no Wi-Fi, no internet, no infrastructure. On their own, though, they're one-way and short-range. mesh-433 turns a handful of them into a sensor network that covers more ground than any one radio can, and keeps working when individual nodes fail.

The packet protocol

Every board uses one standard packet, so any node can relay for any other:

Field Purpose
to / from / dest / origin next hop, this hop's sender, final destination, original sender
type data, ack, relay request, relay advert (the reserved control IDs 999 / 998 in the original sketches)
dataType what the receiver should do with the data, e.g. 1 = show the payload on the LCD
sens1-4 sensor slots, e.g. sens1 = 1 = PIR tripped, so the master sounds the buzzer
payload 32 characters = both lines of a 16x2 LCD
ack flag ask the next hop to acknowledge
hops how many hops the sender is from the master (in relay adverts)
boot, seq boot id (changes every power-up) and sequence number: together they identify a packet
ttl hop limit

Addressing: 0 is the master and every other node has its own ID.

Data frames are 56 bytes. Control frames (ack, relay request, relay advert) send only the 16-byte header, which cuts their time on air from about 0.4 s to 0.16 s at 2000 bps.

How it heals itself

  1. Relay discovery: a node that needs a route broadcasts a relay request. Nodes that can reach the master answer after a random delay (so they don't all transmit at once) with their hop count. The node keeps the neighbour with the fewest hops as its relay.
  2. Better routes spread: when a node hears of a relay with fewer hops, it switches to it and re-advertises, so changes in the network spread outward.
  3. Failover: packets are acknowledged at each hop. If the ack doesn't come back, the node works through a retry sequence: resend, try the other route, ask for a new relay, then send via the new relay. Only if all of that fails does it raise a local alarm.
  4. Collision avoidance: ASK radios can't tell when someone else is transmitting, so timing does the work. Retries wait a random backoff that doubles each try, replies to a relay request are spread over 5 s, and a node drops its own reply if it hears a neighbour answer as well or better.
  5. Loop protection: a node never takes one of its own children as its relay. Packets carry a hop limit, and repeated packets are dropped, so a lost ack can't repeat an alert. Each node keeps a boot counter in EEPROM, so packets sent after a reboot are never mistaken for old ones.
  6. Commands down the mesh: each packet travelling up teaches the nodes on its path how to reach its sender, so the master can send commands back down (arm/disarm from the master's button).

Everything runs on millis() timers rather than delay(), so a node keeps listening while it waits.

Layout

firmware/mesh433/mesh.h       the protocol: plain C++ with no Arduino headers, so it also runs on a PC
firmware/mesh433/mesh433.ino  the board: radio, PIR, LCD, buzzer, arm/disarm button
test/sim.cpp                  desktop test harness: runs mesh.h over simulated lossy links
original/                     earlier versions: 5RX/5TX (sensor -> master) and Node001 (first mesh version)

Build and flash

On an Uno it uses 16 KB of 32 KB flash and 1.4 KB of 2 KB RAM.

Libraries: RadioHead and LiquidCrystal I2C (Arduino Library Manager).

  1. Set #define NODE_ID in mesh433.ino: 0 for the master, 1, 2, 3... for the sensor nodes.
  2. Wire it up (Uno/Nano):
Part Pin
433 MHz receiver data D11
433 MHz transmitter data D12
PIR output D2
Button (to GND) A1 / D15
TX LED, alert LED D5, D6
Buzzer D7
16x2 LCD (I2C, 0x27) A4 SDA, A5 SCL
  1. arduino-cli compile -b arduino:avr:uno firmware/mesh433 && arduino-cli upload -p /dev/ttyUSB0 -b arduino:avr:uno firmware/mesh433

A 17 cm wire antenna on each module makes a big difference to range.

Desktop tests

make -C test test runs the protocol code on a PC against a radio model of RH_ASK at 2000 bps: real time on air per frame, half duplex (a node is deaf while it transmits), and collisions (two frames overlapping at a receiver are both lost), plus optional random loss.

Test Checks
line routes form along a 3-hop chain, a packet arrives once
failover kill the active relay, the node finds the other path and still delivers
lossy grid 3x3 grid, collisions + 15% loss per link, 10 runs x 20 packets: no duplicates, nothing lost silently
storm all 8 nodes trip at the same moment
isolated no route at all: the packet is reported failed, nothing loops
downlink the master sends a command down 2 hops
reboot a power-cycled node's packets aren't mistaken for duplicates
millis wrap routing and delivery across the 49.7-day millis() rollover
queue full sends past the 4-slot queue are refused; every accepted one arrives
late ack an ack that arrives during route discovery still completes the send
fan-out the master arms 8 nodes through the 4-slot queue

Typical results: lossy grid 96% delivered, storm 39/40, failover in about 40 s. The tests also pass under AddressSanitizer and UBSan.

Versions

Started in 2022 and revisited in 2023. The earliest surviving copies are the Arduino Cloud sketches from March 2023 (original/), and the commit history starts there.

  • 5RX / 5TX: PIR sensor nodes reporting to an LCD master, with acks and an alarm when the master doesn't answer.
  • Node001: one sketch for every board. Adds relaying, relay discovery by hop count, and relay failover.
  • firmware/ (current): the same design with binary packets instead of comma-separated text, no blocking delays, repeated packets dropped, collision avoidance, and commands sent down from the master.

Where this applies

The same problems show up anywhere sensors have to report without infrastructure:

  • Perimeter and area sensors: unattended PIR, seismic or acoustic sensors reporting to one operator, like the PPSS-style sensor suites used to watch an area.
  • Comms that degrade gracefully: no node is essential. When one is destroyed, jammed or out of battery, the network routes around it without anyone reconfiguring it.
  • Cheap, disposable nodes: each node is a few dollars of parts, so losing some is acceptable.

Next steps

  • Authentication: an 8-byte message authentication code plus a counter on every packet, so alarms and arm/disarm commands can't be forged or replayed.
  • Health monitoring: heartbeats every few minutes, with "node lost" and "jamming suspected" alerts on the master.
  • Battery nodes: a 3.3 V Pro Mini, with sensor nodes sleeping until the PIR wakes them.
  • Better radios: the Radio interface keeps the protocol separate from the hardware, so it can move to RFM69 or LoRa (SX127x), which can sense a busy channel and reach much further.
  • Field testing: delivery rate against distance, failover time and battery life, on real hardware.

Design notes

  • 433 MHz ASK can't tell when another node is already transmitting, so two nodes sending at once can collide. Random backoff and short control frames keep that rare.
  • Frames are CRC-checked by RadioHead but not yet authenticated (see next steps).
  • Packets are sent as raw little-endian structs. AVR, ARM, ESP and x86 are all little-endian.
  • In Australia, 433.05-434.79 MHz falls under the ACMA LIPD class licence, which caps power at 25 mW EIRP.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages