Tuesday, 25 December 2018

Coding the BinaryBots Totem sensor board with MakeCode

Introduction

CBisEducation is a relative newcomer in the world of STEM education. Their first products were BinaryBots Dimm and UFO cardboard robots, a robotic arm and a remote controlled car, all using the BBC micro:bit. The newest kits in the BinaryBots range are the three Planet Totem kits - Crab, Spider and Tortoise. All three kits have the same electronics – just the mechanics differ between them.

The Totem custom-designed boards are made for the BBC micro:bit and comprise a “power board” and a “sensor board”.

The power board consists of an edge connector into which you slot the micro:bit, a 3xAAA battery holder, three motor ports (one of which controls the crab's claw) and an on/off switch. The sensor board contains 4 RGB LEDs, a piezo-sounder, vibration motor, a light-level sensor, temperature sensor and two touch button/slider sensors.

Whether you follow the instructional videos on the BinaryBots website, or use the booklet provided (“Inventors Manual”), the first bit of coding you will do will be to make the claw open and close using the excellent MakeCode for micro:bit block-based coding environment.

As far as I could see, after that, you are on your own unless you then move to the Python environment as there are no further examples or tutorials using MakeCode. Specifically, there is no way to control any of the components on the sensor board using MakeCode blocks. For younger children, this could be disappointing, as they would want to make use of the sensor board with its RGB LEDs, vibration motor and piezo-sounder. It could be quite a big leap to go straight into Python coding. This blogpost is about how to control the sensor board with MakeCode.

Hardware description

Power board

Rather than use a small servo to control the positioning of the claw pincers, BinaryBots have opted for a standard DC micro-metal motor which uses a worm gear to slow it down (and increase torque). One micro metal motor is provided in the kit. This operates one of the crab’s claws (the other claw is fixed). Motor port 1 on the power board connects to pins P13 & P14 on the inserted micro:bit. Pins P19 & P20 on the micro:bit are reserved for the I2C port. The three most commonly used pins (P0, P1 AND P2) plus 3V and GND and brought out onto banana plug terminals at the front of the power board.

Power board pin assignments
Board function Micro:bit pins
Motor 1 Pins P13 and P14
Motor 2 Pins P15 and P16
Motor 3 Pins P8 and P12
Pin 0 (front of board) P0
Pin 1 (front of board) P1
Pin 2 (front of board) P2
3V (front of board) 3V
GND (front of board) GND

Sensor board

The sensor board is actually a standalone microcontroller board based on the STM32F051K6 ARM Cortex-M0 Access line MCU with 32 Kbytes Flash and 48 MHz CPU. The micro:bit communicates with the sensor board CPU via I2C and the sensor board CPU, in turn, communicates with its own sensors and actuators and passes the data back along the I2C bus to the micro:bit. This means that the micro:bit only needs to know the I2C address of the board – not of the individual sensors and actuators. The firmware on the board listens on the I2C bus and sends the data requested. The touch button/slider sensors are quite complex; along each strip there are three “button points” and 100 “slider points” that can be detected.

Coding with Python

BinaryBots have provided several examples of Python code on their website [https://www.binarybots.co.uk/activities] to move the crab’s pincers, control the LEDs and read the touch and temperature sensors. For beginners, I think it would have been more helpful if BinaryBots had written a Python module with functions to which you can pass parameters, rather than having to use the ‘struct’ data format, which can be quite complicated.

The Python struct.pack function converts all the data into two formats (‘B’ for 8-bit data and ‘H’ for 16-bit data).

The board uses command numbers to identify which board device to use. Here are all the valid commands and data expected:
Function
Command number
Data Format
LED
0
‘<BBBBB’
Buzzer
1
‘<BBH’’
Vibrator
2
‘<BHB’
Read Buttons
4
‘B’
Read Sliders
5
‘B’
Read Light sensor
6
‘B’
Read Temperature sensor
7
‘B’
Reset
8
‘<BB’


 Where there is more than one byte, the ‘<’ symbol signifies that the byte values are to be passed in ‘little-endian’ order. In the case of the LEDs, the five bytes (BBBBB) are:

[0],[LED#], [R], [G], [B].


LED# can take one of five values (one for each LED or 0 for all four). For example, to turn all four sensor board LEDs green, the example Python code is:

i2c.write(42,struct.pack('<BBBBB',0,0,0,255,0))

Although the sensor board has a light sensor and temperature sensor, there is no documentation provided on either sensor, apart from some sample code. Although BinaryBots provide some sample code for reading these sensors, they do not provide any information on what the numbers represent. The Python code for the light and temperature sensors suggest that the outputs are 16-bit signed integers (0-1023) so it appears they are analogue sensors. The light sensor is clearly visible and marked on the board but there is no sign of a temperature sensor. I conclude that the temperature reading is actually the ARM Core CPU temperature, which is supported by the fact that placing my finger directly onto the MCU caused the reading to rise.


Here is the micropython code for reading the temperature sensor and printing the raw analogue value via the USB cable to the PC console (REPL):

from microbit import * 
import struct 
sleep(150) 
while True: 
     temp = i2c.write(42,struct.pack('B',7)) 
     sleep(150) 
     i2c.write(42,struct.pack('B',7)) 
     sleep(10) 
     rx = i2c.read(42,2) 
     temp = rx[0] + (256 * rx[1])  
     print (temp)

Substituting (42,struct.pack('B',6)) with (42,struct.pack('B',7)) will print the raw light sensor readings, instead of the CPU temperature, to the REPL.

Coding with MakeCode

As discussed in the Introduction, MakeCode does not provide an easy way of controlling the sensor board. Ideally, BinaryBots would have done what other companies like Seeed Studios have done, and produced a MakeCode extension so that blocks were available for controlling the sensors and actuators on the sensor board. Although there are no MakeCode blocks available that can control the sensor board, the MakeCode editor provides a Javascript/Typescript coding window. By converting the Python code into Javascript, it is possible to control the sensor board with MakeCode.

The equivalent Javascript of the example given above to turn on all four LEDs in a green colour...

i2c.write(42,struct.pack('<BBBBB',0,0,0,255,0))

is

let buf = pins.createBuffer(5); 
 buf.setNumber(NumberFormat.Int8LE, 0, 0); 
 buf.setNumber(NumberFormat.Int8LE, 1, 0); 
 buf.setNumber(NumberFormat.Int8LE, 2, 0); 
 buf.setNumber(NumberFormat.Int8LE, 3, 255); 
 buf.setNumber(NumberFormat.Int8LE, 4, 0); 
 pins.i2cWriteBuffer(42, buf, false);

The first line sets up a 5 byte buffer ‘buf’. The next five lines put 5 bytes into the buffer and the last line writes the buffer ‘buf’ to device address 42 on the i2c bus (i.e. the sensor board). Two of the components on the sensor board (the buzzer and the vibrator) require 2 bytes plus one word (i.e. 4 bytes in total). In those cases, the word data format is NumberFormat.Int16LE.

If you go back to the Blocks window, you'll see something like this:



As can be seen, the Python code is much more economical. However, I wanted to use MakeCode because I have not yet found a reliable way to use the Grove Ultrasonic Ranger in micropython and I wanted one of those to make my Crab more entertaining. Also, I wanted to show that it is possible!

To save some typing and make my code more efficient, I created some MakeCode functions out of the Javascript. Once the Javascript functions have been defined, MakeCode turns them into blocks, as per the image below, which sends commands to the sensor board to make some noises with the piezo sounder.



Close

Once you have created the custom blocks and functions that you need using Javascript, you can then go back to the Blocks window and use them with the normal MakeCode blocks. The screenshot below shows a load of my custom blocks/functions combined with other blocks, including Seeed Studio blocks to control their 'ultrasonic ranger', as well as a neopixel ring.

Custom blocks

Although it takes a little while to work out the correct Javascript to do what you want with the sensor board, it can be done! Hopefully, with the information provided here, other people will be able to do the same.


No comments:

Post a comment