Skip to content

matthiaskreier/circuitpython

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

circuitpython

Collection of Circuitpython programs

sphero.py for micro:bit

This is the raw file with 4 kByte and several functions we like to use. Uploaded as sphero.py from October 9, 2019 (link to Github):

from microbit import uart

class LEDs:
    RIGHT_HEADLIGHT    = [0x00, 0x00, 0x00, 0x07]  # 00000000 00000000 00000000 00000111
    LEFT_HEADLIGHT     = [0x00, 0x00, 0x00, 0x38]  # 00000000 00000000 00000000 00111000
    LEFT_STATUS        = [0x00, 0x00, 0x01, 0xC0]  # 00000000 00000000 00000001 11000000
    RIGHT_STATUS       = [0x00, 0x00, 0x0E, 0x00]  # 00000000 00000000 00001110 00000000
    BATTERY_DOOR_FRONT = [0x00, 0x03, 0x80, 0x00]  # 00000000 00000000 01110000 00000000
    BATTERY_DOOR_REAR  = [0x00, 0x00, 0x70, 0x00]  # 00000000 00000011 10000000 00000000
    POWER_BUTTON_FRONT = [0x00, 0x1C, 0x00, 0x00]  # 00000000 00011100 00000000 00000000
    POWER_BUTTON_REAR  = [0x00, 0xE0, 0x00, 0x00]  # 00000000 11100000 00000000 00000000
    LEFT_BRAKELIGHT    = [0x07, 0x00, 0x00, 0x00]  # 00000111 00000000 00000000 00000000
    RIGHT_BRAKELIGHT   = [0x38, 0x00, 0x00, 0x00]  # 00111000 00000000 00000000 00000000

class RawMotorModes:
    OFF = 0
    FORWARD = 1
    BACKWARD = 2

class RVRDrive:
    @staticmethod
    def drive(speed, heading):
        flags = 0x00
        if speed < 0:
            speed *= -1
            heading += 180
            heading %= 360
            flags = 0x01
        drive_data = [
            0x8D, 0x3E, 0x12, 0x01, 0x16, 0x07, 0x00,
            speed, heading >> 8, heading & 0xFF, flags
        ]
        drive_data.extend([~((sum(drive_data) - 0x8D) % 256) & 0x00FF, 0xD8])
        uart.write(bytearray(drive_data))
        return

    @staticmethod
    def stop(heading):
        RVRDrive.drive(0, heading)
        return

    @staticmethod
    def set_raw_motors(left_mode, left_speed, right_mode, right_speed):
        if left_mode < 0 or left_mode > 2:
            left_mode = 0
        if right_mode < 0 or right_mode > 2:
            right_mode = 0
        raw_motor_data = [
            0x8D, 0x3E, 0x12, 0x01, 0x16, 0x01, 0x00,
            left_mode, left_speed, right_mode, right_speed
        ]
        raw_motor_data.extend([~((sum(raw_motor_data) - 0x8D) % 256) & 0x00FF, 0xD8])
        uart.write(bytearray(raw_motor_data))
        return

    @staticmethod
    def reset_yaw():
        drive_data = [0x8D, 0x3E, 0x12, 0x01, 0x16, 0x06, 0x00]
        drive_data.extend([~((sum(drive_data) - 0x8D) % 256) & 0x00FF, 0xD8])
        uart.write(bytearray(drive_data))
        return

class RVRLed:
    @staticmethod
    def set_all_leds(red, green, blue):
        led_data = [
            0x8D, 0x3E, 0x11, 0x01, 0x1A, 0x1A, 0x00,
            0x3F, 0xFF, 0xFF, 0xFF
        ]
        
        for _ in range (10):
            led_data.extend([red, green, blue])
        led_data.extend([~((sum(led_data) - 0x8D) % 256) & 0x00FF, 0xD8])
        uart.write(bytearray(led_data))
        return

    @staticmethod
    def set_rgb_led_by_index(index, red, green, blue):
        led_data = [0x8D, 0x3E, 0x11, 0x01, 0x1A, 0x1A, 0x00]
        led_data.extend(index)
        led_data.extend([red, green, blue])
        led_data.extend([~((sum(led_data) - 0x8D) % 256) & 0x00FF, 0xD8])
        uart.write(bytearray(led_data))
        return

class RVRPower:
    @staticmethod
    def wake():
        power_data = [0x8D, 0x3E, 0x11, 0x01, 0x13, 0x0D, 0x00]
        power_data.extend([~((sum(power_data) - 0x8D) % 256) & 0x00FF, 0xD8])
        uart.write(bytearray(power_data))
        return
        
    @staticmethod
    def sleep():
        power_data = [0x8D, 0x3E, 0x11, 0x01, 0x13, 0x01, 0x00]
        power_data.extend([~((sum(power_data) - 0x8D) % 256) & 0x00FF, 0xD8])
        uart.write(bytearray(power_data))
        return
  • RVRDrive with
    • drive(speed, heading)
    • stop(heading)
    • set_raw_motors(left_mode, left_speed, right_mode_ right_speed)
    • reset_yaw()
  • RVRLed for the 10 LEDs with .set_all_leds and .set_rgb_led_by_index
  • RVRPower with .sleep() and .wake()

Documentation of protocol and code

The packages are well documented by @emwdx in his code for drive_to_position:

# Set up the serial port on the board
uart = busio.UART(board.TX, board.RX, baudrate=115200)

# This function takes in an angle, a pair of x and y coordinates, and a speed target to use for the RVR.
def drive_to_position_si(yaw_angle, x, y, speed):

  # This sets up the list of bytes needed for this command to be sent to the RVR through the serial port.
    SOP = 0x8d             # Always the start byte for a command to the RVR
    FLAGS = 0x06           # This tells the RVR to ignore the target and source ID, 
	                       # and that this command expects a response only if there are errors.
    TARGET_ID = 0x0e 
    SOURCE_ID = 0x0b
    DEVICE_ID = 0x16       # The drive system ID is 0x16
    COMMAND_ID = 0x38      # The drive_to_position_si command has ID of 38
    SEQ = 0x01             # The sequence value is arbitrarily 1. We aren't using the sequence capability here.
    EOP = 0xD8             # The final byte in the command is 0xD8

  # The command expects four float values for yaw angle, x coordinate, y coordinate, and speed. 
  # This lets you use decimal values.
  # The lines below convert the float values to a set of four bytes representing each value.
    yaw_angle = bytearray(struct.pack('>f', yaw_angle))
    x = bytearray(struct.pack('>f', x))
    y = bytearray(struct.pack('>f', y))
    speed = bytearray(struct.pack('>f', speed))
	
  # The command has a flags byte that lets you set different attributes for how the robot moves 
  # between the positions. Check out page 12 of the SpheroRVRControlSystem manual for the details.
    flags = bytearray(struct.pack('B', 0))

  # Now we build the command packet byte by byte. First the first five bytes:
    output_packet = [SOP, FLAGS, DEVICE_ID, COMMAND_ID, SEQ]

  # Now the bytes for the flags
    output_packet.extend(yaw_angle)
    output_packet.extend(x)
    output_packet.extend(y)
    output_packet.extend(speed)
    output_packet.extend(flags)
  # And the checksum byte which does some math with the sum of the previous 
  # bytes in the command, and finally the end of packet byte.
    output_packet.extend([~((sum(output_packet) - SOP) % 256) & 0x00FF,EOP])

  # Now that the command is complete, return the command as an array of bytes.
    return bytearray(output_packet)

# END OF DRIVE_TO_POSITION_SI