Snekboard

by Keith Packard

An open-hardware python microcontroller for LEGO®

View all updates Feb 25, 2020

Now Running CircuitPython!

by Keith P

CircuitPython for Snekboard completely fills the SoC on-chip flash, so we have to use an external flash part for Python source code and libraries. The latest Snekboard prototype uses a different flash part to save some space, but I couldn’t get the part from Mouser as they were out of stock. I received them yesterday and got one soldered onto a board this evening, so the current prototypes can now run CircuitPython!

Feel the Power

It’s clear that Adafruit has invested a ton of time and energy into CircuitPython — there are piles of supported boards, lots of example code, and a whole bunch of libraries that take full advantage of these little computers.

If you’ve read any of the articles about Snek on Snekboard, you’ll notice how simple it is to use. The same isn’t as true for CircuitPython. As with Arduino, you need to tell CircuitPython how you want to use each pin for before you can do anything.

Mu-editor has built-in support for CircuitPython boards, so that’s what I’m using to experiment with Snekboard. You can open up a serial window and type directly into the REPL.

Turn on a Motor

The first thing I wanted to do was make sure I could drive the motors. The native CircuitPython motor controller library expects to drive a controller that takes two PWM inputs; the motor controllers on Snekboard take one PWM (for power) and one digital pin (for direction). So, we get to roll our own here. As a trivial first test, let’s just turn a motor on full speed by treating the PWM output as a digital pin. I’ve got a motor connected to M2, which uses pins POWER2 and DIR2 in CircuitPython

import board
import digitalio

power = digitalio.DigitalInOut(board.POWER2)
power.direction = digitalio.Direction.OUTPUT
power.value = True

Now let’s try varying the speed. First we have to stop treating the power pin as digital:

power.deinit()

Now we can use the pulseio library to control the power output:

power = pulseio.PWMOut(board.POWER2)
power.duty_cyle = 32767

Finally, we can play with the direction pin. That’s a digital output:

direct = digitalio.DigitalInOut(board.DIR2)
direct.direction = digitalio.Direction.OUTPUT
direct.value = True

Snekboard is Already Supported Upstream

One of the best things about CircuitPython is how willing Adafruit has been to take my patches and integrate support for Snekboard into their regular release cycle. I’m running 5.0.0-beta.5 on my boards, downloaded from the Snekboard page at CircuitPython.org

Sample Code

Here’s the code that was used to make the video above.

#
# Copyright © 2020 Keith Packard <keithp@keithp.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#

import board
import neopixel_write
import time
import digitalio
import pulseio
import analogio
import random


def set_power(motor, power):
    """Set the motor direction and power. power ranges from -1 to 1"""
    if power >= 0:
    motor[1].value = True
    else:
    motor[1].value = False
    power = -power
    motor[0].duty_cycle = min(max(power * 65535, 0), 65535)


def make_motor(pwm_pin, dir_pin):
    """Create a motor. pwm_pin is the board element which is the PWM pin.
    dir_pin is the board element which is the direction pin"""
    pwm = pulseio.PWMOut(pwm_pin)
    dir = digitalio.DigitalInOut(dir_pin)
    dir.direction = digitalio.Direction.OUTPUT
    return (pwm, dir)


def make_sensor(sensor_pin):
    """Set up an analog sensor input"""
    return analogio.AnalogIn(sensor_pin)


def read(sensor):
    return sensor.value / 65535


left_motor = make_motor(board.POWER3, board.DIR3)
right_motor = make_motor(board.POWER2, board.DIR2)
front = make_sensor(board.A1)
back = make_sensor(board.A7)


neo = digitalio.DigitalInOut(board.NEOPIXEL)
neo.direction = digitalio.Direction.OUTPUT


def set_colors(r, g, b):
    """Set both neopixels to the specified color.
    r, g, b range from 0 to 1"""
    global neo
    r = int(r * 255)
    g = int(g * 255)
    b = int(b * 255)
    pixels = bytearray([g, r, b, g, r, b])
    neopixel_write.neopixel_write(neo, pixels)

def spin_random(d):
    set_power(left_motor, d)
    set_power(right_motor, d)
    set_colors(0, 0, 0.25)
    time.sleep(1 + random.randrange(200) / 200)

def bumper():
    while True:
    while read(front) < 0.5:
        pass
    set_power(left_motor, -1)
    set_power(right_motor, 1)
    time.sleep(1)
    spin_random(1)
    set_power(left_motor, -1)
    set_power(right_motor, 1)
    set_colors(0.25, 0, 0)
    while read(back) < 0.5:
        pass
    set_power(left_motor, 1)
    set_power(right_motor, -1)
    time.sleep(1)
    spin_random(-1)
    set_power(left_motor, 1)
    set_power(right_motor, -1)
    set_colors(0, 0.25, 0)

bumper()

About the Author

Keith P

keith-packard  ·   Portland, OR


$7,405 raised

of $4,000 goal

185% Funded! Order Below

Product Choices

$79

Snekboard

One Snekboard and one 3.7 V, 900 mAh LiPo battery


$20

Snekboard Cable Set

Four motor cables and four GPIO cables (pins to bare wires)


$40

Snekboard Sensor Kit

Two QTR-MD-01A reflectance sensors and two GP2Y0A41SK0F distance sensors. All four sensors are Snekboard-ready with cables pre-soldered. Provides everything you need to follow along with existing Snekboard tutorials.

Credits

Keith Packard

Free Software / Free Hardware developer doing robotics instruction, amateur rocketry and RISC-V processor design.


Keith Packard


OSH Park

Recommended

PCB Manufacturer

Digi-Key

Recommended

Components & Hardware Sourcing

Mouser Electronics

Recommended

Components & Hardware Sourcing

Subscribe to the Crowd Supply newsletter, highlighting the latest creators and projects: