controller arm_tracking#

Describes the entry arm_tracking at version 0.1.0, registered by mime.control._arm_tracking.ArmTracking.

At a glance#

  • controller arm_tracking, version 0.1.0, namespace mime

  • Derivative, by mode: inside the compiled step piecewise_jump, as a callback cut

  • Validity: none declared

What it models, and when not to use it#

A magnet carried by an arm, following a body#

What it models. The controller of an arm that carries a magnet above a robot in a tube and keeps it there as the robot swims: exp.set_controller(ArmTracking(description=asset("arm.urdf"), end_effector="link_6", home=rad(...), axis=X, up=Z, at=m(...)), reads={"body_pose": "umr.pose", "body_twist": "umr.twist", "joint_positions": "rpm.arm.joint_positions"}, writes={"joint_positions": "rpm.arm.joint_positions"}, mode="callback"), or mode="graph" to run it inside the compiled step. Each control period it reads the body’s pose, its twist and the arm’s joint positions, sets a target for the arm’s end effector at the standoff along up from where the body is along axis, that distance held within reach, and writes the joint positions that a few damped-least-squares steps reach from the arm’s present ones: the command of a kinematic arm. The target moves a fraction smoothing of the way towards that point each tick, from the end effector’s pose at home; with orientation_feedback, its orientation also turns so that the end effector’s z follows the body’s.

It is the v0.2 line’s controller of the AR4 rig, ported: the same target, filter and inverse kinematics, compared with the v0.2 controller on a recorded input sequence. It computes in single precision whatever the run’s precision, as the v0.2 controller did, so a run in double precision with it is mixed.

When not to use it.

  • When what the controller reads matters: it reads the body’s pose and twist and the arm’s joint positions straight from the physics state, which the build report lists as ground truth, not deployable (see MIME-ANO-104). No instrument gives a real controller the robot’s pose inside a body.

  • For a dynamic arm: it writes joint positions, and the joint torques of the v0.2 line’s computed-torque control wait for the dynamic arm.

  • When a derivative of the run is needed and it runs as a callback: between compiled chunks no derivative passes through its writes. Inside the compiled step one does, and it is piecewise_jump: the reach is a clip (a kink), and the inverse kinematics’ half turn, the orientation feedback’s hemisphere and its fallback where the body’s z lies along the home pose’s x are jumps. A tracking target never comes near a half turn of the end effector.

  • For a tube that is not straight through the origin along axis: it follows the body’s distance along that one line.

  • When the target filter’s time constant must stay fixed as the rate changes: smoothing is a fraction per tick, so the same value at another rate is another filter.

Versions. arm_tracking 0.1.0 is its first: as a callback or inside the compiled step, writing a kinematic arm’s joint positions.

Settings#

Setting

Type

Default

Dimension

Role

Default’s kind

acknowledged

tuple[tuple[str, str], ...]

[]

none

design

convention

at

Annotated[Quantity, Length]

{"unit": "m", "value": [0.0, 0.0, 0.0]}

length (m)

physical

convention

axis

tuple[float, float, float]

{"required": true}

none

design

none

damping

float

0.05

none

numerical

numerical

description

Asset

{"required": true}

none

physical

none

end_effector

str

{"required": true}

none

design

none

gain

float

1.0

none

numerical

numerical

home

Annotated[Quantity, DIMENSIONLESS]

{"required": true}

dimensionless

design

none

iterations

int

5

none

numerical

numerical

lookahead

Annotated[Quantity, Time]

{"unit": "s", "value": 0.01}

time (s)

numerical

numerical

orientation

tuple[float, float, float, float] | None

null

none

physical

convention

orientation_feedback

bool

false

none

design

convention

reach

Annotated[Quantity, Length]

{"unit": "m", "value": [-0.05, 0.05]}

length (m)

numerical

numerical

smoothing

float

0.005

none

numerical

numerical

standoff

Annotated[Quantity, Length]

{"unit": "m", "value": 0.15}

length (m)

numerical

numerical

up

tuple[float, float, float]

{"required": true}

none

design

none

Each role and default’s kind is the entry’s setting_roles (mime.registry.SettingRole); a setting that declares none is required.

