Seth
Published © GPL3+

BeagleY-AI and New Contributions and Maestro Servo Control

Does your BeagleY-AI have the capability to handle the Maestro 5v Servo Controller (TTL) from a mostly CMOS logic?

IntermediateProtip1 hour19
BeagleY-AI and New Contributions and Maestro Servo Control

Things used in this project

Hardware components

BeagleY-AI
×1
USB-A to Mini-USB Cable
USB-A to Mini-USB Cable
×1
Maestro Servo Controller
×1
Female/Female Jumper Wires
Female/Female Jumper Wires
×1
Servo Module (Generic)
×1

Software apps and online services

Python3
BB-Imager

Story

Read more

Schematics

Fritzing

Code

The Python3 File

Python
#!/usr/bin/python3

import sys
import usb.core
import usb.util
from protocol import *
import numpy as np
import os


# Constant definitions mimicking the C++ implementation
VENDOR_ID = 0x1FFB
PRODUCT_IDS = [0x0089, 0x008A, 0x008B, 0x008C]
REQUEST_SET_TARGET = 0x85  # The standard Pololu Maestro native USB request ID


def find_maestro_device():
    """Loops through known product IDs to find the Pololu Maestro device."""
    for pid in PRODUCT_IDS:
        device = usb.core.find(idVendor=VENDOR_ID, idProduct=pid)
        if device is not None:
            return device
    return None


def set_target(device, position, servo=0):
    """Sends the target position to a specific servo channel using a control transfer."""
    # bmRequestType = 0x40 (Vendor-defined request, host-to-device direction)
    bm_request_type = 0x40
    b_request = REQUEST_SET_TARGET

    # Value parameter requires position in quarter-microseconds (input * 4)
    w_value = int(position * 4)
    w_index = int(servo)

    try:
        # usb.core.Device.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout)
        device.ctrl_transfer(
            bm_request_type, b_request, w_value, w_index, data_or_wLength=0, timeout=5000
        )
    except usb.core.USBError as e:
        print(f"USB Transfer failed: {e}", file=sys.stderr)

def create_3dof_matrix(x, y, theta_rad):
    """
    Creates a 3 DoF homogeneous transformation matrix (3x3).

    Parameters:
    x, y      : Translation along X and Y axes
    theta_rad : Rotation angle in radians
    """
    cos_t = np.cos(theta_rad)
    sin_t = np.sin(theta_rad)

    # Define the 3x3 transformation matrix
    matrix = np.array([
        [cos_t, -sin_t, x],
        [sin_t,  cos_t, y],
        [0,      0,     1]
    ])

    return matrix

# 1. Define transformation parameters (Move 5 units X, 2 units Y, Rotate 45 degrees)
angle = np.radians(45)
T_a_to_b = create_3dof_matrix(5.0, 2.0, angle)

print("Transformation Matrix (Frame A to B):")
print(T_a_to_b)

# 2. Define a point in Frame B: [X, Y, 1] for homogeneous coordinates
point_in_b = np.array([1.0, 0.0, 1.0])

# 3. Transform the point to Frame A using matrix multiplication
point_in_a = np.dot(T_a_to_b, point_in_b)

print("\nTransformed Point in Frame A:")
print(point_in_a[:2]) # Extract just the X and Y coordinates


def main():
    print("Searching for Pololu Maestro device...")
    device = find_maestro_device()

    if device is None:
        print("Error: Maestro device not found. Check physical connections or permissions.")
        sys.exit(1)

    print("Device found and initialized successfully.")
    servo_channel = 0

    try:
        while True:
            user_input = input("Enter position (or 'q' to quit): ").strip()
            if user_input.lower() == "q":
                break

            try:
                position = int(user_input)
                set_target(device, position, servo_channel)
            except ValueError:
                print("Invalid input. Please enter an integer number.")

    except KeyboardInterrupt:
        print("\nExiting program.")
    finally:
        # PyUSB handles closing the device and recycling handles implicitly on exit,
        # but clearing configurations ensures safe detachment.
        usb.util.dispose_resources(device)


if __name__ == "__main__":
    main()

Credits

Seth
36 projects • 14 followers
Stay there and someone will find you...

Comments