Sunday, 5 July 2020

Reading USB (Serial) data

Most microcontrollers have an option to output data over the USB link.

It is helpful during development to be able to read state information and other values that allow the developer to see what is happening.

The first thing is to identify which USB port is in use.
            foreach (string port in ports)
            {
                Console.WriteLine(port);
            }
For my set up, COM5 was the one in use.
using (var sp = new System.IO.Ports.SerialPort("COM5", 115200, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One))
            {
                Console.WriteLine("Reading serial port");
                sp.Open();
                while (true)
                {
                    var readData = sp.ReadLine();
                    Console.WriteLine($"[{readData}]");
                }
            }
This will display on the console anything output from the device.





Sunday, 14 June 2020

BBC Micro:Bit Menu system (with persistent choice)

The BBC Micro:Bit is a simple microcontroller with a 5 x 5 matrix of LEDs, two buttons, 3D magnetic and acceleration sensors and a CPU temperature sensor.
The two buttons can make complicated interfaces rather difficult, however it is possible to build one.
One aadditional feature of this menu system is that your choices are persistent. If you select menu item, power off the Micro:Bit then subsequently power it back one, it will remember the choice (subject to it not being reflashed of course).

Code

This was written in Micropython using the Mu editor.
from microbit import *
import os
import utime
menuitem = 0
if 'choice.opt' in os.listdir():
    with open('choice.opt') as choice:
        menuitem = int(choice.read())
display.scroll("Menu item" + str(menuitem))
start = utime.ticks_ms()+6000
interval = 2000
while True:
    now = utime.ticks_ms()
    if start > now or now - start > interval:
        if menuitem == 0:
            temp = temperature()
            interval = 2000
            display.scroll(str(temp) + 'C', delay=100, wait=False)
        elif menuitem == 1:
            temp = temperature()
            interval = 2000
            display.scroll(str(temp + 273.15) + 'K', delay=100, wait=False)
        elif menuitem == 2:
            level = display.read_light_level()
            interval = 2000
            display.scroll(str(level) + ' light', delay=100, wait=False)
        elif menuitem == 3:
            level = compass.get_field_strength()
            interval = 6000
            display.scroll(str(level) + ' nTesla', delay=100, wait=False)
        elif menuitem == 4:
            display.scroll("Menu test")
        start = now 
    if button_a.is_pressed():
        display.scroll("Menu", delay = 100)
        sleep(50)
        while not button_a.is_pressed():
            display.set_pixel(4,menuitem,5)
            if button_b.is_pressed():
                display.set_pixel(4,menuitem,0)
                menuitem = menuitem + 1
                if menuitem > 4:
                    menuitem = 0
                with open('choice.opt','w') as choice:
                    choice.write(str(menuitem))
                display.scroll("Menu item" + str(menuitem), delay = 100)
            sleep(100)
            display.set_pixel(4,menuitem,5)
            sleep(100) 
    sleep(400)
The persistent choice is handled by this code:
menuitem = 0
if 'choice.opt' in os.listdir():
    with open('choice.opt') as choice:
        menuitem = int(choice.read())
The menu item is given a default value (0).
The file 'choice.opt' is checked if it exists in the directory list, if it is, then the value of the menu item is read from the file and assigned to the menuitem variable. When a subsequent decision is made to change the menuitem, this value is written out to the file, making it available the next time the Micro:Bit is switched on.

The main loop is entered after the start variable is set in advance of the current tick count and the display interval is set (strictly speaking the interval should be dependent on the menu choice but it only affects the first cycle).

Each loop, if the difference between the ticks now and the (loop) start ticks is greater than the interval, then the menuitem is used to choose what to do.
In this example it is used to choose which sensor is read and the results displayed.
Menu choices are:

  1. Temperature in degrees Celsius.
  2. Temperature in Kelvin
  3. Light level (based on the light falling on the LED matrix)
  4. Magnetic field strength in nanoTesla (using the compass module)
  5. A message.
The first three keep the interval at two seconds, but the magnetic field strength is a longer piece of text, so that is stretched to six seconds by setting the interval.
The Start ticks value is set to the Now value.

The next part of the code checks for the A button (left side) being pressed.
If so, it then loops until the button is pressed again.
Inside that loop, pressing the B (right hand) button increments the menuitem value, writes it to the file and shows a pixel on the right hand column indication which option is currently chosen.
Pressing button A exits the loop and recommences the outer infinite loop.

Disadvantages

This does mean that during normal operation, button A is not available. This might not be an issue but is something to bear in mind.

References


Saturday, 13 June 2020

Pimoroni Envirobit

Pimoroni Envirobit


The Pimoroni Envirobit is a set of sensors for the BBC Micro:Bit .


As you can see, it is equipped with a slot to take the Micro:Bit, so no soldering is required.

The Envirobit is fitted with the following sensors:

  • BME280 environmental sensor - which measures temperature, pressure, humidity and can calculate the altitude based on a supplied base pressure level (discuss).
  • tcs3472 RGB sensor - which measures Red Green and Blue light levels as well as “white” light levels. Also includes two illuminating (white) LEDs,
  • Sound - a small microphone allows the sound level to be measured on one of the Micro:Bit’s analogue pins

Assembly

Assembly is simple. Take the Envirobit board with the sensors facing forward, and insert the Micro:Bit with the LEDs also facing forward.
Due to the nature of the connection, you can swap the Microbits if the colour scheme does not match your needs.

Software

The main software support for the Envirobit is orientated towards the Microsoft MakeCode block based system.
There is some support for MicroPython. There is a GitHub link here: https://github.com/pimoroni/micropython-envirobit

There are three python files in the Library.
  • sound.py
  • bme280.py
  • tcs3472.py

The files can be transferred to your Micro:Bit using the Files function in Mu.

Sound

Contrary to the description on GitHub, this is not a class, just three methods.

  • sound.read() - This takes a reading of the sound level and returns a value between 0 and 440. There is an offset value in the code to set the minimum sensitivity.
  • sound.wait_for_double_clap() - listen for two high level sound events in a second, returns True if detected
  • sound.wait_for_clap() - listen for a single high sound level event in a second, returns True if detected

tcs3472

This uses a class to access the TCS3472 sensor via I2C.
To use the sensor, import the module (having transferred it to the Micro:Bit) and instantiate an instance.
import tcs3472
light_sensor = tcs3472.tcs3472() 
Methods:

  • r, g, b = light_sensor.rgb() - returns a tuple of the corrected levels of red, green and blue out of 255
  • r, g, b = light_sensor.scaled() - return a tuple of the amounts of red, green and blue on a scale of 0-1
  • level = light_sensor.light() - return a raw reading of light level on a scale of 0-65535
  • light_sensor.set_leds(0) - Turn the LEDs off
  • light_sensor.set_leds(1) - Turn the LEDs on

BME280

This uses a class to access the BME280 sensor via I2C.
The instructions on GitHub are incorrect, there is a missing () on the end of the class instantiation. Python can be very unforgiving if you make a mistake of this kind.
import bme280
bme = bme280.bme280()

The bme280 class has the following methods:

  • temp = bme.temperature() - return the temperature in degrees C
  • pressure = bme.pressure() - return the pressure in hectopascals
  • humidity = bme.humidity() - return the relative humidity in %
  • alt = bme.altitude() - return the altitude in feet, calculated against the current QNH value
  • bme.set_qnh(value) - set the QNH value for calculating altitude

QNH is the atmospheric pressure adjusted to sea level (what the pressure sensor should read at sea level).
https://en.wikipedia.org/wiki/QNH

References

https://github.com/pimoroni/micropython-envirobit
https://en.wikipedia.org/wiki/QNH


Thursday, 28 May 2020

Inkscape - SVG to PNG conversion

Inkscape is an Open Source vector graphics editing application.
The primary file type  is the Scalable Vector Graphics format. Modern browsers support the format.

However, there are still applications where bit map or raster graphic formats are required (Microsoft Azure Marketplace still wants specific resolution PNG files). Inkscape is a useful tool to convert the SVG format files to PNG.