Each default is a claim (mime.registry.DefaultKind): a determined default is resolved in every profile, a convention taken in every profile, a numerical default taken in exploratory only and stamped pending. Their rules and bases:

  • acknowledged (convention): the setting’s written default; no element of the description is read past unless acknowledged with its reason

  • at (convention): the setting’s written default; the arm’s base sits at the world’s origin unless placed

  • damping (numerical): the value the earlier line’s controller ran with; the frozen reference of the arm’s experiment was run with it; no study of it is recorded

  • gain (numerical): the value the earlier line’s controller ran with; a design value of the controller (where and how it holds the arm), held as a numerical default so that A0’s frozen declarations stand: the frozen reference of the arm’s experiment was run with it, and no study of it is recorded

  • iterations (numerical): the value the earlier line’s controller ran with; the frozen reference of the arm’s experiment was run with it; no study of it is recorded

  • lookahead (numerical): the value the earlier line’s controller ran with; a design value of the controller (where and how it holds the arm), held as a numerical default so that A0’s frozen declarations stand: the frozen reference of the arm’s experiment was run with it, and no study of it is recorded

  • orientation (convention): the setting’s written default; the arm’s base is not turned from the world unless turned

  • orientation_feedback (convention): the setting’s written default; the target is not turned to follow the body unless asked

  • reach (numerical): the value the earlier line’s controller ran with; a design value of the controller (where and how it holds the arm), held as a numerical default so that A0’s frozen declarations stand: the frozen reference of the arm’s experiment was run with it, and no study of it is recorded

  • smoothing (numerical): the value the earlier line’s controller ran with; a design value of the controller (where and how it holds the arm), held as a numerical default so that A0’s frozen declarations stand: the frozen reference of the arm’s experiment was run with it, and no study of it is recorded

  • standoff (numerical): the value the earlier line’s controller ran with; a design value of the controller (where and how it holds the arm), held as a numerical default so that A0’s frozen declarations stand: the frozen reference of the arm’s experiment was run with it, and no study of it is recorded

Reads and writes#

reads: each label bound by the experiment to a thing’s state or an observation’s output:

Label

Units

Shape

body_pose

m; 1

[7]

body_twist

m/s; rad/s

[6]

joint_positions

1

[-1]

writes: each label bound by the experiment to an apparatus’s command, whose drive it replaces:

Label

Units

Shape

joint_positions

1

[-1]

Nodes it builds#

Builds no node of its own.

Gradient status#

The derivative depends on the mode the controller is placed in, and a saved experiment’s lock records that mode’s status:

  • Inside the compiled step: piecewise_jump, its law’s own

  • As a callback: cut, the binding’s whatever the law

The derivative through this controller inside the compiled step is piecewise_jump: not the exact derivative of what it computes everywhere.

Switches the law evaluates, each declared once by its owner:

Switch

Indicator

Orders, per output group

Route to exact

arm_tracking.reach.low

the body’s distance along the axis less the reach’s lower end, m

joint_positions 0 (a kink); target_position 0 (a kink)

none: a distance below the reach is held at its end, whose derivative in the distance is zero; a smooth envelope would be another controller

arm_tracking.reach.high

the reach’s upper end less the body’s distance along the axis, m

joint_positions 0 (a kink); target_position 0 (a kink)

none: a distance above the reach is held at its end, as at the lower one

arm_tracking.half_turn

minus the cosine of half the angle from the end effector’s orientation to its target’s (the w of the turn between them), dimensionless, positive past a half turn

joint_positions -1 (a jump)

none: past a half turn the shorter way round is the other way, and each inverse-kinematics step turns back; a target within a half turn of the end effector, as a tracking one is, never reaches it

arm_tracking.small_turn

the series’ threshold less the squared sine of half the angle from the end effector’s orientation to its target’s, dimensionless, positive where its rotation vector is taken from its series

joint_positions 1 (continuously differentiable)

none needed: the series meets the closed form to rounding in its value and its slope, so the derivative on either side is the one function’s

arm_tracking.parallel

the length of the home pose’s x made perpendicular to the body’s projected z, less the length below which the two are taken as parallel, dimensionless

joint_positions -1 (a jump); target_orientation -1 (a jump)

none: with the home pose’s x along the body’s z the target’s x is undefined, and the home pose’s y stands in for it

arm_tracking.hemisphere

the length of q (q . held), q the turn’s quaternion and held the target’s orientation, dimensionless: zero at the edge of held’s hemisphere

joint_positions -1 (a jump); target_orientation -1 (a jump)

none: at the edge q and -q are as near the held orientation, and the filter goes the other way round on either side

The derivative through this controller as a callback is cut: not the exact derivative of what it computes everywhere.

  • Where: the controller’s writes: a compiled chunk takes them as fixed inputs, so a derivative of the run stops at them (it is zero through them)

  • Why: the run calls the controller’s step on the host between compiled chunks, where no derivative passes through a call

  • Route to exact: place the controller inside the compiled step, where its status is its law’s own, derived from the switches it declares

Validity#

none declared

References#

[@Sciavicco2000], [@deJongh2025NonlinDyn]

Other declarations#

Class variable

Type

Value

live

ClassVar[Mapping[str, LiveInput]]

too long to show; see `mime registry --json`

moving

ClassVar[bool]

false