There is now a new extension to the RFM69 library. It’s called RFM69_ATC aka Automatic Transmission Control. Many thanks to Tom Studwell who implemented this and shared it in the forum. The basic idea behind this extension is to allow your nodes to dial down transmission power based on the received signal strength indicator (RSSI). For instance a sleepy battery node like a MotionMote sits still inside the home and usually has a very strong received signal, somewhere in the range of -30 to -40dBm when transmitting at full power. You could manually tune that down using radio.setPowerLevel(..) in code but its tedious and is a static change, if you move the node or conditions change it will not be smart to adjust the power level to the new environment. However with RFM69_ATC this is done automatically for you, you just need to indicate a target RSSI. On each packet sent and ACK received (using sendWithRetry(…) is required), the node analyzes the actual RSSI and continuously adjusts its own transmission power level of the RFM69 transceiver to attempt to match the target RSSI (+ or -). This way that end node is only “loud” enough to be heard by the gateway, not much louder. Close by nodes can “whisper” while nodes farther away or with more obstacles will “speak up” as necessary but avoid that default fixed maximum “screaming” level. This is “polite” in terms of “RF pollution” and efficient in terms of power consumption. Even non-battery nodes where power is no problem should implement this for the sake of the “polite” factor.
I have updated the Node and Gateway examples to have ATC enabled, and also the MotionMote example is now ATC enabled, in this case with a target RSSI of -90dBm. The noise floor is somewhere around -100dBm with the default RFM69 lib settings, so for static nodes that won’t experience a lot of movement or temperature drifts, a -90dBm target is pretty safe. That will keep the transmitter power to a minimum and save power. We know that the greatest toll on a battery powered node are the spikes of current used when the transmitter is active (up to 130mA for RFM69HW). Reducing the transmit power level to the minimum required will exponentially reduce that spike and result in longer battery life and a more “quiet” sensor network that won’t reach across your whole neighborhood. This is really awesome!
Here is a sample transmission using the Gateway and Node examples linked above. Note how the node starts transmitting at full power, then dials down power to match a test RSSI target of -68dBm. This is output from the Gateway end:
There are a few required changes to a sketch where you want to use ATC:
- you must #include <RFM69_ATC.h> in addition to #include <RFM69.h>
- you must use RFM69_ATC radio; instead of RFM69 radio;
- for the gateway/receiver end the above two changes are sufficient, for the end node that does the power level adjustment you must also do the following:
- in your setup() function (after all RFM69 initialization is complete) call this function to set your target RSSI: radio.enableAutoPower(targetRSSI);
- targetRSSI is a negative integer, should be from very strong (-30) to very weak (-95). Usually you would want to be closer to the noise floor end (-100) since you want to reduce transmit power to the bare minimum
- this is a one time call that enables the dynamic adjustment of the output power on that node
- you must use radio.sendWithRetry() instead of just radio.send() or a combination of radio.send() and radio.receiveDone() for the radio to be able to receive the important headers from the gateway that tells it how to handle its power, this was done in the MotionMote example linked above
Once these changes are implemented, the node will start to progressively dial down power (assuming it starts transmitting at full power) with each packet sent, until the RSSI meets the target. When the RSSI is below the target power is dialed up again and so on, in an attempt to stay as close to the target as possible.
In the examples that I mentioned there is a pattern that I followed by implementing a define directive (#define ENABLE_ATC) which when left uncommented will enable ATC at compile time, if removed/commented the sketch will run normally without ATC. As always, bug reports, suggestions and contributions are welcome, the forum is the best place for that purpose.
I must mention here that at this time I have only partially implemented his variant with some adjustments to Tom’s implementation (I left the differences commented out in my version). For now I chose to leave my power control resolution as is. He actually went into more detail allowing a finer control of the power control – this is because of the differences between RFM69W and HW which handle output power control differently. If you’d like to try his variant with that extra control check this forum post or his Github repo. Thanks Tom for your great contributions and inspiring this piece of work and also the awesome forum projects you’ve posted!