1. Comments

This kit only has code examples for programming the Pi Pico in the Arduino environment. You are welcome to play around with this, but it hasn’t been tested. We will be programming the cars using MicroPython instead.

2. Build notes

The camp’s docs has information about all of the robots.

Open the main build and information document:
docs / Freenove 4WD / Mecanum_wheels / Tutorial.pdf

Survey the PDF’s bookmarks to get a sense of what’s in this document.

3. code

Test code for the RGB lights
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import time

from machine import Pin

led = Pin(25, Pin.OUT)


led.on()
time.sleep(1)
led.off()
time.sleep(1)


from neopixel import NeoPixel

np = NeoPixel(Pin(16, Pin.OUT), 8)

np[1] = (0, 0, 0)
np.write()

Motor utilities for demonstrations
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
from machine import Pin
from machine import PWM
from machine import Timer




def duty_to_u16(x):
    """Convert a percentage 0..100 into the range used by the PWM hardware of
    0..65535.   (2**16 - 1), the largest unsigned 16-bit number.

    The sign of _x_ is ignored and treated as always positive."""

    x = abs(x)  # ensure this is a positive number
    out = (65535 * x) // 100
    return out



class motor:
    """Class that describes how to control _some_ motor, since they all work
    the same way.  When creating a specific instance of the motor drive, it
    needs to be told which two pins it has control over, labeled _a_ and _b_
    here."""

    #
    # Initialization
    #
    def __init__(self, pin_a, pin_b, freq=1_000):
        self.pin_a = pin_a
        self.pin_b = pin_b
        self.a = PWM(Pin(pin_a, Pin.OUT), freq=freq, duty_u16=0)
        self.b = PWM(Pin(pin_b, Pin.OUT), freq=freq, duty_u16=0)
        self._running = False

    #
    # Basic operations
    #
    def coast(self):
        # see the DRV8837 motor driver chip datasheet
        self.a.duty_u16(0)  # always low
        self.b.duty_u16(0)
        self._running = False

    def brake(self):
        # see the DRV8837 motor driver chip datasheet
        self.a.duty_u16(65535)  # always high
        self.b.duty_u16(65535)
        self._running = False

    def stop(self, arg=None):
        """There are two ways to "stop", so uncomment the one that best fits
        your situation."""
        self.coast()
        #self.brake()

        if arg:
            arg.deinit()

    #
    # Actual motions.
    #
    # speed - percentage 0..100.  Negative values mean opposite direction.
    # howlong - time in seconds (currently ignored)
    #
    def forward(self, speed, howlong=None):
        speed_u16 = duty_to_u16(speed)
        self.a.duty_u16(speed_u16)
        self.b.duty_u16(0)
        self._running = True

        if howlong:
            t = Timer(mode=Timer.ONE_SHOT, period=howlong, callback=self.stop)

    def backward(self, speed, howlong=None):
        speed_u16 = duty_to_u16(speed)
        self.a.duty_u16(0)
        self.b.duty_u16(speed_u16)
        self._running = True

        if howlong:
            t = Timer(mode=Timer.ONE_SHOT, period=howlong, callback=self.stop)

    def go(self, speed, howlong=None):
        """Move forward or backwards according to the sign of speed."""
        if speed > 0:
            self.forward(speed, howlong)

        elif speed < 0:
            self.backward(-speed, howlong)

        elif speed == 0:
            self.stop()

        else:
            print(f"ERROR: Unknown speed: {speed}")

    def is_running(self):
        return self._running


# Replace the PINX and PINY with the pin numbers that match the wiring as shown
# in the "Pins of the Car" section in the documentation.
m1 = motor(19, 18)
m2 = motor(20, 21)
m3 = motor(6, 7)
m4 = motor(8, 9)


def stop():
    m1.stop()
    m2.stop()
    m3.stop()
    m4.stop()

def coast():
    m1.coast()
    m2.coast()
    m3.coast()
    m4.coast()

def brake():
    m1.brake()
    m2.brake()
    m3.brake()
    m4.brake()

def go(speed, howlong=None):
    m1.go(speed, howlong)
    m2.go(speed, howlong)
    m3.go(speed, howlong)
    m4.go(speed, howlong)