Inkscape is in the process of rolling out version 1.0 which changes the command line parameters - so check your version.

Installation

Inkscape is available via the Raspbian repository.
After updating and upgrading the operating system, use:
sudo apt-get install inkscape

You can check the installed version.
inkscape -V
Inkscape 0.92.1 r15371

Command line usage

Inkscape has an extensive GUI, but it can also be used via command line. This is particularly useful if you want to convert an SVG file to a number of different sizes.

You can see the full list of options by using:
inkscape -?
Or a concise list with:
inkscape --usage
The command line options used:
-z No GUI
-w Width
-h Height
-e Export file name

Example
inkscape -z -w 1024 -h 1024 picture.svg -e picture.png
WARNING: unknown type: svg:foreignObject
WARNING: unknown type: i:pgf
Background RRGGBBAA: ffffff00
Area 0:0:85.039:85.039 exported to 1024 x 1024 pixels (1155.99 dpi)
Bitmap saved as: picture.png

References

https://inkscape.org/
https://en.wikipedia.org/wiki/Inkscape
https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
https://inkscape.org/doc/inkscape-man.html


Monday, 25 May 2020

Setting a default screen size for a headless Raspberry PI

I have a few Raspberry Pis, and most of them are run "headless" (without keyboard or display).

Now the default screen size for a headless PI is what used to be called VGA and has a resolution of 640 x 480. This was state of the art in the 'nineties, but unfortunately the majority of software expects a larger display. This means that programs tend to fall off the available screen size, in some case losing the close button as well.

You can set the display resolution via the Raspberry Pi configuration tool or via the command line using raspi-config. The problem is that there is no guarantee that your chosen display mode will then work with your monitor.

This particuklar resolution (720p) works okay on monitors and via VNC. Other options are available.

This can be set by editing the config.txt file

sudo nano /boot/config.txt

Scroll down to this section (the highlighted text areas will probably read VGA and 1 respectively). Change the mode to 4 and the resolution description - that is for your information later).
# uncomment to force a specific HDMI mode (this will force 720p resolution)hdmi_group=1hdmi_mode=4
Use Control X, Y to save and accept the default file name to save the changes.

Reboot your machine and you should have a much more workable graphics screen on VNC.

References

Sunday, 24 May 2020

Micro:bit Beacon - part 1: the beacon

One of the features of the Micro:Bit is its Bluetooth compatible radio.

Unfortunately, it is not available in Micropython due to the size of the Bluetooth software stack.

Whatt is available is a Radio object which uses the radio hardware to communicate between Micro:bits.

There is a neat program on the documentation site called Firefly. This has groups of Micro:bits communicating with each other.

Now this project uses the "flash" technique from the Firefly project.

from microbit import *
import radio
import utime
import machine

# "Flash" effect from the Firefly program
#https://microbit-micropython.readthedocs.io/en/latest/tutorials/radio.html?highlight=Firefly#fireflies
flash = [Image().invert()*(i/9) for i in range(9, -1, -1)]

# Obtain the machine id
machineID=machine.unique_id()

# Flash the display over a half second 
# and send the machine ID every second.
while True:
        display.show(flash, delay=50, wait=False)
        radio.on()
        radio.send(str(machineID))
        sleep(500)
        radio.off()
        sleep(500)


Sunday, 3 May 2020

Chaos - and the Headless Raspberry Pi

Cryptography is a voracious consumer of randomness, and computers depend on cryptography for security. Most operating systems harvest this randomness (under the name of entropy) from various pieces of hardware, quite often from mouse movement or keyboard operation. This is fine when the computer has a keyboard and/or mouse, but what happens when the computer is running headless?

Raspberry Pis quite often run headless, and remote operation using products like RealVNC encrypt the communication between the server and the client. To maintain security, no connection can be made until there is sufficient stored entropy. This can lead to long delays between switching the computer on and being able to connect to it remotely.

The package haveged is available in Debian based systems (including Raspbian and Ubuntu) and fills the entropy pool when the supply falls below a set value. This will speed up the start up of RealVNC.

Installing haveged

sudo apt-get install haveged

References