Sniff is a "Scratch-like" programming language that's designed to help Scratchers move gently from Scratch to more conventional languages. They can start writing programs, without having to learn a new language because Sniff is based on Scratch. They learn a little more about variables, compiling, syntax errors (!), and they can have fun controlling real hardware while they're doing it.

Wednesday, 27 April 2016

Sniff From Scratch #6: Microbit Compass

In addition to the accelerometer the Microbit also includes a Magnetometer. It's two main uses are either to make a compass, or to detect the movement of metal objects around it. While in principle its pretty simple there are couple of gotchas:


make i2c device
make magnetometer mag3110 device
make xMagneticField number
make yMagneticField number
make zMagneticField number
make heading number

start by making an i2c bus (you only need this once even if you're using the accelerometer and the magnetometer), and adding a mag3110 device. This is the proper name for the chip that the Microbit uses.

Now we can just tell it to "read" and we get our results back:

when start
.forever
..tell magnetometer to "read"
..say [ xMagneticField ]
..say [ yMagneticField ]
..say [ zMagneticField ]
..say join "Heading " [ heading ]
..say ""
..wait 1 secs


The x/y/z values are the measured strength of the magnetic field on each axis and the heading is just calculated from the x and y values. You could calculate it in Sniff but while the maths is easy, its actually surprisingly hard to code (try it and check it your results agree).

To turn that into a proper compass we just use the angle of heading to draw a needle:

make i2c device
make magnetometer mag3110 device
make heading number

make display microbitDisplay device
make displayX number
make displayY number
make displayColor number

when start
.forever
..tell display to "tick"

when start
.forever
..tell magnetometer to "read"
..set heading to heading/45
..set heading to round heading
..set heading to heading*45
..
..set displayColor to 000
..tell display to "clear"
..
..set displayX to 3-2*cos of heading
..set displayY to 3-2*sin of heading
..tell display to "move"
..
..set displayColor to 111
..set displayX to 3
..set displayY to 3
..tell display to "draw"
..set displayColor to 777
..set displayX to 3+2*cos of heading
..set displayY to 3+2*sin of heading
..tell display to "draw"
..
..wait 0.1 secs

The only "clever" bit here is that to get nice straight line on the low res display, we round the angle to the nearest 45 degrees, but dividing by 45 (to see how many 45's we have), rounding to the nearest whole number then multiplying back again.


So far so good... however you might find that you get some strange results. The thing is that the magnetometer is sensitive to magnetic and electric fields, but then we've gone and put on a circuit board surrounded by metal and electricity! While this is definitely a problem, its not as bad as it sounds because those bits of metal don't move relative to the chip, so we can calibrate them out.

By default the compass is constantly calibrating, so if you just write your code, you might find that it doesn't work properly for a few seconds, until its taken a few readings and the calibration settles down. Turning the microbit around while this is happening will help a lot, and it will fairly quickly start producing good results.

Where this can backfire is if you place the microbit in a changing magnetic field. The calibration method assumes you're in a constant field and that changes are due to the chip rotating. If you want to measure changes accurately, then you need to calibrate before you start measuring. The variable compassCalibrate is normally just set to yes, but if we want more control then set it to yes, take some readings to calibrate the system, then turn off calibration, so that from then on the calibration if fixed. This will give you a more accurate/reliable measurement of changes in the field (which might otherwise be partially calibrated out).

make compassCalibrate boolean

when start
.set compassCalibrate to yes
.
.say "Calibrating"
.repeat 50
..tell magnetometer to "read"
..wait 0.1 secs
.
.set compassCalibrate to no
.
.forever
..tell magnetometer to "read"
..say [ xMagneticField ]
..say [ yMagneticField ]
..say [ zMagneticField ]
..say join "Heading " [ heading ]
..say ""
..wait 1 secs

With a bit of tweaking you can use this to detect metal objects moving near the microbit.


Electric motors also mess with the magnetic field, which can be both a win or a loss - you can detect when devices turn on and off just by putting the microbit close to them. However it also means that if you have a robot buggy and want to use the magnetometer to detect which way its pointing (very handy, as you can now make precise 90 degree turns!) make sure you place the microbit well away from the motors.

2 comments:

  1. Nice one and thanks! I think when you want to go camping, it's necessary to know the basic survival skills that you'll need to survive. These include map reading, compass reading and fire starting, among others. I've recently on the lookout for a sturdy and reliable compass to meet my needs. I do invest in quality gear, but the price has to meet my budget, as well. This site provides quite a number of good choices, you just have to take a look http://myoutdoorslife.com/gear/camping-and-hiking/best-compass.html

    ReplyDelete