Control API
skelarm.control
Trajectory-tracking control: references, torque controllers, and a fixed-step loop.
This module turns a planned reference into joint torques. A task-space trajectory
is first converted to a joint-space reference (samplewise inverse kinematics or
resolved motion rate), then a torque controller (joint PD, inverse-dynamics
feedforward plus PD, or computed torque) tracks it. :func:simulate_controlled
runs a controller against the dynamics with a fixed time step and returns a
:class:~skelarm.StateLog for replay and analysis.
See docs/reference/07_control.md for the theory.
ComputedTorque
Bases: TrackingController
Computed torque control: τ = H(q)(q̈_r + Kd ė + Kp e) + b(q,q̇).
Source code in src/skelarm/control.py
control(t, skeleton)
Compute the model-cancelling torque for the current state.
Source code in src/skelarm/control.py
Controller
Bases: ABC
Base class for joint-torque controllers.
A controller is callable as f(t, skeleton) -> tau so stateless controllers
work directly as a :func:~skelarm.simulate_robot torque callback. Stateful
controllers use :meth:reset and :meth:update together with
:func:simulate_controlled, and may expose internal signals via
:meth:log_channels.
Source code in src/skelarm/control.py
__call__(t, skeleton)
control(t, skeleton)
abstractmethod
log_channels()
reset(skeleton)
InverseDynamicsFeedforwardPD
Bases: TrackingController
Inverse-dynamics feedforward plus PD: τ = ID(q_r,q̇_r,q̈_r) + Kp e + Kd ė.
Source code in src/skelarm/control.py
__init__(reference, kp, kd)
Store the reference and gains; the feedforward model is built lazily.
control(t, skeleton)
Compute the feedforward-plus-PD torque for the current state.
Source code in src/skelarm/control.py
JointPD
Bases: TrackingController
Direct joint-space PD control: τ = Kp(q_r-q) + Kd(q̇_r-q̇).
Source code in src/skelarm/control.py
control(t, skeleton)
Compute the PD torque for the current state.
Source code in src/skelarm/control.py
JointReference
Bases: Protocol
A joint-space reference that can be sampled for (q_r, dq_r, ddq_r).
Source code in src/skelarm/control.py
sample(t)
SampledJointReference
A joint reference stored as time-sampled arrays, read by linear interpolation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
times
|
ArrayLike
|
Sample times, shape |
required |
q
|
ArrayLike
|
Joint angles, velocities, and accelerations, each shape |
required |
dq
|
ArrayLike
|
Joint angles, velocities, and accelerations, each shape |
required |
ddq
|
ArrayLike
|
Joint angles, velocities, and accelerations, each shape |
required |
Source code in src/skelarm/control.py
__init__(times, q, dq, ddq)
Store the sampled reference arrays.
Source code in src/skelarm/control.py
sample(t)
Linearly interpolate the reference at time t (held at the endpoints).
Source code in src/skelarm/control.py
SampledTaskReference
A task-space reference stored as time-sampled arrays, read by linear interpolation.
Use this when a (typically pre-smoothed) endpoint path p_r(t) is supplied as
samples; it satisfies :class:TaskReference, so :func:ik_joint_reference can turn
it into a joint reference for the tracking controllers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
times
|
ArrayLike
|
Sample times, shape |
required |
p
|
ArrayLike
|
Endpoint position, velocity, and acceleration, each shape |
required |
dp
|
ArrayLike
|
Endpoint position, velocity, and acceleration, each shape |
required |
ddp
|
ArrayLike
|
Endpoint position, velocity, and acceleration, each shape |
required |
Source code in src/skelarm/control.py
__init__(times, p, dp, ddp)
Store the sampled task-space arrays and derive the duration.
Source code in src/skelarm/control.py
sample(t)
Linearly interpolate the endpoint reference at time t (held at the endpoints).
Source code in src/skelarm/control.py
TaskReference
Bases: Protocol
A task-space reference p_r(t) sampled for (p, dp, ddp).
Anything exposing .sample(t) and a .duration is a task reference, so
:class:~skelarm.Trajectory, :class:SampledTaskReference, and the periodic
curves all qualify and can feed :func:ik_joint_reference.
Source code in src/skelarm/control.py
sample(t)
TrackingController
Bases: Controller
A controller that tracks a joint reference, logging q_ref and error.
Source code in src/skelarm/control.py
__init__(reference, kp, kd)
Store the reference and (scalar or per-joint) PD gains.
Source code in src/skelarm/control.py
log_channels()
Record the joint reference and tracking error once tracking has begun.
ik_joint_reference(skeleton, task_trajectory, *, dt, method='lm_sugihara')
Convert a task-space trajectory to a joint reference with samplewise IK.
Each sample is solved with :func:compute_inverse_kinematics, warm-started
from the previous solution for joint continuity. Velocities and accelerations
are estimated by finite differences. The input skeleton is not mutated.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skeleton
|
Skeleton
|
The arm to solve for; its current pose seeds the first IK solve. |
required |
task_trajectory
|
TaskReference
|
The desired endpoint trajectory |
required |
dt
|
float
|
Sampling interval (seconds). |
required |
method
|
str
|
IK method passed to :func: |
'lm_sugihara'
|
Returns:
| Type | Description |
|---|---|
SampledJointReference
|
The joint reference |
Warns:
| Type | Description |
|---|---|
UserWarning
|
When one or more samples end more than |
Source code in src/skelarm/control.py
resolved_rate_joint_reference(skeleton, task_trajectory, *, dt, damping=0.001, k_task=0.0)
Convert a task-space trajectory to a joint reference by resolved motion rate.
Integrates q̇_r = Jᵀ(JJᵀ+µI)⁻¹(ṗ_r + K_task(p_r - p)) forward in time. The
task-feedback term K_task corrects drift from the desired path. The input
skeleton is not mutated.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skeleton
|
Skeleton
|
The arm to convert for; its current pose is the integration start. |
required |
task_trajectory
|
TaskReference
|
The desired endpoint trajectory. |
required |
dt
|
float
|
Integration step (seconds). |
required |
damping
|
float
|
Damping |
0.001
|
k_task
|
float
|
Task-space position-feedback gain. |
0.0
|
Returns:
| Type | Description |
|---|---|
SampledJointReference
|
The joint reference |
Source code in src/skelarm/control.py
simulate_controlled(skeleton, controller, *, duration, dt=0.001, grav_vec=None, enforce_limits=True, extra=None, external_force=None)
Run a controller against the dynamics with a fixed time step.
Uses semi-implicit (symplectic) Euler, the same integration as the GUI
simulator. A clone of skeleton is simulated, so the caller's skeleton is
not mutated. Each frame records q, dq, the controller's tau, and any
channels from controller.log_channels().
An external_force scripts a disturbance at the arm's tip, such as a push or
a hand that holds the arm. It is a tip force acting in addition to the
controller's torque, mapped to the joints as J^T F like the mouse force of
the GUI simulator, and recorded as the ext_force channel, which
tools/player.py draws as an arrow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skeleton
|
Skeleton
|
Initial state ( |
required |
controller
|
Controller
|
The torque controller to run. |
required |
duration
|
float
|
Total simulated time (seconds). |
required |
dt
|
float
|
Fixed control/integration step (seconds). |
0.001
|
grav_vec
|
NDArray[float64] | None
|
Gravity vector; defaults to zero (planar motion). |
None
|
enforce_limits
|
bool
|
Apply the joint limits as hard stops in the dynamics (default). When
|
True
|
extra
|
Mapping[str, Any] | None
|
Free-form metadata to embed in the returned log's |
None
|
external_force
|
Callable[[float, Skeleton], ArrayLike] | None
|
|
None
|
Returns:
| Type | Description |
|---|---|
StateLog
|
The recorded run ( |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/skelarm/control.py
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | |