Planar Arm Forward Kinematics — Robotics/Planar Kinematics
Robotics/Planar_Kinematics/Planar_Arm_Forward_Kinematics · 1 input / 1 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text
Description#
The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.
Planar Arm Forward Kinematics
Robotics / Planar Kinematics
The tool pose of an N-link planar serial arm from its N joint angles. Joint angles are relative – each measured from the previous link, which is what a joint sensor reports – so the absolute direction of link k is the running sum φk = q0 + … + qk, and the pose follows by walking the links tip to tip:
- x = Σk lk·cos(φk)
- y = Σk lk·sin(φk)
- φ = φN−1 – the tool's own orientation, which is simply the sum of every joint angle
Ports
- q – the joint angles, an [N,1] column in radians, base joint first. N is set by the Link Lengths config, and an input of any other height is an error rather than something broadcast.
- pose – [3,1], the triple (x, y, φ) the rest of this family uses. φ is raw: it is a sum of joint angles and may leave (−π, π].
Parameters
- Link Lengths – an [N,1] column, base link first, in whatever length unit the diagram uses. Its height is the only source of N, so the arm is defined here and nowhere else; a second config that could disagree with it deliberately does not exist. Lengths may be zero (a coincident joint) but not negative.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The link lengths are baked into the emitted body as literals rather than exposed as tunable parameters: they are structural – changing one changes N and therefore the port sizes, so it is not something that could be retuned on a generated core anyway.
The arm is fully unrolled at export time. N is fixed by the config, so no emitted body contains a loop or a data-dependent index; the code grows linearly with N.
The three HDL targets are simulation-only real
arithmetic, not synthesizable Q16.16: the body needs N sines and N
cosines every sample and there is no fixed-point trigonometry to call.
Quantization happens only at the port boundary.
Simulink bridge
None, and the reason is measured rather than assumed: Simulink's arm
kinematics ship in the Robotics System Toolbox, which is not installed on
this machine (robotics, nav, uav and
shared_robotics are all absent from
matlabroot/toolbox). A model carrying this block exports with the
block reported rather than silently dropped.
Notes
- Algebraic and stateless: the pose depends only on the current joint angles, so the block cannot break an algebraic loop.
- Joint angles are RELATIVE, not absolute. This is the convention a real arm reports and the one Planar Arm Jacobian differentiates. If a model carries absolute link directions instead, the cumulative sum here would double-count – feed differences, or drop the sum.
- Pairs with Planar Arm Jacobian, which is the derivative of this exact map and reads the same Link Lengths config. Give the two the same config value: they describe one arm, and nothing checks that for you.
- φ is unwrapped by design, matching the ledger the whole Robotics family follows. Put an Angle Wrap after it when a wrapped heading is wanted, so the wrap is visible in the diagram.
- Nonlinear, so deliberately no state space – a fabricated linear form would let model reduction merge matrices that do not describe this block.
Code facts#
| Fact | Value |
|---|---|
| registered type | Robotics/Planar_Kinematics/Planar_Arm_Forward_Kinematics |
| family | Robotics/Planar_Kinematics |
| solver environment class | ICoreBlock_0_Robotics_1_Planar_Kinematics_2_Planar_Arm_Forward_Kinematics |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Robotics/Planar_Kinematics/Planar_Arm_Forward_Kinematics/ICoreBlock_0_Robotics_1_Planar_Kinematics_2_Planar_Arm_Forward_Kinematics.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Robotics/Planar_Kinematics/Planar_Arm_Forward_Kinematics/ICoreBlock_0_Robotics_1_Planar_Kinematics_2_Planar_Arm_Forward_Kinematics.h |
| default size on canvas | 140 × 88 px |
| ports at insert | 1 in, 1 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | q |
| 2 | out | ICoreDouble | pose |
Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.
Configuration variables#
| Config variable | Default | Simulink parameter |
|---|---|---|
Link Lengths | [1; 0.8; 0.5] | — |
Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.
Simulink bridge#
| support | Support::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
Caveat (shown to the user): no Simulink equivalent available: planar arm kinematics ship in the Robotics System Toolbox, which is not installed. Rebuild the chain on the Simulink side from Trigonometric Function and Sum blocks, keeping the RELATIVE joint-angle convention and the (x, y, phi) pose layout this block uses
Catalog contract: src/ICoreSDK/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:
B0every stimulus in the sample errored — cross-checks skipped
The verdict above is
tools/docs/check_block_descriptions.py(P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.
File banner (developer view)#
The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).
Planar Arm Forward Kinematics — N relative joint angles to the tool pose (x, y, phi) phi_k = q_0 + q_1 + ... + q_k (cumulative: joint angles are RELATIVE) x = SUM_k l_k * cos(phi_k) y = SUM_k l_k * sin(phi_k) pose = [x; y; phi_{N-1}]
Written together with Planar_Arm_Jacobian, whose columns are suffix sums over the SAME l_k*cos(phi_k) and l_k*sin(phi_k) terms this block accumulates in full. See the header for why the pair travels together and what it buys that neither block has alone.
⚠ THE ACCUMULATION ORDER IS THE CONTRACT, and it is ascending k in all eleven implementations. Floating-point addition is not associative, so a backend summing the links tip-to-base would disagree with this reference in the last ulp on most samples -- a row that moves for a reason having nothing to do with the export.
⚠ EVERYTHING IS UNROLLED AT EXPORT TIME. N is fixed by the config, so the emitted body has no loop and no data-dependent indexing in any of the ten targets -- Decision_Tree's cascade argument, and it is what keeps the three HDL targets straightforward. The emitted body grows linearly in N, which the description states.
⚠ THE GENERATORS BAKE THE LINK LENGTHS IN, so loadBlockConfig() MUST be called from initializePortSignalSize() (§3): code export never calls it, and a generator reading an unfilled config map logs an error and stops the run.
Sample results#
No stimulus produced a sampled output in this rig — Invalid input size at Planar Arm Forward Kinematics block: ICore Blocks/Home/Planar Arm Forward Kinematics. That is a fact about the single-block rig, not a verdict on the block: an offline batch fit, a block whose output only appears at onSolverFinish, or one that needs a driven environment cannot be exercised alone.
Category unsampled · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60
Sample data: docs/generated/samples/Robotics__Planar_Kinematics__Planar_Arm_Forward_Kinematics.json