Difference between revisions of "Tutorial:ZigBee"
(→4.) |
|||
(64 intermediate revisions by 2 users not shown) | |||
Line 5: | Line 5: | ||
* [https://blog.csdn.net/leansmall/article/details/78703633 TinyOS intro (Chinese)] | * [https://blog.csdn.net/leansmall/article/details/78703633 TinyOS intro (Chinese)] | ||
* [https://blog.csdn.net/liuruiqun/article/details/45504035 Programming model of TinyOS (Chinese)] | * [https://blog.csdn.net/liuruiqun/article/details/45504035 Programming model of TinyOS (Chinese)] | ||
* [http:// | * [http://tinyos.stanford.edu/tinyos-wiki/index.php/Main_Page TinyOS main site and official tutorials] | ||
===The simplest example=== | |||
This example shows | |||
1) how the event-driven programming works, | |||
2) how to burn a program to a TelosB node. | |||
for details you can see [http://tinyos.stanford.edu/tinyos-wiki/index.php/The_simplest_TinyOS_program simplest tinyos program] | |||
---- | |||
1. Configuration file, SimpleAppC.nc | |||
<nowiki> | |||
configuration SimpleAppC{ | |||
} | |||
implementation{ | |||
components SimpleC, MainC; | |||
SimpleC.Boot -> MainC.Boot; | |||
}</nowiki> | |||
this file will link two components <code>SimpleC</code> and <code>MainC</code> | |||
2. SimpleC.nc | |||
<nowiki>module SimpleC{ | |||
uses interface Boot; | |||
} | |||
implementation{ | |||
event void Boot.booted() { | |||
} | |||
}</nowiki> | |||
When system starts, it will call interface booted in <code>MainC</code>, but this interface is not implemented. | |||
So <code>SimpleC</code> implements it. | |||
<code>MainC</code> in nesC is just like main function in C. | |||
In this example, it does nothing, so it is just like following code in C: | |||
<nowiki>int main () { | |||
return 0; | |||
}</nowiki> | |||
3. Makefile | |||
<nowiki> | |||
COMPONENT=SimpleAppC | |||
include $(MAKERULES)</nowiki> | |||
with <code>Makefile</code> we can compile the code by typing | |||
<nowiki>make telosb</nowiki> | |||
4. install | |||
<nowiki>make telosb install bsl,/dev/ttyUSB0</nowiki> | |||
===Measurement=== | |||
To measure various information from received packets. | |||
Details is [http://tinyos.stanford.edu/tinyos-wiki/index.php/Mote-mote_radio_communication here] | |||
====Code template==== | |||
ExampleC.nc | |||
<nowiki> | |||
// extract info upon receiving a packet. | |||
event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len) { | |||
if (len != sizeof(msg_t)) { | |||
return bufPtr; | |||
} else { | |||
msg_t* msg = (msg_t*)payload; | |||
// msg is the info, we can do something upon it. | |||
// write your code with msg here, for example, we show it by led | |||
call Leds.set(msg->counter); | |||
return bufPtr; | |||
} | |||
}</nowiki> | |||
====Payload==== | |||
ExampleC.nc | |||
<nowiki> | |||
// following code is the implementation | |||
// to send a packet, we should create a packet at first. | |||
message_t packet; // packet is a container of payload. | |||
bool locked; // when it is sending a packet, sender is locked. | |||
uint16_t counter = 0; // the payload in this example | |||
event void Timer0.fired() { | |||
msg_t *msg; | |||
// important!!! | |||
// variable declaration must be present before operation | |||
// in this example, msg is present before `if (locked)' | |||
if (locked) { | |||
return; | |||
} | |||
msg = (msg_t*) call Packet.getPayload(&packet, sizeof(msg_t)); | |||
++counter; | |||
// suppose msg contains payload `counter` | |||
msg->counter = counter; | |||
// if there is other payload in msg, do assignment. | |||
// to send this packet | |||
if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(msg_t)) == SUCCESS) { | |||
locked = TRUE; | |||
// the packet is being sent | |||
} | |||
}</nowiki> | |||
====Header==== | |||
ExampleC.h | |||
<nowiki> | |||
#ifndef EXAMPLE_H | |||
#define EXAMPLE_H | |||
typedef nx_struct example_msg { | |||
nx_uint16_t counter; | |||
} msg_t; | |||
enum { | |||
AM_MSG = 6, // mesage group | |||
}; | |||
#endif</nowiki> | |||
ExampleAppC.nc | |||
<nowiki>#include "Example.h" | |||
configuration ExampleAppC {} | |||
implementation { | |||
components MainC, ExampleC as App, LedsC; | |||
components new AMSenderC(AM_MSG); | |||
components new AMReceiverC(AM_MSG); | |||
components new TimerMilliC() as Timer0; | |||
components ActiveMessageC; | |||
App.Boot -> MainC.Boot; | |||
App.Receive -> AMReceiverC; | |||
App.AMSend -> AMSenderC; | |||
App.AMControl -> ActiveMessageC; | |||
App.Leds -> LedsC; | |||
App.Timer0 -> Timer0; | |||
App.Packet -> AMSenderC; | |||
}</nowiki> | |||
ExampleC.nc | |||
<nowiki>#include "Timer.h" | |||
#include "Example.h" | |||
module ExampleC @safe() { | |||
uses { | |||
interface Leds; | |||
interface Boot; | |||
interface Receive; | |||
interface AMSend; | |||
interface Timer<TMilli> as Timer0; | |||
interface SplitControl as AMControl; | |||
interface Packet; | |||
} | |||
} | |||
implementation { | |||
event void Boot.booted() { | |||
call AMControl.start(); | |||
} | |||
event void AMControl.startDone(error_t err) { | |||
if (err == SUCCESS) { | |||
call Timer0.startPeriodic(250); | |||
} else { | |||
call AMControl.start(); | |||
} | |||
} | |||
// ... see in other sections: code example, payload | |||
}</nowiki> | |||
====Footer==== | |||
ExampleC.nc | |||
<nowiki> | |||
// to unlock | |||
event void AMSend.sendDone(message_t* bufPtr, error_t error) { | |||
if (&packet == bufPtr) { | |||
locked = FALSE; | |||
} | |||
} | |||
event void AMControl.stopDone(error_t err) { | |||
// do nothing | |||
}</nowiki> | |||
====Makefile==== | |||
<nowiki>COMPONENT=ExampleAppC | |||
include $(MAKERULES)</nowiki> | |||
====RSSI==== | |||
====Byte-level RSSI==== | |||
===Routing=== | |||
====Code template==== | |||
we can change '''ADDRESS''' to implement different protocols. | |||
<nowiki>if (call AMSend.send(ADDRESS, &packet, sizeof(msg_t)) == SUCCESS) { | |||
locked = TRUE; | |||
// the packet is being sent | |||
}</nowiki> | |||
====Broadcast==== | |||
'''AM_BROADCAST_ADDR''' is a MACRO. Using this ADDRESS, a mote will boradcast the packet. | |||
<nowiki>AM_BROADCAST_ADDR</nowiki> | |||
====Unicast==== | |||
When load the binary to the mote, we can set the '''TOS_NODE_ID''', so we can set the '''ADDRESS''' to | |||
a specific '''TOS_NODE_ID''', such as 1 to unicast a packet. | |||
For exmaple, if we want to set '''TOS_NODE_ID = 1''' in /dev/ttyUSB2 | |||
<nowiki>make telosb install,1 bsl,/dev/ttyUSB2</nowiki> | |||
===Testbed usage=== | |||
====Data collection using USB cables==== | |||
1. Use Printf | |||
Details is [http://tinyos.stanford.edu/tinyos-wiki/index.php/The_TinyOS_printf_Library here]. | |||
ExampleC.nc | |||
<nowiki>#include "printf.h" | |||
// in function, fell free to use printf()</nowiki> | |||
ExampleAppC.nc | |||
<nowiki>#define NEW_PRINTF_SEMANTICS | |||
#include "printf.h" | |||
... | |||
implementation { | |||
components PrintfC; | |||
components SerialStartC; | |||
... | |||
}</nowiki> | |||
Makefile | |||
add following code | |||
<nowiki>CFLAGS += -I$(TOSDIR)/lib/printf</nowiki> | |||
Run | |||
in our exvironments, type the following command: | |||
<nowiki>java net.tinyos.tools.PrintfClient -comm serial@/dev/ttyUSB1:telosb</nowiki> | |||
====Batch burn of multiple network nodes==== | |||
1. burn multiple nodes | |||
<nowiki>usage: burn.py [-s] ids | |||
burn.py -s 1 , node with TOS_NODE_ID = 1 will be burned | |||
burn.py -s 5 3 2 , TOS_NODE_ID = 5, 3, 2 will be burned | |||
burn.py 23 55 , TOS_NODE_ID from 23 to 55 will be burned</nowiki> | |||
2. burn all nodes | |||
<nowiki>all-burn</nowiki> | |||
====Remote configuration via web==== | |||
You can visit our server via ssh, then control the motes. | |||
====Useful parse scripts==== | |||
For details you can see /opt/myscripts/tinyos-helpers | |||
1. collect_data.py | |||
<nowiki>similar to burn.py, collect_data.py will redirect the printf message from terminal to files.</nowiki> | |||
2. get-bitmap.py | |||
<nowiki>say collect_data.py provides us the raw data, get-bitmap.py will parse it to bitmap.</nowiki> | |||
3. sjava.py | |||
<nowiki>when we use java, the commad is too long, | |||
just like java net. ... -comm serial@/dev/ttyUSB0:115200, | |||
but with sjava.py, we can just type `sjava.py 1 Class' | |||
here, 1 is the node's id, and Class is a specific java class.</nowiki> | |||
4. output_data.py | |||
<nowiki>similar to sjava.py, when we just want to see exactly one node's printf message in terminal, | |||
say the node's id is 1, then type `output_data.py 1'</nowiki> | |||
====Demo Experiments==== | |||
This demo shows a simple way to calculate ETX and correlation. | |||
=====1. Initiation===== | |||
Suppose you are in home directory(<code>~</code>) | |||
<nowiki>$ tinyos-environment-init</nowiki> | |||
You can see apps in <code>~/tinyos/612_mobinets</code>. | |||
=====2.===== | |||
Make and burn app <code>sendonly</code> and <code>receiveonly</code>. | |||
<nowiki>$ cd sendonly | |||
$ make telosb | |||
$ cd ../receiveonly | |||
$ make telosb</nowiki> | |||
The transmission power is 3 in this experiment. If you want to change it, change the argument in <code>sendonly/Makefile</code>. | |||
=====3.===== | |||
If we want node(id 3) to send packets and other nodes to receive. | |||
<nowiki>$ all-burn-excluding 3 | |||
$ all-collect-excluding 3</nowiki> | |||
<code>all-burn-excluding 3</code> will burn all nodes excluding node(id 3) with app <code>receiveonly</code>. | |||
<code>all-collect-excluding 3</code> will collect data generated by function printf and save it into files. | |||
Then, open a new terminal | |||
<nowiki>$ cd ~/tinyos/612_mobinets/sendonly | |||
$ burn.py -s 3</nowiki> | |||
=====4.===== | |||
Totally, there are 10,000 packets to be sent (if you want to change it, please change it in <code>Makefile</code>), whose interval is 8ms. | |||
After transmission is done, go to the first terminal press key Ctrl+C to exit, then go to the second terminal | |||
<nowiki>$ cd ~/data/tinyos | |||
$ wc -l *.txt</nowiki> | |||
You can see how many packets every node received. | |||
Suppose we find node 23, 32, 40, 55, 60 are what we want. | |||
<nowiki>$ mkdir raw | |||
$ cp 23.txt 32.txt 40.txt 55.txt 60.txt raw</nowiki> | |||
=====5. Processing data===== | |||
To get bitmap (by default, we send 10000 packets) | |||
<nowiki>$ get-bitmap.py</nowiki> | |||
If we send 100000 packets | |||
<nowiki>$ get-bitmap.py 100000</nowiki> | |||
To calculate a-ETX (by default, we send 10000 packets) | |||
<nowiki>$ cal-aetx.py</nowiki> | |||
If we send 100000 packets | |||
<nowiki>$ cal-aetx.py 100000</nowiki> | |||
To calculate b-ETX (by default, we send 10000 packets, number of windows is 5 and size is 4, w = 5, d = 4, definition of w and d, please refer to paper) | |||
<nowiki>$ cal-betx.py</nowiki> | |||
Please see the details of <code>cal-betx.py</code> in <code>/opt/myscripts/tinyos-helpers/cal-betx.py</code> | |||
If we send 100000 packets | |||
<nowiki>$ cal-betx.py 5 4 100000</nowiki> | |||
To calculate correlation (by default, we send 10000 packets) | |||
<nowiki>$ cal-correl.py</nowiki> | |||
If we send 100000 packets | |||
<nowiki>$ cal-correl.py 100000</nowiki> | |||
For more details, you can see the scripts in <code>/opt/myscripts/tinyos-helpers</code> | |||
And the experimental data is archived in <code>/data/archived/tinyos/demos/correlation</code> | |||
====Q&A==== | |||
1. Q: error occurs when compile apps that contain java program such as <code>RadioCountToLeds</code> | |||
$ source /opt/myscripts/tinyos-helpers/tinyos-set-classpath | |||
2. Q: |
Latest revision as of 23:24, 20 February 2020
This page shows the tutorial for experiments with ZigBee communications and the testbed.
Useful links:
- TinyOS intro (Chinese)
- Programming model of TinyOS (Chinese)
- TinyOS main site and official tutorials
The simplest example
This example shows
1) how the event-driven programming works,
2) how to burn a program to a TelosB node.
for details you can see simplest tinyos program
1. Configuration file, SimpleAppC.nc
configuration SimpleAppC{ } implementation{ components SimpleC, MainC; SimpleC.Boot -> MainC.Boot; }
this file will link two components SimpleC
and MainC
2. SimpleC.nc
module SimpleC{ uses interface Boot; } implementation{ event void Boot.booted() { } }
When system starts, it will call interface booted in MainC
, but this interface is not implemented.
So SimpleC
implements it.
MainC
in nesC is just like main function in C.
In this example, it does nothing, so it is just like following code in C:
int main () { return 0; }
3. Makefile
COMPONENT=SimpleAppC include $(MAKERULES)
with Makefile
we can compile the code by typing
make telosb
4. install
make telosb install bsl,/dev/ttyUSB0
Measurement
To measure various information from received packets.
Details is here
Code template
ExampleC.nc
// extract info upon receiving a packet. event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len) { if (len != sizeof(msg_t)) { return bufPtr; } else { msg_t* msg = (msg_t*)payload; // msg is the info, we can do something upon it. // write your code with msg here, for example, we show it by led call Leds.set(msg->counter); return bufPtr; } }
Payload
ExampleC.nc
// following code is the implementation // to send a packet, we should create a packet at first. message_t packet; // packet is a container of payload. bool locked; // when it is sending a packet, sender is locked. uint16_t counter = 0; // the payload in this example event void Timer0.fired() { msg_t *msg; // important!!! // variable declaration must be present before operation // in this example, msg is present before `if (locked)' if (locked) { return; } msg = (msg_t*) call Packet.getPayload(&packet, sizeof(msg_t)); ++counter; // suppose msg contains payload `counter` msg->counter = counter; // if there is other payload in msg, do assignment. // to send this packet if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(msg_t)) == SUCCESS) { locked = TRUE; // the packet is being sent } }
Header
ExampleC.h
#ifndef EXAMPLE_H #define EXAMPLE_H typedef nx_struct example_msg { nx_uint16_t counter; } msg_t; enum { AM_MSG = 6, // mesage group }; #endif
ExampleAppC.nc
#include "Example.h" configuration ExampleAppC {} implementation { components MainC, ExampleC as App, LedsC; components new AMSenderC(AM_MSG); components new AMReceiverC(AM_MSG); components new TimerMilliC() as Timer0; components ActiveMessageC; App.Boot -> MainC.Boot; App.Receive -> AMReceiverC; App.AMSend -> AMSenderC; App.AMControl -> ActiveMessageC; App.Leds -> LedsC; App.Timer0 -> Timer0; App.Packet -> AMSenderC; }
ExampleC.nc
#include "Timer.h" #include "Example.h" module ExampleC @safe() { uses { interface Leds; interface Boot; interface Receive; interface AMSend; interface Timer<TMilli> as Timer0; interface SplitControl as AMControl; interface Packet; } } implementation { event void Boot.booted() { call AMControl.start(); } event void AMControl.startDone(error_t err) { if (err == SUCCESS) { call Timer0.startPeriodic(250); } else { call AMControl.start(); } } // ... see in other sections: code example, payload }
ExampleC.nc
// to unlock event void AMSend.sendDone(message_t* bufPtr, error_t error) { if (&packet == bufPtr) { locked = FALSE; } } event void AMControl.stopDone(error_t err) { // do nothing }
Makefile
COMPONENT=ExampleAppC include $(MAKERULES)
RSSI
Byte-level RSSI
Routing
Code template
we can change ADDRESS to implement different protocols.
if (call AMSend.send(ADDRESS, &packet, sizeof(msg_t)) == SUCCESS) { locked = TRUE; // the packet is being sent }
Broadcast
AM_BROADCAST_ADDR is a MACRO. Using this ADDRESS, a mote will boradcast the packet.
AM_BROADCAST_ADDR
Unicast
When load the binary to the mote, we can set the TOS_NODE_ID, so we can set the ADDRESS to a specific TOS_NODE_ID, such as 1 to unicast a packet. For exmaple, if we want to set TOS_NODE_ID = 1 in /dev/ttyUSB2
make telosb install,1 bsl,/dev/ttyUSB2
Testbed usage
Data collection using USB cables
1. Use Printf
Details is here.
ExampleC.nc
#include "printf.h" // in function, fell free to use printf()
ExampleAppC.nc
#define NEW_PRINTF_SEMANTICS #include "printf.h" ... implementation { components PrintfC; components SerialStartC; ... }
Makefile
add following code
CFLAGS += -I$(TOSDIR)/lib/printf
Run
in our exvironments, type the following command:
java net.tinyos.tools.PrintfClient -comm serial@/dev/ttyUSB1:telosb
Batch burn of multiple network nodes
1. burn multiple nodes
usage: burn.py [-s] ids burn.py -s 1 , node with TOS_NODE_ID = 1 will be burned burn.py -s 5 3 2 , TOS_NODE_ID = 5, 3, 2 will be burned burn.py 23 55 , TOS_NODE_ID from 23 to 55 will be burned
2. burn all nodes
all-burn
Remote configuration via web
You can visit our server via ssh, then control the motes.
Useful parse scripts
For details you can see /opt/myscripts/tinyos-helpers
1. collect_data.py
similar to burn.py, collect_data.py will redirect the printf message from terminal to files.
2. get-bitmap.py
say collect_data.py provides us the raw data, get-bitmap.py will parse it to bitmap.
3. sjava.py
when we use java, the commad is too long, just like java net. ... -comm serial@/dev/ttyUSB0:115200, but with sjava.py, we can just type `sjava.py 1 Class' here, 1 is the node's id, and Class is a specific java class.
4. output_data.py
similar to sjava.py, when we just want to see exactly one node's printf message in terminal, say the node's id is 1, then type `output_data.py 1'
Demo Experiments
This demo shows a simple way to calculate ETX and correlation.
1. Initiation
Suppose you are in home directory(~
)
$ tinyos-environment-init
You can see apps in ~/tinyos/612_mobinets
.
2.
Make and burn app sendonly
and receiveonly
.
$ cd sendonly $ make telosb $ cd ../receiveonly $ make telosb
The transmission power is 3 in this experiment. If you want to change it, change the argument in sendonly/Makefile
.
3.
If we want node(id 3) to send packets and other nodes to receive.
$ all-burn-excluding 3 $ all-collect-excluding 3
all-burn-excluding 3
will burn all nodes excluding node(id 3) with app receiveonly
.
all-collect-excluding 3
will collect data generated by function printf and save it into files.
Then, open a new terminal
$ cd ~/tinyos/612_mobinets/sendonly $ burn.py -s 3
4.
Totally, there are 10,000 packets to be sent (if you want to change it, please change it in Makefile
), whose interval is 8ms.
After transmission is done, go to the first terminal press key Ctrl+C to exit, then go to the second terminal
$ cd ~/data/tinyos $ wc -l *.txt
You can see how many packets every node received.
Suppose we find node 23, 32, 40, 55, 60 are what we want.
$ mkdir raw $ cp 23.txt 32.txt 40.txt 55.txt 60.txt raw
5. Processing data
To get bitmap (by default, we send 10000 packets)
$ get-bitmap.py
If we send 100000 packets
$ get-bitmap.py 100000
To calculate a-ETX (by default, we send 10000 packets)
$ cal-aetx.py
If we send 100000 packets
$ cal-aetx.py 100000
To calculate b-ETX (by default, we send 10000 packets, number of windows is 5 and size is 4, w = 5, d = 4, definition of w and d, please refer to paper)
$ cal-betx.py
Please see the details of cal-betx.py
in /opt/myscripts/tinyos-helpers/cal-betx.py
If we send 100000 packets
$ cal-betx.py 5 4 100000
To calculate correlation (by default, we send 10000 packets)
$ cal-correl.py
If we send 100000 packets
$ cal-correl.py 100000
For more details, you can see the scripts in /opt/myscripts/tinyos-helpers
And the experimental data is archived in /data/archived/tinyos/demos/correlation
Q&A
1. Q: error occurs when compile apps that contain java program such as RadioCountToLeds
$ source /opt/myscripts/tinyos-helpers/tinyos-set-classpath
2. Q: