Code with CircuitPython

Plug your Circuit Playground Bluefruit board into your computer with a known good USB A to USB micro B cable (good = had both data & power wires in it). 

Do not plug your USB cable into the Crickit - that port is rarely used, use the one on the Circuit Playground Bluetooth board only).

Your computer should recognize the Circuit Playground Bluefruit as a new flash drive named CIRCUITPY. If you see a new drive named CPLAYBTBOOT then press reset. If still no CIRCUITPY drive, go back to the CircuitPython on the Circuit Playground Bluefruit page to install CircuitPython again.

Using your computer's operating system, make a directory named lib in the main (root) directory of the CIRCUITPY drive if it is not already present. This will hold some code libraries for the project.

Libraries

Now we'll install the libraries that we need to run the rover code on the Circuit Playground Express with Crickit.

Click this link to got to the circuitpython.org Libraries page. Download the latest version of the Bundle library .zip file that matches the version of CircuitPython you're using on the board.

Uncompress the .zip file and then copy the following directories and .mpy files to the lib directory of the CIRCUITPY drive:

  • adafruit_ble
  • adafruit_bluefruit_connect
  • adafruit_bus_device
  • adafruit_motor
  • adafruit_seesaw
  • adafruit_crickit.mpy
  • neopixel.mpy

Your lib directory on the CIRCUITPY drive should be similar to the picture above.

The Mu Editor

Adafruit recommends using the free program Mu to edit your CircuitPython programs and save them on your Circuit Playground Bluefruit. You can use any text editor, but Mu has some handy features.

See this page on the Circuit Playground Bluefruit guide on the steps used to install Mu.

Turtle Rover Code

The event we've all been waiting for! The actual CircuitPython code for our rover!

Copy this code and then paste it into a new document in Mu, then save it to your CIRCUITPY drive as code.py

# Circuit Playground Bluefruit Rover
# Use with the Adafruit BlueFruit LE Connect app
# Works with CircuitPython 5.0.0-beta.0 and later
# running on an nRF52840 CPB board and Crickit

import time
import board
import digitalio
import neopixel
from adafruit_crickit import crickit

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

from adafruit_bluefruit_connect.packet import Packet
# Only the packet classes that are imported will be known to Packet.
from adafruit_bluefruit_connect.button_packet import ButtonPacket
from adafruit_bluefruit_connect.color_packet import ColorPacket

# Prep the status LED on the CPB
red_led = digitalio.DigitalInOut(board.D13)
red_led.direction = digitalio.Direction.OUTPUT

ble = BLERadio()
uart_service = UARTService()
advertisement = ProvideServicesAdvertisement(uart_service)

# motor setup
motor_1 = crickit.dc_motor_1
motor_2 = crickit.dc_motor_2

FWD = 0.25
REV = -0.25

neopixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=0.1)
RED = (200, 0, 0)
GREEN = (0, 200, 0)
BLUE = (0, 0, 200)
PURPLE = (120, 0, 160)
YELLOW = (100, 100, 0)
AQUA = (0, 100, 100)
BLACK = (0, 0, 0)
color = PURPLE  # current NeoPixel color
neopixels.fill(color)

print("BLE Turtle Rover")
print("Use Adafruit Bluefruit app to connect")
while True:
    neopixels[0] = BLACK
    neopixels.show()
    ble.start_advertising(advertisement)
    while not ble.connected:
        # Wait for a connection.
        pass
    # set a pixel blue when connected
    neopixels[0] = BLUE
    neopixels.show()
    while ble.connected:
        if uart_service.in_waiting:
            # Packet is arriving.
            red_led.value = False  # turn off red LED
            packet = Packet.from_stream(uart_service)
            if isinstance(packet, ColorPacket):
                # Change the color.
                color = packet.color
                neopixels.fill(color)

            # do this when buttons are pressed
            if isinstance(packet, ButtonPacket) and packet.pressed:
                red_led.value = True  # blink to show packet has been received
                if packet.button == ButtonPacket.UP:
                    neopixels.fill(color)
                    motor_1.throttle = FWD
                    motor_2.throttle = FWD
                elif packet.button == ButtonPacket.DOWN:
                    neopixels.fill(color)
                    motor_1.throttle = REV
                    motor_2.throttle = REV
                elif packet.button == ButtonPacket.RIGHT:
                    color = YELLOW
                    neopixels.fill(color)
                    motor_2.throttle = 0
                    motor_1.throttle = FWD
                elif packet.button == ButtonPacket.LEFT:
                    color = YELLOW
                    neopixels.fill(color)
                    motor_2.throttle = FWD
                    motor_1.throttle = 0
                elif packet.button == ButtonPacket.BUTTON_1:
                    neopixels.fill(RED)
                    motor_1.throttle = 0.0
                    motor_2.throttle = 0.0
                    time.sleep(0.5)
                    neopixels.fill(color)
                elif packet.button == ButtonPacket.BUTTON_2:
                    color = GREEN
                    neopixels.fill(color)
                elif packet.button == ButtonPacket.BUTTON_3:
                    color = BLUE
                    neopixels.fill(color)
                elif packet.button == ButtonPacket.BUTTON_4:
                    color = PURPLE
                    neopixels.fill(color)
            # do this when some buttons are released
            elif isinstance(packet, ButtonPacket) and not packet.pressed:
                if packet.button == ButtonPacket.UP:
                    neopixels.fill(RED)
                    motor_1.throttle = 0
                    motor_2.throttle = 0
                if packet.button == ButtonPacket.DOWN:
                    neopixels.fill(RED)
                    motor_1.throttle = 0
                    motor_2.throttle = 0
                if packet.button == ButtonPacket.RIGHT:
                    neopixels.fill(RED)
                    motor_1.throttle = 0
                    motor_2.throttle = 0
                if packet.button == ButtonPacket.LEFT:
                    neopixels.fill(RED)
                    motor_1.throttle = 0
                    motor_2.throttle = 0

How the Code Works

The first part of the program sets up a UARTServer, which is a BLE service that wirelessly sends streams of characters between a BLE device and a client computer (which could be a phone or tablet). The program then starts advertising its UART service to anyone listening. The client computer receives the advertisement, and tells the user it's available. The user can then choose to connect as a client of the service.

One a connection is established, the program code waits for incoming command packets from the client, either a ColorPacket or a ButtonPacket. When one arrives, the program waits to see which button has been pressed or which color value is sent and then either runs the motors or changes the colors on the NeoPixels.

Motor Movement

We set up a couple of variables -- FWD and REV -- that tell the program which base values to send for forward and reverse. Depending on how you wired the motors, and which way you want to consider "forward" on the cart, you can adjust these values anywhere from -1.0 to 1.0.

When you test the rover, if it goes backwards when you press the up button, you can switch the FWD variable from 0.25 to -0.25 and flip the REV value from -0.25 to 0.25. The alternative is to swap which wire -- red or black -- is going into each port of the Motor 1 and Motor 2 terminals on the Crickit.

If you find the rover spinning in circle when you press up or down on the remote app, then one of the motors is wired "backwards". Simply swap the two wires of that motor into each others' ports on the Crickit!

micropython___circuitpython_Untitled.png
Swapping wires to get a motor to run the other way. Swap the two in the red circle for one or the orange circle for the other but don't swap pins between the circles.

Control the Rover with the Bluefruit LE Connect App

Download the App

To control the motors and NeoPixels from a client device (phone or tablet), you use the free Adafruit Bluefruit LE Connect App. Install it from the Apple App Store or Google Play App Store.

Connect to CPB

 

With the Crickit plugged into DC power and turned on with its on-board power switch, the CPB will also get power and automatically start running your code. Then start up the Bluefruit LE Connect app, and make sure it's in Central Mode (left button on the bottom).  When you start the app, you should see a device named CIRCU or CIRCUITPY. If there's a long list of devices, you can shorten it by turning on the "Must have UART Service" switch.

To connect to the bot, touch the Connect button.

Drive and Light

 

Once connected, you can use the Controllers -> Control Pad to drive with the arrow buttons, stop with the 1 button, and change to some preset colors on 2, 3, & 4

The incoming packet for any arrow button press event will tell the motors to throttle to the preset speed variable, such as motor_1.throttle = FWD. When you release the button, the button packet will tell the motor to stop. So, you can press and hold to go, and then release to stop, it's easy and fun!

Here's our turtle up on blocks to demonstrate the remote control:

And here it is with wheels (flippers!) down:

This guide was first published on Nov 12, 2019. It was last updated on Nov 12, 2019. This page (Code with CircuitPython) was last updated on Mar 22, 2020.