phyphox Forums
Calliope Mini as external Accelerometer - Printable Version

+- phyphox Forums (https://phyphox.org/forums)
+-- Forum: Discussion (https://phyphox.org/forums/forumdisplay.php?fid=1)
+--- Forum: General (https://phyphox.org/forums/forumdisplay.php?fid=3)
+--- Thread: Calliope Mini as external Accelerometer (/showthread.php?tid=700)



Calliope Mini as external Accelerometer - Jonathan Haug - 03-03-2020

Dear phyphox-Team,

first of all: Thanks for your great work! Phyphox is a wonderful piece of software.

I would like to use a Calliope mini in conjunction with phyphox as an accelerometer.
(background: exploring the periodic movement of a spring by students in secondary education)
Therefor I was able to edit the following configuration of a new bluetooth experiment.

Here are my questions:

  1. Do you have any recommendations for further improvements?
  2. Is it possible to "smooth" the graph, i.e. to set a higher rate of given datapoints?
  3. After filing the buffer, old data points are deleted (as expected) but the time line (x-Axis) does not keep in sync, it keeps staying static. Any ideas?
  4. How would it be possible to get linear acceleration from a Calliope?

Here are some notes from my site:

  1. I gave the bluetooth input the somewhat weird name "mi" to let it find the Calliope MIni as well as the MIcro:bit.
  2. Acceleration data is given in "Micro-g", that's why I added the formula " / 1000 * 9.81 "
  3. I was only able to get results within phyphox after using the beta editor makecode.calliope.cc/beta for starting the bluetooth service on the Calliope. As I'm using phyphox on iPads in the class it would be easier to use the Calliope Mini App, which is currently (to my understanding) not possible. I will discuss this in the Calliope forum later.

Thank you for your help!


Code:
<phyphox xmlns="http://phyphox.org/xml" xmlns:editor="http://phyphox.org/editor/xml" version="1.7" editor:version="1.0" locale="en">
    <title>Acceleration Calliope</title>
    <category>Bluetooth</category>
    <description>Reads the acceleration sensor and plots a graph</description>
    <link label="Documentation of BLE micro:bit">https://lancaster-university.github.io/microbit-docs/resources/bluetooth/bluetooth_profile.html</link>
    <translations>
        <translation locale="de">
            <title>Beschleunigung Calliope</title>
            <string original="Acceleration x">Beschleunigung x</string>
            <string original="Acceleration y">Beschleunigung y</string>
            <string original="Acceleration z">Beschleunigung z</string>
            <string original="Absolute">Betrag</string>
            <string original="Acceleration">Beschleunigung</string>
        </translation>
    </translations>
    <data-containers>
        <container size="1" static="false">Ax_mg</container>
        <container size="1" static="false">Az_mg</container>
        <container size="0" static="false">t</container>
        <container size="1" static="false">Ay_mg</container>
        <container size="1000" static="false">A_abs</container>
        <container size="1000" static="false">Ax</container>
        <container size="1000" static="false">Ay</container>
        <container size="1000" static="false">Az</container>
    </data-containers>
    <input>
        <bluetooth id="Accelerometer" name="mi"  mode="notification" rate="1" subscribeOnStart="false">
            <output char="E95DCA4B-251D-470A-A062-FA1922DFA9A8" conversion="int16LittleEndian" offset="0">Ax_mg</output>
            <output char="E95DCA4B-251D-470A-A062-FA1922DFA9A8" conversion="int16LittleEndian" offset="2">Ay_mg</output>
            <output char="E95DCA4B-251D-470A-A062-FA1922DFA9A8" conversion="int16LittleEndian" offset="4">Az_mg</output>
            <output char="E95DCA4B-251D-470A-A062-FA1922DFA9A8" conversion="string" extra="time">t</output>
        </bluetooth>
    </input>
    <output>
    </output>
    <analysis sleep="0"  onUserInput="false">
        <formula formula="([1]/1000)*9.81">
            <input as="in" clear="false">Ax_mg</input>
            <output as="out" clear="false">Ax</output>
        </formula>
        <formula formula="([1]/1000)*9.81">
            <input as="in" clear="false">Ay_mg</input>
            <output as="out" clear="false">Ay</output>
        </formula>
        <formula formula="([1]/1000)*9.81">
            <input as="in" clear="false">Az_mg</input>
            <output as="out" clear="false">Az</output>
        </formula>
        <formula formula="(sqrt([1]*[1]+[2]*[2]+[3]*[3])/1000)*9.81">
            <input as="in" clear="false">Ax_mg</input>
            <input as="in" clear="false">Ay_mg</input>
            <input as="in" clear="false">Az_mg</input>
            <output as="out" clear="false">A_abs</output>
        </formula>
    </analysis>
    <views>
        <view label="Graph">
            <graph label="Acceleration x" aspectRatio="2.5" style="lines" lineWidth="1" color="ff7e22" partialUpdate="true" history="1" labelX="t" labelY="a" labelZ="" unitX="s" unitY="m/s²" unitZ="" logX="false" logY="false" logZ="false" xPrecision="2" yPrecision="2" zPrecision="2" scaleMinX="auto" scaleMaxX="auto" scaleMinY="auto" scaleMaxY="auto" scaleMinZ="auto" scaleMaxZ="auto" minX="0" maxX="0" minY="0" maxY="0" minZ="0" maxZ="0"  mapWidth="0"      >
                <input axis="x">t</input>
                <input axis="y">Ax</input>
            </graph>
            <graph label="Acceleration y" aspectRatio="2.5" style="lines" lineWidth="1" color="00ff00" partialUpdate="false" history="1" labelX="t" labelY="a" labelZ="" unitX="s" unitY="m/s²" unitZ="" logX="false" logY="false" logZ="false" xPrecision="2" yPrecision="2" zPrecision="2" scaleMinX="auto" scaleMaxX="auto" scaleMinY="auto" scaleMaxY="auto" scaleMinZ="auto" scaleMaxZ="auto" minX="0" maxX="0" minY="0" maxY="0" minZ="0" maxZ="0"  mapWidth="0"      >
                <input axis="x">t</input>
                <input axis="y">Ay</input>
            </graph>
            <graph label="Acceleration z" aspectRatio="2.5" style="lines" lineWidth="1" color="0000ff" partialUpdate="false" history="1" labelX="t" labelY="a" labelZ="" unitX="s" unitY="m/s²" unitZ="" logX="false" logY="false" logZ="false" xPrecision="2" yPrecision="2" zPrecision="2" scaleMinX="auto" scaleMaxX="auto" scaleMinY="auto" scaleMaxY="auto" scaleMinZ="auto" scaleMaxZ="auto" minX="0" maxX="0" minY="0" maxY="0" minZ="0" maxZ="0"  mapWidth="0"      >
                <input axis="x">t</input>
                <input axis="y">Az</input>
            </graph>
        </view>
        <view label="Absolute">
            <graph label="Acceleration" aspectRatio="2.5" style="lines" lineWidth="1" color="ff7e22" partialUpdate="false" history="1" labelX="t" labelY="a" labelZ="" unitX="s" unitY="m/s²" unitZ="" logX="false" logY="false" logZ="false" xPrecision="2" yPrecision="2" zPrecision="2" scaleMinX="auto" scaleMaxX="auto" scaleMinY="auto" scaleMaxY="auto" scaleMinZ="auto" scaleMaxZ="auto" minX="0" maxX="0" minY="0" maxY="0" minZ="0" maxZ="0"  mapWidth="0"      >
                <input axis="x">t</input>
                <input axis="y">A_abs</input>
            </graph>
        </view>
    </views>
    <export>
    </export>
</phyphox>



RE: Calliope Mini as external Accelerometer - Sebastian Staacks - 03-05-2020

Nice work. I am always happy to see when users successfully use our editor as it is not always that easy.

(03-03-2020, 10:23 PM)Jonathan Haug Wrote: Is it possible to "smooth" the graph, i.e. to set a higher rate of given datapoints?

I would say that smoothing is quite the opposite of a higher data rate. Well, this may depend on what data you are getting and what you want to achieve. My first thought about smoothing was getting rid of noise in the recorded data, which could be achieved by using the "gausssmooth" module (make sure that it does not change any absolute values that you might need) or by implementing an actual low pass using two Fourier transforms. But it seems like you have the problem of getting to few data points and therefore only having a rather "rough" approximation of the sine function? If so, you want some interpolation. Not sure if this really would help because when recording sine functions at too low sampling rates, you get a tendency to "miss" the maxima and interpolation cannot easily reconstruct these.

The best thing of course would be if you can increase the data rate of the Calliope, but that is something at the Calliope-end of the problem.

In any case, an interpolation module would be nice in phyphox and I have added it to my todo list.

(03-03-2020, 10:23 PM)Jonathan Haug Wrote: After filing the buffer, old data points are deleted (as expected) but the time line (x-Axis) does not keep in sync, it keeps staying static. Any ideas?

Your setup of the buffers and clearing is a bit unusual. In the XML file you can see the buffer sizes in the "data-containers" block and the clear-attributes for each module in the analysis-block. In the editor you can see these options when clicking on a connecting line (which you have probably noticed as you seem to have changed these settings). What is happening at the moment is the following:
The entire analysis section is run periodically as fast as possible. Every time a new value from the Calliope arrives, it is written to the buffers "Ax_mg", "Ay_mg" and "Az_mg" and the time is written to "t". Then in each analysis run, the value from "Ax_mg" etc. is used by the formula modules you have set up and then appended to the buffers "Ax", "Ay", "Az" and "A_abs". Those have a size of 1000, so after 1000 values, the oldest values are dropped and the data starts shifting to the left. However, your "t" buffer has the size 0, which means that it is infinite. It receives new values and grows ever larger. But as it is plotted against "Ax" etc. you will only see its first 1000 (old) data points as it only has 1000 matching points in the other buffer.

Unfortunately, you can not simply set the size of "t" to 1000 because of another problem. In fact, I think that you might notice that the behavior of the time axis is a bit off anyways. The problem is that the last value from the Calliope stays in the "Ax_mg" buffer for several runs of the analysis modules because you are not clearing anything. The Calliope delivers values at a much smaller rate than the rate of the analysis, so I would expect (again, not tested) that each value from the Calliope is fed multiple times through the formula modules and you will see something like a stair-case plot in your measurements. Even worse, I would expect that it does not really align with your time axis, because the "t" buffer only receives a new value when the Calliope sends one, so there should be fewer values in "t" than in "Ax" (until Ax is filled any you only see the latest values anyways).

This approach of using buffers of size 1 only works if the analysis process is slowed to run at a lower rate than the data input and only if you are ok with losing some data points.

Instead, I would recommend to set all buffers with direct input to a size of 0 (Ax_mg, Ay_mg and Az_mg) and let the formula modules delete the data every time it has been processed (set "clear at the input" for the connection from the Bluetooth input to the formula nodes). For the time buffer, you can either create a similar construction or directly set its size to 1000 to match the processed data.

Let me know if this works or if you need some more help on this.

(03-03-2020, 10:23 PM)Jonathan Haug Wrote: How would it be possible to get linear acceleration from a Calliope?

If you are sure that your Calliope will not rotate during the measurement, simply subtract Earth's acceleration or the first value recorded if you are sure that the experiment starts without any acceleration. If your Calliope might rotate, however, it is much more complicated. Phyphox does not derive the linear acceleration itself but uses the linear acceleration directly provided by Android and iOS as it is optimized for each sensor. You will need to combine the data from the accelerometer and the gyroscope for this. The term you want to search for is "sensor fusion", but it will be tough to implement just in our editor.

Here are some notes from my site:

(03-03-2020, 10:23 PM)Jonathan Haug Wrote: I gave the bluetooth input the somewhat weird name "mi" to let it find the Calliope MIni as well as the MIcro:bit.

Yes, that is a bit of a problem there. An alternative might be looking for a specific service that is advertised by both of them, but I do not know if there is any.

(03-03-2020, 10:23 PM)Jonathan Haug Wrote: I was only able to get results within phyphox after using the beta editor makecode.calliope.cc/beta for starting the bluetooth service on the Calliope. As I'm using phyphox on iPads in the class it would be easier to use the Calliope Mini App, which is currently (to my understanding) not possible. I will discuss this in the Calliope forum later.

Cannot say much about this. We mostly test the Micro:Bit, but we checked if the Calliope worked the same way a while ago. At that time I do not remember this problem, but that does not say much.


RE: Calliope Mini as external Accelerometer - Jonathan Haug - 03-08-2020

Dear Sebastian,

thanks for your helpful reply!


(03-05-2020, 12:04 PM)Sebastian Staacks Wrote: The best thing of course would be if you can increase the data rate of the Calliope, but that is something at the Calliope-end of the problem.


Actually there is a characteristic called "Accelerometer Period", which "determines the frequency with which accelerometer data is reported in milliseconds."
[Micro:bit Docs]

But I was not able to write a proper new value with nRF Connect due to too many questions (hex or uint16 ? with or without "0x"? from right to left or from left to right? byte array or uint8?)


(03-05-2020, 12:04 PM)Sebastian Staacks Wrote: An alternative might be looking for a specific service that is advertised by both of them,

Unfortunately my Calliope mini isn't advertising any service according to nRF Connect.


(03-05-2020, 12:04 PM)Sebastian Staacks Wrote: ... and let the formula modules delete the data every time it has been processed

Great hint, thanks! Didn't noticed/understand this option before.
But when deleting the data after processing of Ax_mg, Ay_mg and Az_mg, there is noting to calculate with for the "Absolute" graph... So now I'm deleting only after processing the "Absolute" formula.
(NB: Since the position of the modules in the editor window is important, it could be a good idea to give an extra hint for the user when using the "clear at the input" option)

Although I still get a kind of a stair-case plot the "smoothness" is now ok for me.

If you have further comments to my code I would love to hear them:

Code:
<phyphox xmlns="http://phyphox.org/xml" xmlns:editor="http://phyphox.org/editor/xml" version="1.7" editor:version="1.0" locale="en">
    <title>Acceleration</title>
    <category>Calliope mini</category>
    <color>42C9C9</color>
    <description>Shows the movement of a Calliope mini

</description>
    <link label="Documentation of BLE micro:bit">https://lancaster-university.github.io/microbit-docs/resources/bluetooth/bluetooth_profile.html</link>
   
    <translations>
        <translation locale="de">
            <title>Beschleunigung</title>
            <description>Zeigt die Bewegung eines Calliope mini

</description>
            <string original="Acceleration x">Beschleunigung in x-Richtung</string>
            <string original="Acceleration y">Beschleunigung in y-Richtung</string>
            <string original="Acceleration z">Beschleunigung in z-Richtung</string>
            <string original="Absolute">Betrag</string>
            <string original="Acceleration">Beschleunigung</string>
        </translation>
    </translations>
    <data-containers>
        <container size="0" static="false">Ax_mg</container>
        <container size="0" static="false">Az_mg</container>
        <container size="5000" static="false">t</container>
        <container size="0" static="false">Ay_mg</container>
        <container size="5000" static="false">A_abs</container>
        <container size="5000" static="false">Ax</container>
        <container size="5000" static="false">Ay</container>
        <container size="5000" static="false">Az</container>
    </data-containers>
    <input>
        <bluetooth editor:uuid="179" editor:posx="46.83332824707031" editor:posy="274.83335876464844" id="Accelerometer" name="mi"  mode="notification" rate="1" subscribeOnStart="false">
            <output char="E95DCA4B-251D-470A-A062-FA1922DFA9A8" conversion="int16LittleEndian" offset="0">Ax_mg</output>
            <output char="E95DCA4B-251D-470A-A062-FA1922DFA9A8" conversion="int16LittleEndian" offset="2">Ay_mg</output>
            <output char="E95DCA4B-251D-470A-A062-FA1922DFA9A8" conversion="int16LittleEndian" offset="4">Az_mg</output>
            <output char="E95DCA4B-251D-470A-A062-FA1922DFA9A8" conversion="string" extra="time">t</output>
        </bluetooth>
    </input>
    <output>
    </output>
    <analysis sleep="0"  onUserInput="false">
        <formula editor:uuid="227" editor:posx="191.5833282470703" editor:posy="63.583343505859375" formula="([1]/1000)*9.81">
            <input as="in" clear="false">Ax_mg</input>
            <output as="out" clear="false">Ax</output>
        </formula>
        <formula editor:uuid="228" editor:posx="256.41668701171875" editor:posy="182.4166717529297" formula="([1]/1000)*9.81">
            <input as="in" clear="false">Ay_mg</input>
            <output as="out" clear="false">Ay</output>
        </formula>
        <formula editor:uuid="229" editor:posx="319.58331298828125" editor:posy="307.58335876464844" formula="([1]/1000)*9.81">
            <input as="in" clear="false">Az_mg</input>
            <output as="out" clear="false">Az</output>
        </formula>
        <formula editor:uuid="230" editor:posx="475.8999938964844" editor:posy="555.8333587646484" formula="(sqrt([1]*[1]+[2]*[2]+[3]*[3])/1000)*9.81">
            <input as="in">Ax_mg</input>
            <input as="in">Ay_mg</input>
            <input as="in">Az_mg</input>
            <output as="out" clear="false">A_abs</output>
        </formula>
    </analysis>
    <views>
        <view label="Graph">
            <graph editor:uuid="237" editor:posx="645.6500244140625" editor:posy="64.48333740234375" label="Acceleration x" aspectRatio="3" style="lines" lineWidth="1" color="ff7e22" partialUpdate="true" history="1" labelX="t" labelY="a" labelZ="" unitX="s" unitY="m/s²" unitZ="" logX="false" logY="false" logZ="false" xPrecision="2" yPrecision="2" zPrecision="2" scaleMinX="auto" scaleMaxX="auto" scaleMinY="auto" scaleMaxY="auto" scaleMinZ="auto" scaleMaxZ="auto" minX="0" maxX="0" minY="0" maxY="0" minZ="0" maxZ="0"  mapWidth="0"       >
                <input axis="x">t</input>
                <input axis="y">Ax</input>
            </graph>
            <graph editor:uuid="238" editor:posx="674.933349609375" editor:posy="221.10000610351562" label="Acceleration y" aspectRatio="3" style="lines" lineWidth="1" color="00ff00" partialUpdate="true" history="1" labelX="t" labelY="a" labelZ="" unitX="s" unitY="m/s²" unitZ="" logX="false" logY="false" logZ="false" xPrecision="2" yPrecision="2" zPrecision="2" scaleMinX="auto" scaleMaxX="auto" scaleMinY="auto" scaleMaxY="auto" scaleMinZ="auto" scaleMaxZ="auto" minX="0" maxX="0" minY="0" maxY="0" minZ="0" maxZ="0"  mapWidth="0"       >
                <input axis="x">t</input>
                <input axis="y">Ay</input>
            </graph>
            <graph editor:uuid="239" editor:posx="702.75" editor:posy="373.5999755859375" label="Acceleration z" aspectRatio="3" style="lines" lineWidth="1" color="0000ff" partialUpdate="true" history="1" labelX="t" labelY="a" labelZ="" unitX="s" unitY="m/s²" unitZ="" logX="false" logY="false" logZ="false" xPrecision="2" yPrecision="2" zPrecision="2" scaleMinX="auto" scaleMaxX="auto" scaleMinY="auto" scaleMaxY="auto" scaleMinZ="auto" scaleMaxZ="auto" minX="0" maxX="0" minY="0" maxY="0" minZ="0" maxZ="0"  mapWidth="0"       >
                <input axis="x">t</input>
                <input axis="y">Az</input>
            </graph>
        </view>
        <view label="Absolute">
            <graph editor:uuid="240" editor:posx="729" editor:posy="523" label="Acceleration" aspectRatio="1" style="lines" lineWidth="2" color="ff7e22" partialUpdate="true" history="1" labelX="t" labelY="a" labelZ="" unitX="s" unitY="m/s²" unitZ="" logX="false" logY="false" logZ="false" xPrecision="2" yPrecision="2" zPrecision="2" scaleMinX="auto" scaleMaxX="auto" scaleMinY="auto" scaleMaxY="auto" scaleMinZ="auto" scaleMaxZ="auto" minX="0" maxX="0" minY="0" maxY="0" minZ="0" maxZ="0"  mapWidth="0"       >
                <input axis="x">t</input>
                <input axis="y">A_abs</input>
            </graph>
        </view>
    </views>
    <export>
    </export>
</phyphox>

Again a few notes:
  • I extended the container size to 5000. This way I get graphs showing roughly the last 30 seconds.
  • I enabled "partial Update". Forgot this before in 3 of 4 graphs.
  • I tried to swap the calculations: Firstly the "Absolute" graph, then "x/y/z". Seemed to be no difference.
  • I tried to to combine the calculations: Firstly x/y/z, then connecting the output of them to the "Absolute" formula. I thought this would be a great idea - but it didn't worked out.

Final question:
How would I permanently distribute this work? I created a little Icon, now I'm getting up to 10 Offline QR-Codes and the Online-QR-Code is not permanent for sure. Same would go for another config file for the magnetometer, which I'm planing to edit soon.

May I add a little bug report:
  • When marking a few characters in an input-field in the editor and then pressing "Delete", the editor is asking me "Would you like to delete this module?"
  • When searching for bluetooth devices within the app I have to touch the desired entry quite often (5 to 10 times) until it is recognized by the app.
Thanks again for all your help!


RE: Calliope Mini as external Accelerometer - Sebastian Staacks - 03-08-2020

(03-08-2020, 05:53 PM)Jonathan Haug Wrote: Actually there is a characteristic called "Accelerometer Period", which "determines the frequency with which accelerometer data is reported in milliseconds."
[Micro:bit Docs]

But I was not able to write a proper new value with nRF Connect due to too many questions (hex or uint16 ? with or without "0x"? from right to left or from left to right? byte array or uint8?)

The doc says it is uint16 (and everything else seems to be little endian, so this probably is also little endian). In nRF Connect you should then simply enter one of the listed valid option. However, their descriptions says that it is the "frequency in milliseconds". Uhm...? Since the title says that it is the period, I would guess, that it is in fact the period. But a period of 1ms would amount to a frequency of 1000 Hz and I do not believe that this works properly through Bluetooth Low Energy. You need to try a few values if you'd like to change it. In phyphox you could then set it as a "config" entry in the Bluetooth block, which should also work with "uInt16LittleEndian" as a conversion function.

(03-08-2020, 05:53 PM)Jonathan Haug Wrote: Final question:
How would I permanently distribute this work? I created a little Icon, now I'm getting up to 10 Offline QR-Codes and the Online-QR-Code is not permanent for sure. Same would go for another config file for the magnetometer, which I'm planing to edit soon.
Well, so far, we have not yet deleted any QR codes and since each is only associated with a file that has a size of few kB, we are keeping an eye on the huge amount of files, but do not yet intend to delete anything - we also do not guarantee, that it is working forever. The best way to share it, is to download the phyphox-file from the editor and place it in our wiki. You need to create an account (which I have to approve because of massive spamming by bots in the past) and then simply upload the phyphox-file to the wiki. If you simply link to this uploaded file on the Micro:Bit/Calliope page, the wiki will automatically create the context menu which allows creating a QR code or downloading the original file. Just have a look at the Wiki code of the first few entries (the other ones with QR codes are from a user).

(03-08-2020, 05:53 PM)Jonathan Haug Wrote: When marking a few characters in an input-field in the editor and then pressing "Delete", the editor is asking me "Would you like to delete this module?"
Thanks. The editor really needs a few fixes and lacks some functions. At the moment, I just cannot find the time to work on it.

(03-08-2020, 05:53 PM)Jonathan Haug Wrote: When searching for bluetooth devices within the app I have to touch the desired entry quite often (5 to 10 times) until it is recognized by the app.
Thanks again. I have added it to my todo list (it sometimes felt a bit unresponsive to me as well, but never bad enough to really look into it). Hopefully, I can figure  it out for the next release.