Pages

Sunday, 26 April 2020

Virtual Pi Wars 2020 was outstanding!

This year Pi Wars went virtual, and it was a huge success.

Mike Horne did a superb job as compère, and the Robot videos were wonderful: always informative, often amusing and of very high quality.

Over the next few days we'll have a chance to vote. It's going to be a very difficult choice!

The Teams presented creative and individual solutions, but some common themes emerged. Lots of teams made use of simulations. Some used custom software based around standard libraries; others were based on specialised open source frameworks like VTK.

Most Robots were programmed in Python, but several used Pi controllers with peripheral Arduino nanos or teensies programmed in C.

Some teams used ToF (Time of flight) sensors for distance sensing and SLAM (Simultaneous location mapping and mapping). A growing number of entrants used OpenCV or plan to use it next year.

Many Teams share their software and designs. I'm looking forward to exploring several of the projects on GitHub as I look through the videos over the next day or so.

Over 300 people watched the virtual presentation. They  savoured three hours of excellent virus-free entertainment. Thanks to everyone involved, and special thanks to Mike Horne and Tim Richardson for turning that bright idea all those years ago into a wonderful, enduring institution.

Tuesday, 7 April 2020

The micro:bit is talking to theVL53L0X ToF sensors!

This chip is no more :(
This morning I got my Arduino sensor driver talking to a micro:bit using SPI.

The Arduino Uno runs at 5 volts, and the micro:bit works at 3v3, so I used a level shifter to connect the two.

My first attempt failed disastrously.

The level shifter I used was based on the TI TXB0108.
I managed to connect the 5v power and inputs to the 3v3 side, and I fear the magic smoke has left the chip.

It's a shame, as the board was my first attempt at soldering SMD devices. It's been sitting unused in my bits box for a few years, though, so it's not the end of the world.

Fortunately I had an Adafruit level shifter breakout based on the same IC. It's well laid out with very clear pin markings and I managed to connect it correctly.

The replacement worked perfectly and the micro:bit MicroPython code was very straightforward. I've listed it below, and it's with the other code on GitHub.

from microbit import *
import struct
from time import sleep

SENSORS = 2

def spi_read(sensor):
    pin16.write_digital(0)  # Chip select
    ibuffer = struct.pack('<B', sensor)
    spi.write(ibuffer)
    result = spi.read(1)
    pin16.write_digital(1)  # Chip select off
    return result

spi.init(baudrate=100000)
while True:
    for i in [0, 1]:
        print(i, ord(spi_read(i)))
        sleep(0.1)


The technology is working. The next step is to build a compact version for Anastasia. I'll report on progress.

Monday, 6 April 2020

Read distances from up to 8 VL53L0X sensors via SPI

I'v now got my two-Arduino version of a multiiple ToF sensor LiDAR working.

I have only tested it with two sensors; I'll add one more later, and report, but the code should work with more.

I'm a little hesitant about that claim. The Slave Arduino code has little spare memory but I've tried to  reduce requirements to a minimum. I have more VL53L0X sensors on order, and I am hoping I can handle up to eight.

That would allow a robot to get a good sense of the closest obstacles.

The Slave code uses an SPI interrupt routine modified from Nick Gammon's excellent example.

The code that configures and then reads from the ToF sensors is a complete rewrite of Adafruit's example code for dual VL53L0X sensors.

I'm no expert at C programming, so if you can see improvements (or bugs), let me know!

The code is on GitHub, along with some minimal documentation.

The next step will be go get the Arduino slave working with a micro:bit master; then I'll need to work out how to install hardware and software on Anastasia to help her avoid collisions.

Here's the core code for the slave:

const byte MAX_OK = 253; // largest acceptable range / 2
const byte NO_SUCH_SENSOR = 255;
const byte INVALID_READING = 254;
const int SENSORS = 2; // two sensors for now
// addresses we will assign to sensors
byte address[SENSORS];
// pins to shutdown
byte shutdown_pin[SENSORS];
// scaled distances
byte distance[SENSORS];

// create array of sensors
Adafruit_VL53L0X lox[SENSORS];
VL53L0X_RangingMeasurementData_t measure;

void setID() {

  int i;
  for (i=0; i < SENSORS; i++) {
    shutdown_pin[i] = i + 2; // pins go from 2 to SENSORS + 2
    address[i] = (byte) 0x30 + i; // addresses go from 0x30 to 0x37
    pinMode(shutdown_pin[i], OUTPUT);
    digitalWrite(shutdown_pin[i], LOW);
  }
  delay(10);
  for (i=0; i < SENSORS; i++) {
    digitalWrite(shutdown_pin[i], HIGH);
    delay(10);
    bool result = lox[i].begin(address[i]);
    if(!result) {
      while(1);  // loop forever if the setup didn't work
    }
  }
  delay(10);
}

void readSensors() {
  for (int i=0; i < SENSORS; i++) {
    float range;
    lox[1].rangingTest(&measure, false);
    if (measure.RangeStatus != 4) {
      range = measure.RangeMilliMeter;
      distance[i] = min(range / 2, MAX_OK);
    } else {
      distance[i] = INVALID_READING;
    }

  }
}

void setup() {
  // turn on SPI in slave mode
  SPCR |= bit (SPE);

  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  setID();
  SPI.attachInterrupt();
}

// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;  // grab byte from SPI Data Register
SPDR = c < SENSORS ? distance[c] : NO_SUCH_SENSOR; // return scaled distance or error code
}  // end of interrupt routine SPI_STC_vect


void loop() {
  readSensors();
  delay(100); // read all sensors every 1/10 second
}