feat: add omni_angular kinematics and body-frame velocity for omni robots#270
feat: add omni_angular kinematics and body-frame velocity for omni robots#270
Conversation
* chore(deps-dev): bump ruff from 0.15.6 to 0.15.7 (#259) Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.6 to 0.15.7. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](astral-sh/ruff@0.15.6...0.15.7) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.7 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump ty from 0.0.23 to 0.0.24 (#260) Bumps [ty](https://github.com/astral-sh/ty) from 0.0.23 to 0.0.24. - [Release notes](https://github.com/astral-sh/ty/releases) - [Changelog](https://github.com/astral-sh/ty/blob/main/CHANGELOG.md) - [Commits](astral-sh/ty@0.0.23...0.0.24) --- updated-dependencies: - dependency-name: ty dependency-version: 0.0.24 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump pytest-cov from 7.0.0 to 7.1.0 (#261) Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 7.0.0 to 7.1.0. - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - [Commits](pytest-dev/pytest-cov@v7.0.0...v7.1.0) --- updated-dependencies: - dependency-name: pytest-cov dependency-version: 7.1.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump importlib-metadata from 8.7.1 to 9.0.0 (#262) Bumps [importlib-metadata](https://github.com/python/importlib_metadata) from 8.7.1 to 9.0.0. - [Release notes](https://github.com/python/importlib_metadata/releases) - [Changelog](https://github.com/python/importlib_metadata/blob/main/NEWS.rst) - [Commits](python/importlib_metadata@v8.7.1...v9.0.0) --- updated-dependencies: - dependency-name: importlib-metadata dependency-version: 9.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(usage): add CBF-QP and collision-cone examples in 21cbf_world (#258) * feat(usage): add CBF-QP and collision-cone examples in 21cbf_world * refactor: refine to adapt to project style --------- Co-authored-by: hanruihua <hanrh@connect.hku.hk> * feat: add omni_angular kinematics model with yaw_rate integration Add a new kinematics model that extends omni with a third velocity channel (yaw_rate) so that orientation is integrated natively inside the simulation step, removing the need for external post-step hacks. * docs: add omni_angular to kinematics documentation Update README support table, YAML configuration reference, and kinematics models card to include the new omni_angular model. * fix(omni_angular): Refactor as suggested * feat(docs): update configuration for omni_angular kinematics and velocity parameters * fix(kinematics): set default alpha values for Omni and OmniAngular kinematics * fix(tests): update test description for kinematics registry to include all built-in types * doc: add chinese translation --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Xinyi WANG <49263319+Lawliet9666@users.noreply.github.com> Co-authored-by: hanruihua <hanrh@connect.hku.hk>
Change omni_kinematics and omni_angular_kinematics to accept body-frame velocity [forward, lateral] and [forward, lateral, yaw_rate] respectively. The body-to-world rotation is now handled inside the kinematics functions. Simplify OmniDash and OmniAngularDash behaviors to output body-frame velocity directly. Update velocity_to_xy and compute_heading accordingly.
Expand keyboard from 2-axis to 3-axis control [linear, lateral, angular]. W/S controls forward/backward, A/D controls lateral strafe, Q/E controls rotation. Add Shift+Z/C for max linear velocity adjustment. Simplify per-kinematics mapping in _assign_keyboard_action.
Update omni and omni_angular kinematics tests to validate body-frame velocity semantics. Update keyboard tests for Q/E rotation and Shift+Z/C linear max velocity adjustment.
Restore original A/D behavior: sets key_ang for diff/acker rotation and omni lateral movement. Q/E now sets a separate key_rot axis used only by omni_angular for yaw rate control.
…trols Update velocity descriptions from world-frame [vx, vy] to body-frame [forward, lateral] for omni and omni_angular. Add omni_angular to kinematics comparison tables. Update keyboard control key mapping docs for A/D, Q/E, and Shift+Z/C. Update Chinese translations accordingly.
Codecov Report❌ Patch coverage is
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 2 files with indirect coverage changes 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds an omni_angular kinematics model (body-frame [forward, lateral, yaw_rate]) and refactors existing omni kinematics to use body-frame [forward, lateral], alongside a 3-axis keyboard control scheme and updated docs/tests.
Changes:
- Implement
omni_angular_kinematics+OmniAngularKinematics, and refactoromnito body-frame velocity. - Redesign keyboard control to a 3-axis command and adapt env action assignment for different kinematics.
- Update behaviors (
dash), tests, usage examples, and documentation (including zh_CN translations).
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
irsim/lib/algorithm/kinematics.py |
Refactors omni_kinematics to body-frame + adds omni_angular_kinematics. |
irsim/lib/algorithm/__init__.py |
Re-exports omni_angular_kinematics. |
irsim/lib/handler/kinematics_handler.py |
Adds OmniAngularKinematics handler + updates OmniKinematics metadata/conversions. |
irsim/lib/behavior/behavior_methods.py |
Adds omni_angular dash behavior and updates OmniDash to body-frame. |
irsim/gui/keyboard_control.py |
Updates key mappings and expands keyboard command vector to 3 axes. |
irsim/env/env_base.py |
Converts 3-axis keyboard command into per-kinematics action vectors. |
tests/test_kinematics.py |
Updates omni tests for body-frame + adds omni_angular tests. |
tests/test_keyboard.py |
Updates keyboard tests for new mappings and 3-axis behavior. |
tests/test_env.py |
Adds coverage for keyboard-action assignment for omni vs omni_angular. |
tests/test_behaviors.py |
Adds/updates tests for body-frame OmniDash and OmniAngularDash behavior. |
tests/test_all_objects.py |
Updates integration-style keyboard assertions for new mappings. |
usage/09keyboard_control/keyboard_control.py |
Points example runner at the new omni_angular keyboard config. |
usage/09keyboard_control/keyboard_control_pynput_omni_angular.yaml |
Adds a new keyboard-control example for omni_angular. |
usage/02robot_world/robot_world.py |
Points example runner at the new omni_angular world config. |
usage/02robot_world/robot_omni_angular_world.yaml |
Adds a new world example for omni_angular. |
docs/source/yaml_config/configuration.md |
Documents omni_angular and body-frame velocity semantics. |
docs/source/usage/configure_robots_obstacles.md |
Updates kinematics table/definitions for omni vs omni_angular. |
docs/source/usage/configure_keyboard_Mouse_control.md |
Updates keyboard mapping documentation (including shift+z/c). |
docs/source/get_started/quick_start.md |
Updates quick-start kinematics list to include omni_angular. |
docs/locale/zh_CN/LC_MESSAGES/yaml_config/configuration.po |
Updates zh_CN strings for new kinematics/velocity semantics (partial). |
docs/locale/zh_CN/LC_MESSAGES/usage/configure_robots_obstacles.po |
Updates zh_CN usage translation for omni_angular and body-frame omni. |
docs/locale/zh_CN/LC_MESSAGES/usage/configure_keyboard_Mouse_control.po |
Updates zh_CN keyboard mapping translation. |
README.md |
Updates top-level docs to mention omni_angular. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| self.key_ang = self.key_ang_max | ||
| if key.char == "d": | ||
| self.key_ang = -self.key_ang_max |
There was a problem hiding this comment.
a/d are documented as strafe for omni/omni_angular, but the code sets key_ang using key_ang_max (the max angular velocity). This couples lateral strafe speed to the angular limit and makes shift+z/c (linear max) not affect strafing as intended. Consider using key_lv_max for the strafe axis when controlling omni/omni_angular (or otherwise separating lateral max from angular max based on the selected robot kinematics).
| self.key_ang = self.key_ang_max | |
| if key.char == "d": | |
| self.key_ang = -self.key_ang_max | |
| self.key_ang = self.key_lv_max | |
| if key.char == "d": | |
| self.key_ang = -self.key_lv_max |
| self.key_ang = self.key_ang_max | ||
| if base == "d": | ||
| self.key_ang = -self.key_ang_max |
There was a problem hiding this comment.
Same issue as the pynput backend: in the mpl backend a/d set key_ang using key_ang_max, but for omni/omni_angular this axis is lateral strafe (linear). This makes the lateral speed limit track the angular limit instead of key_lv_max and conflicts with the documented key mappings.
| self.key_ang = self.key_ang_max | |
| if base == "d": | |
| self.key_ang = -self.key_ang_max | |
| self.key_ang = self.key_lv_max | |
| if base == "d": | |
| self.key_ang = -self.key_lv_max |
| @@ -135,26 +135,97 @@ def omni_kinematics( | |||
| """ | |||
| Calculate the next position for an omnidirectional robot. | |||
|
|
|||
| Uses body-frame velocity: the two components are forward and lateral | |||
| speeds relative to the robot heading (theta). Since omni robots have | |||
| no yaw control, theta remains unchanged. | |||
|
|
|||
| Args: | |||
| state: A 2x1 vector [x, y] representing the current position. | |||
| velocity: A 2x1 vector [vx, vy] representing the current velocities. | |||
| state: A 3x1 vector [x, y, theta] representing the current state. | |||
| velocity: A 2x1 vector [forward, lateral] in body frame. | |||
| step_time: The time step for the simulation. | |||
There was a problem hiding this comment.
omni_kinematics now enforces state.shape[0] >= 3 via @validate_shape(state=3, ...), which will raise at runtime for any existing callers passing a 2D [x, y] state (previously accepted). If backward compatibility is desired, consider accepting 2D state by treating missing theta as 0 (or explicitly migrating callers and updating any docs that still claim [x, y] is allowed).
| state: [5, 5, 1, 0] | ||
| goal: [40, 40, 0] | ||
| vel_max: [3.0, 3.0, 3.0] # [v_x, v_y, angular] | ||
| vel_min: [-3.0, -3.0, -3.0] # [v_x, v_y, angular] |
There was a problem hiding this comment.
This example config uses a 4-element state: [5, 5, 1, 0], but omni_angular kinematics/state are 3D ([x, y, theta]). The extra element will be truncated/padded implicitly, which is confusing for users. Also the vel_max/vel_min comments still refer to [v_x, v_y, angular] rather than body-frame [forward, lateral, yaw_rate].
| state: [5, 5, 1, 0] | |
| goal: [40, 40, 0] | |
| vel_max: [3.0, 3.0, 3.0] # [v_x, v_y, angular] | |
| vel_min: [-3.0, -3.0, -3.0] # [v_x, v_y, angular] | |
| state: [5, 5, 1] | |
| goal: [40, 40, 0] | |
| vel_max: [3.0, 3.0, 3.0] # [forward, lateral, yaw_rate] | |
| vel_min: [-3.0, -3.0, -3.0] # [forward, lateral, yaw_rate] |
| next_state = omni_angular_kinematics(state, velocity, 1.0) | ||
| assert np.allclose(next_state, np.array([[0], [1], [np.pi / 2]]), atol=1e-10) | ||
|
|
||
| # Test lateral movement at theta=0 (lateral = -y in world... no, +y) |
There was a problem hiding this comment.
The inline comment here reads like an edit note ("... no, +y") and is likely unintentional. Please clean it up to avoid confusion about the sign convention for lateral motion.
| # Test lateral movement at theta=0 (lateral = -y in world... no, +y) | |
| # Test lateral movement at theta=0 (lateral = +y in world) |
| #: ../../source/yaml_config/configuration.md:1195 | ||
| msgid "" | ||
| "**Kinematics and Velocities**: Ensure that the `velocity` and `vel_max` " | ||
| "parameters match the kinematics model. For example, a differential drive " | ||
| "robot (`'diff'`) should have velocities in `[v, omega]`, while an " | ||
| "omnidirectional robot (`'omni'`) uses `[vx, vy]`." | ||
|
|
||
| msgstr "" | ||
| "**运动学与速度**:确保 `velocity` 与 `vel_max` 的格式与运动学模型匹配,例如差速 (`'diff'`) 使用 `[v, " | ||
| "omega]`,全向 (`'omni'`) 使用 `[vx, vy]`。" |
There was a problem hiding this comment.
This translated string still describes omni velocity as world-frame [vx, vy], but the PR changes omni to body-frame [forward, lateral] and adds omni_angular. The zh_CN translation should be updated to match the new semantics (and ideally regenerated from the updated source gettext catalogs so msgid/msgstr stay in sync).
Resolves #214
Summary
omni_angularkinematics model: adds a 3-DOF omnidirectional robot type with independent yaw rate control. Velocity is[forward, lateral, yaw_rate]in body frame, allowing the robot to translate and rotate simultaneously.omnikinematics to body-frame velocity: the existingomnimodel now takes[forward, lateral]in body frame (relative to the robot's heading) instead of world-frame[vx, vy]. The heading (theta) is preserved in state but no longer directly controllable — useomni_angularif yaw control is needed.omni_angulardash behavior: navigates to a goal using body-frame forward/lateral movement while turning to face the target, then rotates in place to match the goal orientation.robot_omni_angular_world.yamlandkeyboard_control_pynput_omni_angular.yamlfor the new kinematics type.Test plan
test_kinematics.pyupdated with body-frame omni and new omni_angular teststest_keyboard.pyupdated for 3-axis key_vel and new key mappingstest_all_objects.pyupdated to include omni_angular robot typepytest tests/)