Overview
Another coaster application? This time, we're riding roller coasters. My fiancee's family and I had a "coast off": the one who rode the most coasters won. Sure, we could have simply counted how many coasters each person went on... but what would that teach us?
This application writes to the file system, reads the accelerometer in its 3 axis, and communicates with other motes to find the winner.
Components
- Motes: one per person
- Roller coasters
Code
I broke my main code into two pieces: the main thread that constantly reads the accelerometer, and a second thread, handling communication with other motes to determine who won.
Accelerometer
The most important piece of the code is how to read the accelerometer. It is initialized this way:
// Set sleep pin to be awake DigitalPinDriver.create(0x23).write(true); // Choose range of 4G DigitalPinDriver.create(0x20).write(false); DigitalPinDriver.create(0x21).write(true); // Make sure that the pin is set as input: DigitalPinDriver.create(0x64).read(); DigitalPinDriver.create(0x65).read(); DigitalPinDriver.create(0x66).read();
Calibration ensures that whatever bias is found at the accelerometer, it is subtracted every time. To find the calibration values, the mote must start flat.
Since I wanted a lightweight code to handle the accelerometer, I chose to read only raw values. These are compared to a threshold (above 1G to avoid recording steps), and if the mote is detecting a strong acceleration, it starts adding the readings (a premium rewards riders of mighty coasters over those who choose kiddy rides).
For my accelerometer, I chose a range of 4G, as coasters rarely exceed this value (Wikipedia).
One of the constraints I had was to make sure that the cumulative acceleration would be safely recorded, even if the mote rebooted (as to be expected under the constant shaking). To help me, I used the PropertyDriver:
RandomAccessFile fw = PropertyDriver.create("totalAcceleration", 64);
fw.seek(0); // Make sure you always write in the right place
fw.writeLong(totalAcc); // Done!
This would ensure that if a mote rebooted, I could read the file system to recover my score.
After a day riding, I realized that the calibration of the accelerometer should also be recorded: what if a mote reboots while on a coaster? It needs to grab its original calibration values, and not recalculate new ones that would be undoubtedly false.
Communication
The way I used to interact with my motes was to check for the Z axis: if the mote was flipped on its back for more than 10s, this meant that scores had to be exchanged, and a winner found.
The motes send a request packet and expect to receive a response from the other motes. I placed this occasional code in the WinnerDisplay thread. Thanks to the call
receiver.submit().block(); message = receiver.getData();
it is blocked most of the time.
The Application
It was obviously tricky to monitor the application: no computer, only one chance to make it right. However, the motes seem to have resisted pretty well. At the end of the day, we had ridden about the same coasters. The motes returned pretty similar values. The scores found were equivalent to 11min at 1G, which seems consistent with very very long lines and fairly short rides (17s for the tallest one!).
This code can be used to record many interesting things: the time passed on a coaster is a cool one, so is the biggest acceleration, etc.
The code is available here.
#Overview#
Another coaster application? This time, we're riding roller coasters.
My fiancee's family and I had a "coast off": the one who rode the most coasters won.
Sure, we could have simply counted how many coasters each person went on... but what would that teach us?
This application writes to the file system, reads the accelerometer in its 3 axis, and communicates with other motes to find the winner.
#Components#
* Motes: one per person
* Roller coasters
#Code#
I broke my main code into two pieces: the main thread that constantly reads the accelerometer, and a second thread, handling communication with other motes to determine who won.
##Accelerometer##
The most important piece of the code is how to read the accelerometer. It is initialized this way:
<code>
// Set sleep pin to be awake
DigitalPinDriver.create(0x23).write(true);
// Choose range of 4G
DigitalPinDriver.create(0x20).write(false);
DigitalPinDriver.create(0x21).write(true);
// Make sure that the pin is set as input:
DigitalPinDriver.create(0x64).read();
DigitalPinDriver.create(0x65).read();
DigitalPinDriver.create(0x66).read();
</code>
Calibration ensures that whatever bias is found at the accelerometer, it is subtracted every time. To find the calibration values, the mote must start flat.
<P>Since I wanted a lightweight code to handle the accelerometer, I chose to read only raw values. These are compared to a threshold (above 1G to avoid recording steps), and if the mote is detecting a strong acceleration, it starts adding the readings (a premium rewards riders of mighty coasters over those who choose kiddy rides).
<P>For my accelerometer, I chose a range of 4G, as coasters rarely exceed this value (Wikipedia).
<P>One of the constraints I had was to make sure that the cumulative acceleration would be safely recorded, even if the mote rebooted (as to be expected under the constant shaking). To help me, I used the PropertyDriver:
<code>
RandomAccessFile fw = PropertyDriver.create("totalAcceleration", 64);
fw.seek(0); // Make sure you always write in the right place
fw.writeLong(totalAcc); // Done!
</code>
This would ensure that if a mote rebooted, I could read the file system to recover my score.
<P>After a day riding, I realized that the calibration of the accelerometer should also be recorded: what if a mote reboots while on a coaster? It needs to grab its original calibration values, and not recalculate new ones that would be undoubtedly false.
##Communication##
The way I used to interact with my motes was to check for the Z axis: if the mote was flipped on its back for more than 10s, this meant that scores had to be exchanged, and a winner found.
<P>The motes send a request packet and expect to receive a response from the other motes. I placed this occasional code in the WinnerDisplay thread. Thanks to the call
<code>
receiver.submit().block();
message = receiver.getData();
</code>
it is blocked most of the time.
#The Application#
It was obviously tricky to monitor the application: no computer, only one chance to make it right. However, the motes seem to have resisted pretty well. At the end of the day, we had ridden about the same coasters. The motes returned pretty similar values. The scores found were equivalent to 11min at 1G, which seems consistent with very very long lines and fairly short rides (17s for the tallest one!).
<P>This code can be used to record many interesting things: the time passed on a coaster is a cool one, so is the biggest acceleration, etc.
<P>The code is available @[here][[CoasterApp.zip]].
