@BrandonM ,
Hey sir, Seth here. I got some working source so far for the Maestro in Python3 but with me and my learning curve, I am seeing anomalies in the way things work “for me” while the SDK needs additional data (I think).
I know this weekend is Memorial Day weekend. So, no big woof about replying early or even by next Wed.
I will post the source and the anomaly soon so you can see what I am describing.
#!/usr/bin/python3
import sys
import usb.core
import usb.util
from protocol import *
import numpy as np
from time import sleep
# 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
def create_3dof_action():
action = np.array([
[1.5, 1.0, 0.5, 0.0],
[-1.5, -1.0, -0.5, 0.0],
[5.0, -5.0, 2.5, -2.5],
[0.0, 1.1, -1.1, 0.0]
])
return action
# 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) # LINE 500
set_target(device, position, servo_channel) # LINE 501
else:
return position
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()
The source code above was derived from various sources and installed on a SBC. It is a work in progress as I make this 3 DoF Arm and more…
Anyway, the source code above has two comments, LINE 500 and LINE 501, that I just commented on for this error:
On various occasions while running the source, I get working order commands that do what is intended. Other times, I get nothing. I know why now, i.e. permissions and lack of Pythonista coding skills from me.
In any light and here, those lines in comments listed work. I can just type positive to negative integers all day.
That is not my end game here. It seems if I put in a set of source code, the errors arise. Here…
if position >= 49 or position != 0:
set_target(device, position, servo_channel)
...
usually when I use specific interfaces/peripherals on SBC boards like the beagleboard.org setlist, I can alter the source code well enough.
I am seemingly coming to a halt where I cannot understand why things are transpiring in the source code and/or for what reasons the source code is working or not working.
I know this is my issue. I should know what I am doing before I do it. I got in a rush in some backlogs of the SDK without reviewing it completely and understanding everything.
Do you or anyone else see why the listed LINE 500 and LINE 501 comments are working while my listed if statement does not do what is intended?
Seth
P.S. And…if you could point me to a handy tutorial in Python3 for your Maestro, we could be besties! For life! All jokes aside, any explanation will suffice. This is for one servo from the Maestro Mini 18.