same output on port 3001
i wonder what the difference between those interfaces is
same output on port 3001
i wonder what the difference between those interfaces is
Heres a reference guide on the error codes:
I’m on my phone right now… but it doesn’t look like -2808 is immediately listed
“Error codes available for use by GPL application programs (in addition to -786 and -1038)”
gpl = Guidance Programming Language
here:
through telnet interface (password for me is Help)
GPL: Show Thread
ICT, Idle
TcpAsyncCom1, Running
TcpCom1, Running
What’s the current state of this? At a glance it looks pretty feature complete on github but pretty recent commits. I have an arm coming in the next week or so
pf is fully working! we are using it in production, including one with a linear rail.
I just reverse engineered the inverse kinematics last friday (because the brooks cartesian api has some ambiguity). this will live on the v1b1 branch until we merge v1b1 into main. I will post an update here when I merge this (this afternoon)
Amazing! Thanks, I’m looking forward to trying this out
pushed this yesterday pf kinematics · PyLabRobot/pylabrobot@0fa5e4e · GitHub
Wow, this is awesome Rick. Been thinking about doing this, much simpler than I thought it would be :). Curious what sort of issues you had with Cartesian commands? For the most part I’ve mostly preferred using joint space for the same reason. eg. not being able to determine elbow orientation between locations. (unless you force the path)
yeah of course
l1 and l2 are initially fitted using linear regression on the arm model, by querying joint and cartesian locations and just learning the function. Then I was actually able to validate this by looking at the technical drawings of the pf400 (https://www.brooks.com/getmedia/968fcb26-d347-4404-b9ab-bbd910447975/PreciseFlex_400.pdf), which I should have done from the start but didnt think of.
L3 is dependent on the gripper. I am not sure how that is configured for the stock dataset that I trained, must somewhere be on the arm. But this one is actually parameterized since it depends on the gripper:
from pylabrobot.brooks.precise_flex import PreciseFlex400
# Default (stock single gripper, 162 mm)
pf = PreciseFlex400(host="192.168.0.1")
# Custom gripper length (e.g. 185 mm for an alternate end-effector)
pf = PreciseFlex400(host="192.168.0.1", gripper_length=185.0)
await pf.setup()
Yeap! I know what you are talking about. Great solution.
@rickwierenga can you tell me more about this, is there a way to easily query these values? I assume they vary by robot to robot?
@dataclass
class PF400Params:
"""Calibrated link lengths; sub-mm FK residual on a held-out probe set."""
l1: float = 302.0 # shoulder -> elbow [mm]
l2: float = 289.0 # elbow -> wrist [mm]
l3: float = 162.0 # wrist -> TCP [mm]
z_tool_offset: float = 0.0
eps: float = 1e-6
initially I fitted those parameters by linear regression against the model for this arm, but then I was able to validate them against the technical drawing (https://www.brooks.com/getmedia/968fcb26-d347-4404-b9ab-bbd910447975/PreciseFlex_400.pdf). In hindsight I should have just used that model from the start but oh well.
The gripper (l3) is machine specific. I am not sure where the 162 came from for the “training set” I made for fitting this model, must be stored on the machine somewhere. But it’s parameterized now so should be easy to change. Here’s the API for that:
from pylabrobot.brooks.precise_flex import PreciseFlex400
# Defaults (stock PF400 single gripper): gripper_length=162.0, gripper_z_offset=0.0
pf = PreciseFlex400(host="192.168.0.1")
# Custom end-effector
pf = PreciseFlex400(
host="192.168.0.1",
gripper_length=185.0,
gripper_z_offset=12.5,
)
await pf.setup()
also renamed z_tool_offset to gripper_z_offset and l3 to gripper_length for clarity.