Skip navigation
> RoadTest Reviews

All-in-one Robotics Board + micro:bit - Review

Scoring

Product Performed to Expectations: 10
Specifications were sufficient to design with: 10
Demo Software was of good quality: 6
Product was easy to use: 10
Support materials were available: 10
The price to performance ratio was good: 10
TotalScore: 56 / 60
  • RoadTest: All-in-one Robotics Board + micro:bit
  • Evaluation Type: Development Boards & Tools
  • Was everything in the box required?: Yes
  • Comparable Products/Other parts you considered: This is the only motor controller I've tried for the micro:bit
  • What were the biggest problems encountered?: Bugs in the Demo software. They were easy to fix but shouldn't have been there.

  • Detailed Review:

    Table of contents

     

    Introduction

    First, I want to thank Kitronik and Element14 for selecting me to test the board.  I had fun and learned a lot testing the board.

     

    The All-in-one Robotics Board for BBC micro:bit enables the BBC micro:bit to drive 4 motors (or 2 stepper motors )

    and 8 servos.  The only I/O used by the board on the micro:bit is the I2C port so all the micro:bit's expansion pins are available

    for other I/O devices.  The board has a 3.3V regulator to power the BBC micro:bit.

     

    The heart of the board is an NXP PCA9685 16-channel, 12-bit PWM I2C LED controller.  The other chips on the board are two dual H-Bridge drivers for the 4 DC or 2 stepper motors and 2 other chips which I assume are drivers for the 8 servo outputs.  The drivers are controlled by the PWM outputs: one for each servo and two for each H-Bridge.  It's a clever way to make a low cost controller that can control three types of motors.

     

    Goals for this review:

    • Verify the signals for different types of motors
    • Use the board with the micro:bit's other I/O
    • Build a robot!
    • Learn MicroPython!
    • Have fun while learning new things.

     

    What's in the box?

    For the RoadTest, element14 provided at the All-in-one Robotics Board and a BBC micro:bit

    Contents of RoadTest box: Robotics board and micro:bit

     

     

    Kitronik All-in-one Robotics Board

    Here is the unpacked  Kitronik All-in-one Robotics Board

     

    Documentation

    None in the box but the Kitronik webpage for the board (5641-all-in-one-robotics-board-for-bbc-microbit.html) contains what you need to get started:

    • Datasheet
    • Link to MicroPython demo file on GitHub
    • Short video showing All-in-one Robotics board in action

     

    What’s missing?

    Schematic

     

    Kitronik support

    The product page also has a Q&A section. I posted a question to see if I can have the micro:bit plugged into USB while the robotics board is powered from an external supply and they quickly replied that I can.

     

    Software provided

    From GitHub, you can download a zip file containing:

    • License
    • Readme.md describing the calls
    • robotics.py
    • kitronik-reference-file-robotics-TOO-LARGE.py

     

    The version I downloaded to test was commited on Oct 11, 2018.

    The robotics.py and the TOO-LARGE files contain the same code but the comments have been removed in robotics.py to save space in the micro:bit.

     

    Robotics.py defines a class named KintronikRoboticsBoard that implements methods for stepper, regular DC and servo motors.  The file also contains code that will exercise the methods if the file is loaded as the main file on the micro:bit.

     

    MicroPython

    After applying for this Roadtest, I read two books on MicroPython: Programming with MicroPython by Nicholas Tollervery and Make: Getting Started with the micro:bit by Wolfram Donat.

    I was very impressed with MicroPython. I expected some sort of ‘Tiny Python’ that would be pretty much coding in C with Python-like syntax. MicroPython is a very full implementation of Python. We teach a Python workshop for beginning programmers and it will be very easy for those students to use those skills for Arduino like projects.

    There are a couple ways to create MicroPython code for the micro:bit

    1. Use a cloud based python editor and download a hex file to transfer to the micro:bit. ( http://microbit.org )
    2. Use the stand alone Mu-editor, a simple Python editor for beginner programmers. ( http://codewith.mu )
    3. Use your normal Python editor and some tools to create the hex file. I didn’t try this.

    I tried #1 and  #2 and used the app for my testing . The mu-editor app was easy to install and use. They kept it to the basic functionality needed making it easy to understand. It supports ‘minifying’ your code which strips out comments and extra spaces when creating the hex file to save memory space in the micro:bit. I later learned that saving space is very important when using MicroPython on the micro:bit.

    Mu-editor is very particular about how it wants spaces around comments, commas and parenthesis and limits the lines to 79 characters. I found this annoying but assume it’s there to teach beginning programmers to be consistent.

     

    screenshot of Mu editor

    Screenshot of mu-editor which has definite opinions about whitespace.

     

    Tests to be performed

    Testing will be done in three phases: Verifying the motor signals, verifying the ability to use the micro:bit I/O and building a robot.

    1. Verify the motor signals using a scope
      1. Download demo SW to micro:bit
      2. Test the stepper motor signals
      3. Test the DC motor signals
      4. Test the servo motor signals
    2. Verify the ability to use the micro:bit I/O
      1. Add header pins for the micro:bit I/O lines
      2. Breadboard an I2C and other device
      3. Test with and without the Robotics board
    3. Build a robot!
      1. TBD

     

    Test setup

    • Mu 1.0.2 running on a Macintosh to edit and download code
    • Digilent Analog Discovery and Waveforms 2015 SW to measure motor signals
    • I will start with the robotics.py file from Kitronik and modify it as needed.

    Test setup showing measuring motor signals

    Test setup showing the Analog Discovery hooked up to the Kitronik All-in-one Robotics Board and measuring the DC motor signals.

     

    Test 1: Verify the motor signals using a scope

     

    Test 1-A: Download demo SW to micro:bit

    This test will load the robotic.py into mu-editor and then download it into the micro:bit. The micro:bit will then be plugged into and powered by the Kitronik board
    What I'm looking for:

    • The code should check and download with no errors and run with no errors when plugged into the robot board.

    What I observed:

    • When I checked the code with mu-editor's check button there were many errors about spacing and line length (see the earliar picture for examples). These were easy to fix.
    • More seriously, there were references to an instance variable stepStage as stepStage instead of self.stepStage. This causes the code to fail on the micro:bit. It was easy to fix after examining the code but should not have been there.

    Screenshot showing robotics.py errors

    Screenshot showing errors in Mu

     

    Test 1-B: Test stepper motor signals

    This test will exercise the stepper motor output Stepper1  using calls in the robotics.py code to move it 100 steps.

     

         theBoard.stepperMotorTurnSteps(theBoard, "Stepper1", "forward", 100)

     

    What I'm looking for and why:

    • Two square waves 90° out of phase
      The phase shift, Motor1 preceeding or trailing Motor2 determines if the stepper movers forwards or backwards.
    • A voltage swing of 2 times the supply voltage
      The stepper motor is being controlled by an H-bridge which switches the polarity of the motor signal. This will look like a negative voltage on the scope when the polarity is reversed.
    • A period of around 80 ms. There are 4 stages to the stepper control. At each stage one motor switches polarity. Each stage is one 50Hz PWM cycle.
    • Dead Time Insertion when a signal switches polarity DTI, or Dead Time Insertion, is a brief period of turning off the signal for one polarity before turing on the signal for the reverse polarity. This prevents both polarities being active at the same time which shorts the power supply in a sometimes spectacular fashion.

     

    What I observed:

    • The phase relationship is as expected but the square wave isn't as regular as expected.
    • The voltage swing is as expected but sometimes the signal is at 0V indicating the H-bridge is totally off.
    • The period is sometimes longer than 80ms and a stage gets extended but I did not observe a stage being too short or skipped.
    • Dead Time is being inserted but was also being inserted on when there was no polarity change.

     

    All-in-one Robitis=cs Board Stepper Signals

    Screen capture from Stepper Motor test.

    Channel 1 (Yellow) shows motor1, which would hook up to Coil A of a 4 wire bipolar stepper motor.

    Channel 2 (Blue) shows motor2, which would hook up to Coil B of a 4 wire bipolar stepper motor.

     

    All-in-one Robitics Board DTI insertion

    Screen capture zooming in on Dead Time Insertion.

    Both motors are off (0V) during the last 500 microseconds of the PWM period.

    Motor1 (Yellow) did not need dead time since it was not reversing polarity.

    Motor2 (Blue) reversed polarity and needed the dead time.

     

    Analysis of results:

    The PWM chip has it's own clock which is not synchronized to the micro:bit. If the micro:bit hasn't updted the PWM value by the end of the period, the PWM chip will reload the last value extending the stage by 20ms. Reversing the polarity requires turning on one polarity by setting it's PWM value from 0% to 100% and then setting the other polarity's PWM from 100% to 0%. Sometimes the PWM reload happens between the two changes leaving the H-bridge in braking mode for 20ms.

    Dead Time Insertion is done by never allowing a 100% duty cycle. 100% motor speed is mapped to 4000 instead of 4095 on a 12 bit PWM leaving about 460 microseconds of dead time at the end of each PWM period. This is why we see DTI even when the polarity isn't changing.

    Is it a problem?

    I spent a while pondering this  and thinking of a way to synchronize the micro:bit code with the PWM updates.  I also concluded it's probably harmless when the micro:bit code is late updating the PWM value since it just extends the last step.  Likewise the unneeded DTI insertions should be harmless since the H-bridge will be in coasting mode during this time.

     

    Test 1-C: Test DC motor signals

    This test will exercise the DC motor outputs Motor3 and Motor4 using calls in the robotics.py code to set Motor3 to 10% in one direction and Motor4 to 100% in the other direction:

     

    theBoard.motorOn(theBoard, 3, "forward", 10)

    theBoard.motorOn(theBoard, 4, "reverse", 100)

     

    What I'm looking for and why:

    • Motor3 should have a 10% duty cycle.
      Motor3 should be at 0V for 90% of the period.
    • Motor4 should have a 100% duty cycle.
      We won't see 100% because of DTI
    • Polarity reversed between motor3 and motor4.
      One direction will show as a positive voltage on the scope and the other will show as a negative voltage.
    • Dead Time Insertion.
      Like the stepper motor, Dead Time is inserted by having a max duty cycle of 4000/4095
    • PWM period of 20ms.
      All the PWMs are running at 50 Hz.

     

    What I observed:

    • Motor3 shows about a 10% duty cycle.
      Note that the -6V for 10% of the time is the motor on in the forward direction.
    • Motor4 shows an almost 100% duty cycle.
      It has +6V for 97.5% of the period and the rest is DTI.
    • The polarity is reversed between motor3 and motor4.
    • Dead Time is inserted.
      Just like the stepper motor with DTI even if there is no change.
    • PWM period is about 20ms.

     

    Screenshot showing DC motor test

    Screen capture from DC Motor test.

    Channel 1 (Yellow) shows motor3. A negative voltage indicates the motor active in the forward direction.

    Channel 2 (Blue) shows motor3. A positive voltage indicates the motor active in the reverse direction.

     

    Analysis of results:

    Everything behaved as expected.

     

    Test 1-D: Test servo motor signals

    This test will exercise the servo motor outputs SV1 - SV8 using calls in the robotics.py code to set them at 0, 90 or 180 degrees:

     

    theBoard.servoWrite(theBoard, 1, 180)
    theBoard.servoWrite(theBoard, 2, 90)
    theBoard.servoWrite(theBoard, 3, 0)
    theBoard.servoWrite(theBoard, 4, 180)
    theBoard.servoWrite(theBoard, 5, 90)
    theBoard.servoWrite(theBoard, 6, 0)
    theBoard.servoWrite(theBoard, 7, 180)
    theBoard.servoWrite(theBoard, 8, 90)

     

    What I'm looking for and why:

    • 180° gives a PWM signal that is high for 2.5ms each period.
    • 90° gives a PWM signal that is high for 1.5ms each period.
    • 0° gives a PWM signal that is high for 0.5ms each period. These are the common values for the full range of motion in an actuator servo. Some servos have less range in motion and/or use a shorter range of pulses.
    • PWM rate of around 50Hz.
      This is the commonly used value for servo motors.

     

    What I observed:

    • the 180° servos are 2ms instead of 2.5ms
    • The 90° servos are 1ms instead of 1.5ms
    • The 0° servos have no pulse instead of 0.5ms
    • The PWM period is 21ms or 46.7Hz instead 50Hz (close enough)

    Screenshot showing servo motor test

    Screen capture from Servo Motor test.

     

    Analysis of results:

    All the pulses are about 0.5ms short.

     

    The code in robotics.py to calculate the PWM value is:

    PWMVal = (degrees * 100 * self.SERVO_MULTIPLIER) / (10000 + self.SERVO_ZERO_OFFSET)

    if degrees = 0, PWMVal will be 0 which explains why we had no pulse. SERVO_ZERO_OFFSET should be added after the division.

    PWMVal = ((degrees * 100 * self.SERVO_MULTIPLIER) / 10000) + self.SERVO_ZERO_OFFSET

    Changing the code will also fix the 90° and 180° signals.

    Screenshot showing servo motor test after fixing code

    Screen capture from Servo Motor test after changing the code.

    All the pulses and the PWM period are now pretty close (about 5% long).

     

    Why are we about 5% off?

    The PCA9685 PWM controller chip  has an internal 25MHZ oscillator. The datasheet doesn't specify a tolerance for the clock and just says: '25 MHz typical internal oscillator requires no external components'. For LED applications, the accuracy probably isn't important as long as it's fast.  This is a possible source of the difference in timing

    The PWM rate is set by setting a prescale register in the PCA9685. Here is the code from robotics.py:

     

    buf[0] = self.PRESCALE_REG
    buf[1] = 0x85 #50Hz
    i2c.write(self.chipAddress, buf, False)

     

    The equation from the datasheet for calculating the prescale value is: prescale_value = round(osc_clock/(4096*update_rate))-1

    or, we can rearrange it to:
    update_rate = osc_clock/(4096*(prescale_value + 1))

    If osc_clock = 25MHz and the prescale_value = 0x85, the update rate will be 45.55Hz instead of 50Hz.

    The writer was probably adjusting the prescale to make the refresh rate 50Hz on their board. I'll leave it alone for now unless it causes a problem.

     

    Now that we have tested and fixed any problems with the motor signals and demo software, we can move on to testing using the micro:bit I/O.

     

    Phase 2: Test the ability to use the micro:bit I/O

    The only micro:bit  I/O pin used by the All-in-one Robotics board is I2C so all of the micro:bit's I/O is available except for the I2C address used by the robotics board.

     

    To test this, I will need to:

    1. Solder header pins to the robotics board.
    2. Breadboard an I2C device (TMP102 temperature sensor) and a NeoPixel strip
    3. Test them with and without the robotics board.
    4. Add the code to to the robotics.py code and test it with the robotics board.

     

    Soldering header pins to the robotics board was straightforward.

    However, the webpage for the board says:

    If using the breakout pads at the back of the board, you will also need Soldering iron, solder and wire cutters.

    It should also say that you need header pins.

    Header pining soldered to robotics board

    Robotics board with micro:bit I/O headers added

     

    I wrote a program to read and display the temperature while scrolling the LEDs on the NeoPixel strip.  I tested the breadboard with an AdaFruit Dragontail breakout board with no problems.

     

    I then added the robotics.py code to test it with the robotics board.  My RoadTest then ran into a couple of speed bumps.

     

    The combined code was too large to load at startup and the micro:bit failed with a memory error at startup.  I tried keeping the KitronikRoboticsBoard class in a separate file but it still failed.  I'm not using stepper motors so I removed the stepper motor calls for now.  I'll talk more about code space later when making a robot.

     

    After removing the stepper code, the code loaded with no problems but would usually fail after a few seconds with an I2C write error.  This was unexpected since it ran with no problems without the robotics board!

     

    I put a scope on the I2C line and saw that it was over 1/3 V when a 0 was on the bus.  The micro:bit can only source or sink a small amount of current.  The micro:bit has 4.7KΩ pull-ups on the on the I2C line, the robotics board appears to have 10KΩ pull-ups and the TMP102Ω board has 1KΩ pull-ups.  These three in parallel are about 760Ω which is probably too much current for the micro:bit pin.  The micro:bit can have three pins configured for high current (5ma) which I assume are used for the led array.

     

    I changed my code to use an MCP9808 temperature sensor board that has 10KΩ pull-ups and everything worked fine.  A 0 on the I2C line measured 0V on the scope.

    The final test:

    Display a happy face on the LED array

    Turns off the servos

    Turns on three servos to 180º, 90º, 0º

    Reads temperature over I2C

    Displays temperature on LED array

    Scrolls a NeoPixel on the strip

    I'm only lighting one NeoPixel at a time to keep the current under the 90ma spec of the robotics board 3V pin.

    Robotics board with MCP9808 I/O test

    Picture of the I/O test with servo outputs, I2C temperature sensor and a NeoPixel strip.

     

    Here's a movie of the test in action.

     

    We've got motor control and can use other devices so we're ready to build a robot!

     

    Test 3: Build and test a robot

    For my robot, I'm going to use a Makeblock Starter Robot I bought at the flea market several months ago for $5.  It was missing a bunch of pieces but all I need it the chassis, motors and battery pack.

     

    Makeblock starter robot chassis

    Testing the robot motors with the robotics board.

     

    My robot will have the following:

    • 2 DC motors driven by the robotics board
    • A US-100 ultrasonic distance sensor read with micro:bit's serial port
    • An 8 LED neopixel strip used to indicate the distance to the nearest obstacle.

     

    Completed robot from the front

     

    Completed robot from the side

    My finished robot

     

    My tale of woe with memory issues

    My first pass at the code that loaded the support for the robotics board, US-100 and NeoPixels but didn't do much with them got memory errors when loading.

    Failing this early usually means there wasn't enough space to load the .py file and convert it to byte codes.

    I then simplified the NeoPixel animation and it loaded but got a memory error when instantiating one of the classes.

    I then gave up on the NeoPixels, which probably allocate all sorts of buffers, and removed the code using them.

    The code successfully loaded and drove the robot in a straight line but wasn't finished.

    I added some code to turn the robot when an obstacle is detected but ran out of memory again.

    I removed the unneeded servo code from the Kitronik class and was up, running and avoiding obstacles.

     

    Hooray, but I was disappointed to lose my blinking lights!

     

    I dug into the Kitronik code and the PCA9685 data sheet and was able to save space by combining routines and using features in the chip like auto increment and writing to all PWMs with one write.   This saved enough space to use the NeoPixels.  Aside from having a couple of bugs (which it shouldn't), the Demo code did it's job: showing me an easy to follow example of how to talk to the board.

     

    My robot doing a victory lap

     

    Conclusions

    I like the board and would recommend it to my students.  With one board you can control three types of motors for a reasonable price and it provides a nice low cost solution for STEM and art projects.  Memory is limited for MicroPython but I'm still amazed the we can run MicroPython at all.

     

    Suggested improvements:

    • Add a schematic and theory of operation to the documentation.
    • Fix the bugs in the Demo code
    • Make it easy to add a power switch.  A place to add a couple header pins with a cuttable trace shorting them in series with the power would be convenient.

Comments

Also Enrolling

Enrollment Closes: Aug 13 
Enroll
Enrollment Closes: Sep 15 
Enroll
Enrollment Closes: Sep 8 
Enroll
Enrollment Closes: Aug 21 
Enroll
Enrollment Closes: Aug 28 
Enroll
Enrollment Closes: Aug 25 
Enroll
Enrollment Closes: Aug 18 
Enroll
Enrollment Closes: Aug 18 
Enroll
Enrollment Closes: Aug 17 
Enroll