Logging accelerometer data with the micro:bit (Part 2A: Saving to memory)

What would we need to do to have the micro:bit be a useful logger of acceleration data?

  • Set a sampling rate (covered in the first part, here)
  • Store data on the micro:bit’s local storage
  • Play the data back or transfer it to a computer for analysis

In the first part, I took a look at setting/limiting the sampling rate. I did this for a couple reasons:

  1. I made the assumption that having a super high sampling resolution (100+ times per second) is not necessary for the kinds of applications we might want
  2. While we can, indeed, read/sample data quite fast, the micro:bit is quite limited in terms of where we can put the data.

Imagine this like a pipe with water (the water is the data) flowing through it. A huge amount of water could be flowing through a pipe, but to store it, you’d need to block up one end of the pipe. If you do that, how fast would the pipe become full of water and burst? It depends on the size of the pipe, or if you could, say, siphon some of the water out and put it somewhere else.

Continue reading “Logging accelerometer data with the micro:bit (Part 2A: Saving to memory)”

Logging accelerometer data with the micro:bit

What would we need to do to have the micro:bit be a useful logger of acceleration data?

  • Set a sampling rate
  • Store data on the micro:bit’s local storage
  • Play the data back or transfer it to a computer for analysis

The micro:bit has an accelerometer and magnetometer (compass) powered by ST’s LSM303AGR chip (https://www.st.com/en/mems-and-sensors/lsm303agr.html). According to the chip’s technical specs, in terms of acceleration, you can use the micro:bit to measure acceleration up to ±16g (1g being acceleration due to gravity, i.e. 9.8 m/s2—16g is 16x acceleration due to gravity). The micro:bit uses this chip to detect gestures but it can also be used just to read acceleration in 3 axes.

In this first part, I will show a method of setting the sampling rate and plotting the accelerometer data from the micro:bit.

Setting a sampling rate

What might not be obvious is that for some things, the micro:bit is actually running really fast. For example, if all we do is call accelerometer.get_values() (which emits a tuple of the x, y, and z accelerations as measured by the accelerometer), the micro:bit can read in excess of 1400 times per second. You can try it yourself with:

from microbit import *

counter = 0

while True:
   
    if counter % 5000 == 0:
        print("{n} iterations in {t} ms ({rate} per second)".format(
                n=counter, 
                t=running_time(),
                rate=counter*1000/(running_time())))

    accelerometer.get_values()
    counter = counter + 1 

Of course, every additional line of code we add would slow down execution, but practically speaking, we probably only need to sample acceleration at most 10-20 times per second (sampling frequency). To get the sampling period, i.e. the time between samples, recall that period is the inverse of frequency:

period = 1/frequency

Thus, to achieve a sampling frequency of 10 times per second, we need to leave 1/10 of second (100 milliseconds)  between samples. We can do this using the micro:bit’s built-in sleep() function as follows:

from microbit import *

frequency = 10

while True:

    print(accelerometer.get_values())
    sleep(1000/frequency)

You might notice that I used the print() function in the previous block of code. If you use Mu (https://codewith.mu) as your code editor, you’ll have access to a REPL which is essentially like a console, meaning that you can print out text from your micro:bit. Mu also has a plotter which will automatically plot any tuples emitted using print– lucky for us, accelerometer.get_values() provides such tuples:

Pretty neat!

In the next part, I’ll discuss saving your data to the micro:bit’s memory and local storage. Stay tuned!

Design Blog #3 – micro:bit and motors

After a bit of tinkering, I made a short clip of a micro:bit being used to control a robot platform. One of the challenges of using the micro:bit for something like this is the limit on the amount of current (mA) the micro:bit can provide. In some cases, the voltage (max 3.3V) that it can provide is also an issue.

In this particular case, the platform (from CodeMyRobot) uses a separate chip (or integrated circuit/IC) to drive the two motors, one for each wheel. Usually, integrated circuits will have a model number written on them to identify them. In this case, the chip being used was an L9110. A quick Google search later, and I had found a description of the L9110, including how to control it. Once supplying it with power, two inputs could be used to control the direction of a motor:

Pin A Pin B Output
L L Off
H L Forward
L H Backward
H H Off

So , according to that table, if you wanted the motor to spin forward, you would set Pin A to “High” and Pin B to “Low”. On the micro:bit, if you’re not using a breakout board, you have access to three pins along the bottom edge: Pin 0, Pin 1, and Pin 2. You also have a 3.3V power pin (which can either be an input or an output) and a ground pin.  We have to be the ones to tell the micro:bit which pins it should be using and how. In our case, we can say that Pin 0 will correspond to Pin A, and Pin 1 will correspond to Pin B. If we want the motor to run forward when, say, Button A is pressed, our MicroPython code might look something like:

from microbit import *

while True:
    # Go forward
    if button_a.is_pressed(): 
        pin0.write_digital(1) # Pin A = High
        pin1.write_digital(0) # Pin B = Low
    
    # Stop
    else:
        pin0.write_digital(1) # Pin A = High
        pin1.write_digital(1) # Pin B = High

So, as long as Button A is pressed, the motor will run forward; as soon as it’s not pressed, both Pin 0/A and Pin 1/B are set to “High” which, according to our table, means the motor shuts off. In the video above, both motors are using the same inputs, i.e. I’m sending the same signals to two L9110 chips, which make the motors attached to them behave the same way. This means, though, that I can only move forward or backward, because to turn, I need to have one motor running faster than the other, which means having them do different things. I can accomplish this through use of the third pin (Pin 2) and sharing one of the pins. Consider the following setup:

  • we have our left motor as Motor A and our right motor as Motor B
  • Pin 0 is now Pin A for Motor A
  • Pin 1 is now Pin A for Motor B
  • Pin 2 is shared, and is Pin B for Motor A+B

Then, to get the micro:bit to put out the correct signals on its pins, we have to figure out what the desired outputs should be, as in below:

Desired outputs Pin 0 Pin 1 Pin 2 (shared)
Off L L L
Forward (i.e. Motor A+B forward) H H L
Backward (i.e. Motor A+B backward) L L H
Left (i.e. Motor B only forward) L H L
Right (i.e. Motor A only forward) H L L

The code below defines a few functions to make our lives easier if we wanted to reuse or combine any of these actions. It runs through a sequence of forward, back, left, then right, for 0.75 seconds each, with a 4 second stop in between.

from microbit import *

wait_amount = 750

motor_a_pin_a = pin0
motor_b_pin_a = pin1
motor_shared_pin = pin2

def forward():
    motor_a_pin_a.write_digital(1)
    motor_b_pin_a.write_digital(1)
    motor_shared_pin.write_digital(0)
    
def backward():
    motor_a_pin_a.write_digital(0)
    motor_b_pin_a.write_digital(0)
    motor_shared_pin.write_digital(1)
    
def left():
    motor_a_pin_a.write_digital(0)
    motor_b_pin_a.write_digital(1)
    motor_shared_pin.write_digital(0)
    
def right():
    motor_a_pin_a.write_digital(1)
    motor_b_pin_a.write_digital(0)
    motor_shared_pin.write_digital(0)

def stop():
    motor_a_pin_a.write_digital(0)
    motor_b_pin_a.write_digital(0)
    motor_shared_pin.write_digital(0)
    
while True:
    stop()
    display.show(Image.ASLEEP, wait=False)
    sleep(4000)
    
    forward()
    display.show(Image.ARROW_N, wait=False)
    sleep(wait_amount)
    
    backward()
    display.show(Image.ARROW_S, wait=False)
    sleep(wait_amount)
    
    left()
    display.show(Image.ARROW_W, wait=False)
    sleep(wait_amount)
    
    right()
    display.show(Image.ARROW_E, wait=False)
    sleep(wait_amount)

This would depend on your physical setup– for example, when I plugged everything in the first time, everything was reversed. It was an easy switch–swapping the physical connections of Pins 0 and 1. You can see the video of the code running in this tweet:

One of the easiest ways to figure out what a device is capable of is to read (or at least search) the documentation. For example, how did I know how to “tell” the pins to be high or low? I check the documentation for MicroPython, micro:bit, and how to use its pins: http://microbit-micropython.readthedocs.io/en/latest/microbit_micropython_api.html#pins

Design Blog #2 – Learning a new platform (micro:bit!)

I’ve been spending some time getting familiar with the BBC micro:bit, which is (essentially) a microcontroller with a bunch of things already done for you. One of my biggest issues when thinking about how to teach people to use Arduinos is the amount of overhead (in both time and components) required to get it to do something interesting. The micro:bits takes a different approach, integrating things like:

  • an accelerometer
  • a compass
  • a 5×5 LED matrix
  • two push buttons
  • Bluetooth Low Energy (BLE)
  • and a proprietary-ish “radio”

While these are certainly available to add on to an Arduino-based project, the micro:bit and its development environment provide direct access, without the need to fiddle with SPI or I2C– perfect for beginners looking to develop projects around the functionality that these components afford, without necessarily being at the point where they want to learn about the intricacies of communicating with the devices.

I also like that you can use a variety of programming languages to program the micro:bit. My first foray used the block-based editor: not only is it a familiar interaction experience (much like Scratch), but it allows you to switch (and edit!) the code generated by the blocks, which is TypeScript. This addresses some of the issues I had with Scratch’s interface and how time consuming/click intensive some simple activities were (e.g. trying to do greater than or equal to) by letting you write/edit the code that’s generated.

You can also use a variety of Python called MicroPython, which is a pared down version of Python. On the micro:bit, there is a fairly comprehensive description of what is exposed by the microbit module; most things are included/available, though my understanding is that BLE is not. I use a free editor called Mu which runs without installation. Here are a few notes based on the brief time I’ve spent with the device so far:

  1. You can power the device in a number of ways, including a 2-pin JST-PH connector and battery back, via USB, as well as via a 3.3V pin exposed on the board’s edge. If you’re powering by USB, be aware of the current limitation (120 mA), which will affect whether or not you can power things like servomotors.
  2. If you’re going to try and power the board via the edge pins (3.3V and GND), you must use a regulated 3.3V supply. The board is at most 3.6V tolerant according to the micro:bit documentation. This means no LiPo/Li-ion batteries being directly connected (as they range from 4.2V to 3.7V).
  3. If you want to use (micro)Python, Mu seems to be a good choice for a local environment: https://codewith.mu/#download
  4. The web environments for both Block-based/TypeScript and Python seem to work well. If you’re using these, one easy way to save some clicking and dragging is to have your browser prompt you for the download location. In Chrome, for example, this means going into the Settings -> Advanced -> and flipping the switch that says “Ask where to save each file before downloading”. Then, you can save the generated .hex file directly to the micro:bit.

Design Blog #1 – Measure twice, print once

My shower has two controls: a temperature ring and a flow rate knob. The flow rate knob in my shower broke the other day.  Without the knob, you can’t turn the shower on or off, which is kind of crucial for taking a shower.

Each of the above are various solutions or attempts at solutions to the problem of having no on/of knob. The pliers worked in a pinch, and I used them for about a week or so, but they weren’t an elegant (or permanent) solution. I set about designing a new knob. The original knob was held onto a post with a screw. The first centimeter or so of the post had an oval-ish shape; you can see it in the printed designs above, but the shape is essentially a circle, but with two flat, parallel sides. The one key dimension in this case would be the width across the two flat sides. The dimension of the circle isn’t critical so long as it is at least as long as the long dimension of the post (it can be longer; the knob “grabs” with the flat sides). I’m printing in white ABS, at 235/105 (extruder temp/bed temp).

For the first attempt, I had incorrectly recorded the key measurement: I had used 4 mm instead of 6 mm. The knob finished printing, but it didn’t fit. I had also incorrectly oriented the model in the slicing software such that it printed supports and a raft. You can see the remnants of the raft in the picture above. It is the filled in part of the long section

For the second attempt, I used the correct measurements for the keyhole area. It fit, but the keyhole section wasn’t sufficiently deep, again, because I had recorded the wrong measurement. It worked-ish, but wasn’t nice. It was also humorously long and was aesthetically intrusive. As you can see above, I didn’t even bother putting a hole through the keyhole.

For the third attempt, I scaled back the handle part of the knob to a much more reasonable size. I also used a drill press to make a hole for the screw to fit it. I mounted it to my shower and it functioned, but it still looked funny. It was also time (and resource) consuming to print because of the big flat pancake of the top.

For the fourth and final (for now) attempt, I went with a hollow gear shape. First, aesthetically, it fits much better and is much less intrusive compared to the rest of the elements in the shower. Second, avoiding large flat spaces improves printing speed and reduces resource consumption. Third, I included the hole for the screw directly in the printed design so I didn’t have to drill it out after. I’m mostly happy with this design, and it works quite well. I think it could use a bit of flair, but the design itself is clean and prints quickly.

Like brushing your teeth

Somebody once described remembering to blog or maintaining a blog as being like brushing your teeth: you just need to make it a habit, something that you do regularly and without hesitation. Of course, I’m the kind of person that forgets their toothbrush when travelling and ends up with one of those weird hotel toothbrushes with two rows of bristles, about a third of which come out in your mouth the first time that you use it.

I will say that what I’m really good at is starting blog posts, but what I’m really bad at is finishing them. The first draft of this post, for example, consisting only of the title, was written a week ago. So to help content generation along, I’m going to lay out the kinds of things I will be putting here:

  • I came up with the concept of “Impractically awesome” when I was thinking about  designs for artifacts or products that are solutions ridiculously specific to situations that I encounter in everyday life. These are the kinds of things that you think about, and then dismiss as being silly or overly specific. I thought, yes, but what if we just designed (and perhaps made) them anyway? So I’m thinking lots of one-off designs to solve problems you never knew you had because you probably don’t. That’s going to be part of the core content.
  • The other is to give an outlet for short form writing and reflection on either what I’m reading or what I’m writing about. Essentially, mini-articles sharing the work that I’m doing that might not ever become full articles. I have a couple of these in mind, but can’t dedicate a whole whack of time to them, so this is how they’ll exist.

That’s going to be the bulk of the content. Some drawing, some writing, some photos… A little bit of everything. Plans can, of course, change, but I think this’ll be a good way to keep the brain juice flowing!

Until next time! 🙂

May you live in interesting times*

“May you live in interesting times” is said to be an ancient Chinese curse, a projection of the cultural tendency towards risk aversion associated with many Asian countries. For these cultures, or so it goes, interesting times refer to an unwelcome uncertainty, ambiguity, or lack of stability–“Better to be a dog in a peaceful time than be a man in a chaotic period” (another Chinese saying**). A more familiar way to think about it may be along the lines of “better safe than sorry,” an approach to negative outcome reduction that deals with mitigating known issues ahead of time.

Maybe it’s just my youthful vigor (or just my casual nihilism), but I can’t imagine the point of a world that is uninteresting. This doesn’t mean that we (the big we, the human race) have to be in constant conflict. But a world of stability and complete risk avoidance is a world that is stagnant. It is a world that is petrified, ossified. Without risk, there would be no innovation. No new ideas. It would be boring. And to be bored, is to be dead.

So, with my little slice of the Internet, I’ll try to keep things interesting. 🙂

*As is readily found around the Internet, it is likely that this saying is, in fact, apocryphal. Still, Chinese or not–and I’m not a huge subscriber to “ancient wisdom”– it neatly embodies a sentiment towards risk and uncertainty. Also, sayings aside, there is some research to show that Asian cultures do tend to be more risk averse.

**This one seems to be real.