EOM 3DOF Body Axes — Robotics/Equations Of Motion
Robotics/Equations_Of_Motion/EOM_3DOF_Body_Axes · 3 input / 4 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.
EOM 3DOF Body Axes
Robotics / Equations Of Motion
The longitudinal equations of motion of a rigid body of fixed mass, carried in body axes. With the body velocity [u; w], the pitch rate q, the pitch attitude θ and the earth-frame position [xe; ze]:
- u' = Fx/m − q·w − g·sin θ
- w' = Fz/m + q·u + g·cos θ
- q' = M/Iyy, θ' = q
- xe' = u·cos θ + w·sin θ, ze' = −u·sin θ + w·cos θ
Ports
- Fx – the force along the body x axis, a scalar [1,1].
- Fz – the force along the body z axis (positive down), a scalar [1,1].
- M – the pitching moment about the centre of gravity, a scalar [1,1].
- theta – the pitch attitude θ in radians, [1,1].
- q – the pitch rate in rad/s, [1,1].
- Xe – the position [xe; ze] in the flat-earth frame, [2,1].
- Vb – the body velocity [u; w], [2,1].
Parameters
- Units – Metric (MKS) (the default) or English (velocity in ft/s). The two are the same arithmetic – the gravity is a parameter – so the choice only says which units the numbers are in.
- Initial Airspeed – V0, a scalar. Defaults to 100.
- Initial Pitch Attitude – θ0 in radians. Defaults to 0.
- Initial Body Rotation Rate – q0 in rad/s. Defaults to 0.
- Initial Incidence – α0 in radians: the initial body velocity is V0·[cos α0; sin α0]. Defaults to 0.
- Initial Position [x z] – the initial [xe ze], two values. Defaults to [0 0].
- Mass – m, a scalar > 0. Defaults to 1.
- Inertia – Iyy, a scalar > 0. Defaults to 1.
- Gravity – g, a scalar. Defaults to 9.81.
- Integration Substeps – M, how many fourth-order Runge-Kutta steps a sample is integrated with on the discrete solver and in exported code, a whole number of 1 or more. Defaults to 100. No Simulink counterpart.
- 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. A core holds the six states, publishes the four outputs from them, and integrates one sample with the inputs held and M Runge-Kutta substeps – with M = 100, the same computation as Simulink's fixed-step ode4 at one hundredth of the sample time. The mass, inertia, gravity and substep are folded to constants; a core does 4·M derivative evaluations per sample.
The three HDL targets are simulation-only real
arithmetic, quantized at the port: a sine of a state has no Q16.16 form. The cores
simulate correctly and are not offered as synthesizable.
Simulink bridge
Import and export, mapped to Aerospace Blockset's
aerolib3dof2/3dof (Body Axes): Units → units
(the two offered values 1:1), Initial Airspeed → v_ini,
Initial Pitch Attitude → theta_ini, Initial Body
Rotation Rate → q_ini, Initial Incidence →
alpha_ini, Initial Position [x z] → pos_ini,
Mass → mass, Inertia → Iyy and
Gravity → g. Always emitted with axes =
Body, mtype = Fixed, g_in =
Internal and vre_flag and mass_flag off: each
of those moves that block's port list, and this block has one. The knots unit
system is not offered – it converts velocities inside the integration
– and an imported one is reported. "Sampling Time (s)" does not
cross: the Simulink block is continuous and defines no
SampleTime.
Notes
- Stateful, continuous and nonlinear: six continuous states. The outputs are states, so the block has no direct feedthrough and a loop through it is not an algebraic loop.
- Variable mass, an external gravity and a relative-velocity input are the Simulink block's other port shapes and are not offered here.
Code facts#
| Fact | Value |
|---|---|
| registered type | Robotics/Equations_Of_Motion/EOM_3DOF_Body_Axes |
| family | Robotics/Equations_Of_Motion |
| solver environment class | ICoreBlock_0_Robotics_1_Equations_Of_Motion_2_EOM_3DOF_Body_Axes |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Equations_Of_Motion/EOM_3DOF_Body_Axes/ICoreBlock_0_Robotics_1_Equations_Of_Motion_2_EOM_3DOF_Body_Axes.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Equations_Of_Motion/EOM_3DOF_Body_Axes/ICoreBlock_0_Robotics_1_Equations_Of_Motion_2_EOM_3DOF_Body_Axes.h |
| default size on canvas | 130 × 110 px |
| ports at insert | 3 in, 4 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 | Fx |
| 2 | in | ICoreDouble | Fz |
| 3 | in | ICoreDouble | M |
| 4 | out | ICoreDouble | theta |
| 5 | out | ICoreDouble | q |
| 6 | out | ICoreDouble | Xe |
| 7 | out | ICoreDouble | Vb |
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 |
|---|---|---|
Units | Metric (MKS)%~%English (velocity in ft/s)~~Metric (MKS) | units |
Initial Airspeed | 100 | v_ini |
Initial Pitch Attitude | 0 | theta_ini |
Initial Body Rotation Rate | 0 | q_ini |
Initial Incidence | 0 | alpha_ini |
Initial Position [x z] | [0 0] | pos_ini |
Mass | 1.0 | mass |
Inertia | 1.0 | Iyy |
Gravity | 9.81 | g |
Integration Substeps | 100 | not crossed |
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::Both |
| Simulink path | aerolib3dof2/3dof (Body Axes) |
| port-count rule | PortsParam::None |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
| deliberately not crossed | Integration Substeps |
| always set | axes = Body, mtype = Fixed, g_in = Internal, vre_flag = off, mass_flag = off |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Units | units | Metric (MKS) → Metric (MKS), English (velocity in ft/s) → English (velocity in ft/s) |
Initial Airspeed | v_ini | passes through |
Initial Pitch Attitude | theta_ini | passes through |
Initial Body Rotation Rate | q_ini | passes through |
Initial Incidence | alpha_ini | passes through |
Initial Position [x z] | pos_ini | passes through |
Mass | mass | passes through |
Inertia | Iyy | passes through |
Gravity | g | passes through |
Caveat (shown to the user): aerolib3dof2/3dof (Body Axes) is continuous and has NO SampleTime parameter (verified against the R2026a block dialog). axes, mtype, g_in, vre_flag and mass_flag are pinned because each moves that block's port list; the kts unit system is not offered because it converts velocities inside the integration; "Integration Substeps" is how this block integrates a sample and has no counterpart
Catalog contract: src/ICoreBlocks/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The lists agree. check_block_descriptions.py finds no disagreement between the description's Ports, Parameters, Code export and Simulink bridge lists and the code's.
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).
3dof (Body Axes) — longitudinal rigid-body equations of motion, fixed mass State [u w q theta xe ze], inputs Fx, Fz (body axes) and M (pitching moment):
u' = (Fx/m - q*w) - g*sin(theta) xe' = u*cos(theta) + w*sin(theta) w' = (Fz/m + q*u) + g*cos(theta) ze' = (-u)*sin(theta) + w*cos(theta) q' = M/Iyy theta' = q
⚠ MEASURED AGAINST R2026a, and the block cannot be read: aerolib3dof2/3dof (Body Axes) is a compiled EOM3DOFNoAccel block, not a masked subsystem. Integrated with ode4 at 1e-4 for 0.5 s from a non-trivial state under constant forces, the six equations above reproduce all four of its outputs to EVERY printed digit (theta 0.3472222222222236, xe 6.6404055312933732, u 9.9343039587580009 ...). Four more things that measurement settled:
- The outputs are theta, q, [xe ze] and [u w] -- four ports, no acceleration: the
"NoAccel" in the block type is literal; the accelerations are the 3DOF Acceleration block.
- The initial body velocity is V0*[cos(alpha0); sin(alpha0)] -- the dialog's airspeed and
incidence, not u and w.
- "Metric" and "English (velocity in ft/s)" are the SAME arithmetic (g is a parameter, so the
unit system only renames things); "kts" converts velocities inside the integration, and is not offered here -- an imported kts value is reported rather than silently mis-integrated.
- mtype, g_in and the two optional flags MOVE the port list; each is pinned (fixedParams).
A continuous block with a real derivative (joint integration answers "yes" to all three of §4's questions: continuous states, a pure output, no direct feedthrough). The discrete solver path and every exported core run ICoreEomRk4's map: the input held across a sample and M RK4 substeps -- which at M = 100 is Simulink's fixed-step ode4 at Ts/100, step for step.
Sample results#
The same rig also ran:
| Stimulus | What it is | Output range |
|---|---|---|
impulse | Impulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair) | 0 … 0.535 |
ramp | Ramp: slope 1 from t = 0 | 0 … 34.23 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | 0 … 3.123 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | -0.17 … 4.518 |
Plotted: step — Step: 0 -> 1 at t = 1 s
Category dynamic · sample time 0.1 · 60 steps · commit 7a143da00 · produced by docsSample --out <folder> --blocks EOM_3DOF_Body_Axes EOM_3DOF_Wind_Axes Point_Mass_Longitudinal Point_Mass_Coordinated_Flight Acceleration_3DOF --steps 60 · data docs/generated/samples/Robotics__Equations_Of_Motion__EOM_3DOF_Body_Axes.json · the SVG is generated from those numbers by tools/docs/plot_svg.py, so it is a run and not a drawing (R-D10).