Experiment Aim
The aim here is to Setup two wireless modules and use the RF12_Demo application provided with the JeeLabs library to drive the modules. Special attention will be paid to the robustness of the signal at range.
A secondary aim is to gain an understanding into how the library is driving the modules and begin to think about how I will implement them.
Predicted Outcome
The specifications on the module say that they can reach a maximum distance of 300m. It must be assumed this will be in ideal conditions with no obstacles or interference and hence direct line of sight. This will also assume correct antenna use. A prediction of around 20-30m would be impressive considering testing is being carried out in the Undergraduate Engineering labs which are densely filled with electronic equipment.
Setup
After reading through the documentation provided with the library the following setup was chosen:
Circuit
The following diagram illustrates the circuit to be used and how it will be connected on the breadboard:
Test circuit Setup for the Alpha transceiver module. (RF12) |
This was worked out by looking at the header files of the library:
// ATmega328, etc. #define RFM_IRQ 2 #define SS_PORT PORTB #define SPI_SS 5 #define SPI_MOSI 11 #define SPI_MISO 12 #define SPI_SCK 13
These were referenced with the pin out diagram of the transceiver module:
Code – “RF12demo” (Relevant excerpts)
A look into what the demo code is doing to better understand what is going on. The microcontroller (MCU) was flashed with the demo program. A serial console was then opened on the computer it was connected to and a serial connection established.
Setup code:
This is the code which will be run before entering the main loop. I have used comments to better explain what it does.
void setup() { //Initialize a serial connection with the //computer at 27600 baud Serial.begin(57600); //A simple print via serial connection Serial.print("\n
Before continuing a look at the commands this demo program allows. This is the code that the “showHelp” function prints to the serial connection, useful commands have been commented:
char helpText1[] PROGMEM = "\n" "Available commands:" "\n" // This will allow setting of ID in EEPROM ----------------- " i - set node ID (standard node ids are 1..26)" " (or enter an uppercase 'A'..'Z' to set id)" // ------------------------------------------------------ " b - set MHz band (4 = 433, 8 = 868, 9 = 915)" " g - set network group (RFM12 only allows 212, 0 = any)" " c - set collect mode (advanced, normally 0)" // ------Our main method of testing will be using this----- " t - broadcast max-size test packet, with ack" " ..., a - send data packet to node , with ack" // ------------------------------------------------------ " ..., s - send data packet to node , no ack" " l - turn activity LED on PB1 on or off" " q - set quiet mode (1 = don't report bad packets)" ;
Main Loop
Now the initialization of the device is complete it will fall into its main loop where it will wait for instructions via serial or received packets via the wireless module. Some relevant code excerpts have been explained below: The first condition we have will check whether there is any information on the serial buffer. If there is it will read the data into the function handleInput().
if (Serial.available()) handleInput(Serial.read());
Inside “handleInput” is a simple set of switch case statements. I have included below the switch case statements for the highlighted commands above:
If ‘i’ is send to the board via serial the following code is executed:
case 'i': // set node id config.nodeId = (config.nodeId & 0xE0) + (value & 0x1F); saveConfig(); break;
So simply put when ‘i’ is selected the variable “nodeId” in class config is filled. The config is then saved. If ‘t’ is selected the following is run:
case 't': // broadcast a maximum size test packet, request an ack cmd = 'a'; sendLen = RF12_MAXDATA; dest = 0; for (byte i = 0; i < RF12_MAXDATA; ++i) testbuf[i] = i; break;
The task here is to broadcast a test packet of the maximum size available and request an acknowledgement. If this is broken down:
- Firstly broadcast means we want to send it to all nodes. This is done by setting its destination address to 0. This can be seen on line 4 of the code above.
- Maximum size of a packet is defined in the header file by RF12_MAXDATA. We will set “sendLen” to this value. To create some data to send we load the array with numbers using a for loop from 0 to RF12_MAXDATA.
- Lastly an ack must be requested. This is done by setting the “cmd” variable to ‘a’.
It will soon become clear how setting these variable will, after breaking from this switch case, influence the behaviour of the radio module. Here we see the ‘a’ and the ‘s’ keys run the same piece of code. The only difference is that the selected choice is moved into the global variable “cmd”.
case 'a': // send packet to node ID N, request an ack case 's': // send packet to node ID N, no ack cmd = c; sendLen = top; dest = value; memcpy(testbuf, stack, top); break;
So the above commands, ‘t’, ‘a’ and ‘s’ set up some variables but do not actually transmit anything. The transmission part is done outside of the switch case. This was done, most likely to reduce the repetition of code within the program. Below is the code which actually performs the transmission using calls to library provided functions: Before taking a look at this code its makes for easier visual conception to see take a look at the structure of a packet:
if (cmd && rf12_canSend()) { Serial.print(" -> "); Serial.print((int) sendLen); Serial.println(" b"); byte header = cmd == 'a' ? RF12_HDR_ACK : 0; if (dest) header |= RF12_HDR_DST | dest; rf12_sendStart(header, testbuf, sendLen); cmd = 0; }
So to begin we have if (cmd && rf12_canSend()). Here is a condition which stops a send going ahead without a command first being set AND the module returning true to “rf12_canSend” stating its readiness. The module cannot transmit and receive at the same time.
At this point it became important to understand the structure of the packet to be sent. The diagram below shows the packet layout:
Command to build packet:
void rf12_sendStart(byte header, const void* data, byte length);
- Header: Destination, if ack is required or if it is an ack
- Length: Length of data in bytes (up to 66 bytes)
- Data: A pointer to the data to be sent
Above we saw the data to be transmitted being placed into a variable names “testbuf” and the length of “testbuf” placed into “sendLen”. Now a look into how the application is building the correct packets for transmission:
After printing some characters to the serial port the header of the packet to be sent is built factoring in whether to request an acknowledgement or not. The line
“byte header = cmd == ‘a’ ? RF12_HDR_ACK : 0 ;”
is a simple “if” statement. It could also be written:
if( cmd == 'a') //If cmd is equal to 'a' header = RF12_HDR_ACK; //Header is set equal to the pre-defined- else //-value RF12_HDR_ACK header = 0; //If not header is set to Zero
Next we bring together all the variables we have just set and pass them to “rf12_sendstart” for transmission:
rf12_sendStart(header, testbuf, sendLen);
Experiment and Results
The experiment was simple. Set-up one of the Boards described above on a desk attached to a bench power supply. Power the other from a laptop and walk around whilst hitting the ‘t’ command. This will transmit a packet and then display acknowledgements, if any, received.
This was carried out in the undergraduate laboratories at the University of Surrey. These labs are packed densely with electronic instruments and devices.
A diagram of the set-up:
The results were very impressive. The link was solid for over 25 meters in nearly all directions. This was through walls and even worked into the building opposite. All in all the results indicate there should be little issue with range and transmission ability.
Table of results:
Direction 1 | Direction 2 | |||
Distance (m) | packets Lost / 10 | Line of Sight | Packets Lost / 10 | Line of Sight |
0 | 0 | yes | 0 | yes |
2 | 0 | yes | 0 | yes |
4 | 0 | yes | 0 | yes |
6 | 1 | yes | 0 | yes |
8 | 0 | yes | 0 | yes |
10 | 0 | yes | 0 | yes |
12 | 0 | yes | 0 | no |
14 | 0 | yes | 0 | no |
16 | 0 | yes | 0 | no |
18 | 0 | yes | 0 | no |
20 | 0 | yes | 0 | no |
22 | 0 | yes | 0 | no |
24 | 0 | no | 0 | no |
26 | 0 | no | 6 | no |
28 | 0 | no | 5 | no |
30 | 0 | no | 10 | no |
32 | 8 | no | 8 | no |
34 | 10 | no | 10 | no |
36 | 10 | no | 10 | no |
38 | 10 | no | 10 | no |
40 | 10 | no | 10 | no |
?A graph of the values:
A screen shot of the test taking place (click to zoom):
Credits once again to http://jeelabs.org/. An immensely helpful and well written library.
Hi,
I’m about to prototype observatory dome shutter controls for Auckland Astronomical Society and Stardome Observatory Auckland New Zealand.
We’re expecting to use Alpha-TRX433S RF Transceiver modules to link data to/from the rotating dome.
It would be very helpful to me to be able to see the diagrams in this web page but I am unable to access any ..
Are you able to help me with this?
thanx
Tony Burns
Auckland
NZ
Sorry for the lack of reply Tony, I do hope you got this working!
Images have been restored on the off chance its on the back burner.
Cheers,
Louis
hi,
First two images are broken, please can you reupload them, it’s very hard to debug this library. Also can you write a simple example how to send one data packet to from one node to another just to test devices. br