Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 21 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ on:

jobs:
build-and-test:
name: Build and test (thais_urdf)
name: Build and test (inmoov_urdf)
runs-on: ubuntu-latest
container:
image: osrf/ros:humble-desktop
image: osrf/ros:jazzy-desktop
# Colcon tree must live next to the checkout, not under it: copying $GITHUB_WORKSPACE
# into workspace/ws/... would copy a directory into its own subtree ("cannot copy into itself").
# COLCON_WS must be canonical (no ..): upload-artifact@v4 rejects paths with relative segments.
Expand All @@ -36,7 +36,8 @@ jobs:
build-essential \
cmake \
git \
gz-harmonic
ros-jazzy-ros-gz \
ros-jazzy-gz-ros2-control
# Do not rm -rf /var/lib/apt/lists/* here; rosdep uses apt next and needs indexes.
rosdep init || true
rosdep update
Expand All @@ -48,42 +49,42 @@ jobs:
run: |
set -e
mkdir -p "${COLCON_WS}/src"
cp -a "${GITHUB_WORKSPACE}" "${COLCON_WS}/src/thais_urdf"
cp -a "${GITHUB_WORKSPACE}" "${COLCON_WS}/src/inmoov_urdf"

- name: rosdep install
working-directory: ${{ env.COLCON_WS }}
shell: bash
run: |
set -e
apt-get update
source /opt/ros/humble/setup.bash
source /opt/ros/jazzy/setup.bash
rosdep install --from-paths src --ignore-src -r -y

- name: colcon build
working-directory: ${{ env.COLCON_WS }}
shell: bash
run: |
source /opt/ros/humble/setup.bash
source /opt/ros/jazzy/setup.bash
colcon build --symlink-install \
--packages-select thais_urdf \
--packages-select inmoov_urdf \
--cmake-args -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON

- name: colcon test
working-directory: ${{ env.COLCON_WS }}
shell: bash
run: |
source /opt/ros/humble/setup.bash
source /opt/ros/jazzy/setup.bash
source install/setup.bash
colcon test \
--packages-select thais_urdf \
--packages-select inmoov_urdf \
--event-handlers console_direct+ \
--pytest-args "--tb=short -vv"

- name: colcon test-result
working-directory: ${{ env.COLCON_WS }}
shell: bash
run: |
source /opt/ros/humble/setup.bash
source /opt/ros/jazzy/setup.bash
source install/setup.bash
colcon test-result --verbose

Expand All @@ -93,14 +94,14 @@ jobs:
if: success()
run: |
set -e
source /opt/ros/humble/setup.bash
source /opt/ros/jazzy/setup.bash
source install/setup.bash
mkdir -p build/coverage_reports
python3 -m pytest src/thais_urdf/test/ \
--cov=src/thais_urdf/launch \
--cov=src/thais_urdf/test \
--cov-report=xml:build/coverage_reports/thais_urdf.xml \
--cov-report=html:build/coverage_reports/html_thais_urdf \
python3 -m pytest src/inmoov_urdf/test/ \
--cov=src/inmoov_urdf/launch \
--cov=src/inmoov_urdf/test \
--cov-report=xml:build/coverage_reports/inmoov_urdf.xml \
--cov-report=html:build/coverage_reports/html_inmoov_urdf \
--cov-report=term-missing \
--cov-branch

Expand All @@ -109,15 +110,15 @@ jobs:
if: success()
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ${{ env.COLCON_WS }}/build/coverage_reports/thais_urdf.xml
flags: thais_urdf
name: thais_urdf
files: ${{ env.COLCON_WS }}/build/coverage_reports/inmoov_urdf.xml
flags: inmoov_urdf
name: inmoov_urdf
fail_ci_if_error: false

- name: Upload coverage artifacts (XML + HTML)
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-thais_urdf
name: coverage-inmoov_urdf
path: ${{ env.COLCON_WS }}/build/coverage_reports/
retention-days: 14
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# inmoov_urdf

ROS 2 **Humble** package with the **InMoov-derived** robot description used by Lucy: **URDF/xacro**, **DAE meshes**, **ros2_control** blocks, **Gazebo (gz-sim) physics**, an **RViz** layout, and **launch files** for ros2_control + RViz / Gazebo.
ROS 2 **Jazzy** (Ubuntu 24.04) package with the **InMoov-derived** robot description used by Lucy: **URDF/xacro**, **DAE meshes**, **ros2_control** blocks, **Gazebo (gz-sim) physics**, an **RViz** layout, and **launch files** for ros2_control + RViz / Gazebo.

The web control panel (rosbridge + `/config/*` services) is **not** started from here — use `lucy_bringup` (`lucy.launch.py`) or `web_ros_api.launch.py` from `lucy_ros_packages`.

Expand Down Expand Up @@ -58,7 +58,7 @@ inmoov_urdf/

## Requirements

ROS 2 Humble plus: `robot_state_publisher`, `controller_manager`, `rviz2`, `ros_gz_sim`, `ros_gz_bridge`, `gz_ros2_control`, `launch_ros`, `lucy_ros2_control`. The auto-cal script also needs **PyBullet** (already in the `lucy_ros2:humble` image, `pip` otherwise).
ROS 2 Jazzy (Ubuntu 24.04) plus: `robot_state_publisher`, `controller_manager`, `rviz2`, `ros_gz_sim`, `ros_gz_bridge`, `gz_ros2_control`, `launch_ros`, `lucy_ros2_control`. The auto-cal script also needs **PyBullet** (already in the `lucy_ros2:jazzy` image, `pip` otherwise).

```bash
rosdep install --from-paths src --ignore-src -r -y
Expand All @@ -69,7 +69,7 @@ For the control panel, also build `lucy_bringup` + `lucy_config_pipeline` (pulle
## Build

```bash
source /opt/ros/humble/setup.bash
source /opt/ros/jazzy/setup.bash
cd lucy_ws
colcon build --symlink-install --packages-select inmoov_urdf lucy_ros2_control
source install/setup.bash
Expand Down
6 changes: 3 additions & 3 deletions docs/DEVELOPER.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Developer guide — `inmoov_urdf`

ROS 2 **Humble**. For contributors who change URDF/xacro, meshes, RViz config, hardware YAML, or launch files. Bringup, hardware plugin, and cameras live in **`lucy_ros_packages`** ([Sentience-Robotics/lucy_ros_packages](https://github.com/Sentience-Robotics/lucy_ros_packages) → `docs/DEVELOPER.md`).
ROS 2 **Jazzy** (Ubuntu 24.04). For contributors who change URDF/xacro, meshes, RViz config, hardware YAML, or launch files. Bringup, hardware plugin, and cameras live in **`lucy_ros_packages`** ([Sentience-Robotics/lucy_ros_packages](https://github.com/Sentience-Robotics/lucy_ros_packages) → `docs/DEVELOPER.md`).

---

Expand Down Expand Up @@ -228,7 +228,7 @@ Flags:
- `--step-deg`, `--margin-deg` — sweep granularity / safety margin.
- `--apply` — write the limits back to `robot_description.urdf.xacro`.

PyBullet ships in the `lucy_ros2:humble` image via `Dockerfile.humble`; for host-side runs, see `scripts/requirements.txt`.
PyBullet ships in the `lucy_ros2:jazzy` image via `Dockerfile.jazzy`; for host-side runs, see `scripts/requirements.txt`.

Treat the result as an **upper bound on the kinematic envelope**, not the real end-stop. Override by hand for mechanical stops the URDF can't model (cable tension, gear stops), important poses outside the per-axis sweep from neutral, and finger meshes that overlap at the bind pose.

Expand Down Expand Up @@ -267,7 +267,7 @@ This restarts `robot_state_publisher` + `ros2_control` with the new URDF. **Cave
| `scripts/autocalibrate_joint_limits.py` | Self-collision-bound joint-limit sweep in PyBullet. Optional `--apply` to write back. | `--apply` overwrites previous auto-cal values; manual values can be re-applied on top. |
| `scripts/scale_xacro_origins.py` | One-shot maintenance: wrap raw `xyz` / primitive sizes with `${model_scale * N}`. | No — run once per migration; check the diff carefully. |

`scripts/requirements.txt` is for host-side PyBullet runs only; CI / Docker image installs it via `Dockerfile.humble`.
`scripts/requirements.txt` is for host-side PyBullet runs only; CI / Docker image installs it via `Dockerfile.jazzy`.

---

Expand Down
2 changes: 1 addition & 1 deletion docs/hardware_mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ With **SIMULATION ONLY** enabled in the activate workflow, `lucy_config_generato
- One `<ros2_control>` block per board (`gz_ros2_control/GazeboSimSystem` when `use_gazebo_sim:=true`, otherwise `lucy_ros2_control/LucySystemHardware` with `publish_actuators:=false` for RViz/mock). URDF `min`/`max` on the command interface are enforced by **LucySystemHardware** only (real + mock), not by the stock Gazebo plugin.
- `controllers.yaml` with `joint_state_broadcaster` + a single `lucy_sim_controller` listing every actuator `urdf_joint`.

After generation, `lucy_config_pipeline` calls **`/lucy_control/restart`** so the running stack reloads without a full `lucy.launch.py` restart. Structural joint changes still require that restart (Humble does not hot-swap URDF hardware topology).
After generation, `lucy_config_pipeline` calls **`/lucy_control/restart`** so the running stack reloads without a full `lucy.launch.py` restart. Structural joint changes still require that restart (ROS 2 does not hot-swap URDF hardware topology).

## Editing

Expand Down
7 changes: 3 additions & 4 deletions launch/gazebo.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,14 @@
import yaml



def _gz_ros2_control_plugin_path():
pkg_share = get_package_prefix("inmoov_urdf")
plugin_path = os.path.join(pkg_share, "lib", "mock_sensor")
try:
share = get_package_share_directory("gz_ros2_control")
return os.path.join(os.path.dirname(share), "lib") + os.pathsep + plugin_path
except Exception:
return "/opt/ros/humble/lib" + os.pathsep + plugin_path
return "/opt/ros/jazzy/lib" + os.pathsep + plugin_path


_DEFAULT_GENERATED_FILES = {
Expand Down Expand Up @@ -129,7 +128,7 @@ def _sim_camera_topics(pkg_share: str) -> list[tuple[str, str]]:


def generate_launch_description():
ros_distro = os.environ.get("ROS_DISTRO", "humble").lower()
ros_distro = os.environ.get("ROS_DISTRO", "jazzy").lower()
pkg_share = get_package_share_directory("inmoov_urdf")
default_base = os.path.join(pkg_share, "description")
generated = _active_generated_files(pkg_share)
Expand Down Expand Up @@ -247,7 +246,7 @@ def _camera_compressor(topic: str, compressed_topic: str) -> Node:
gz_sim_share = get_package_share_directory("ros_gz_sim")
gz_sim_launch_path = os.path.join(gz_sim_share, "launch", "gz_sim.launch.py")
except Exception:
gz_sim_launch_path = "/opt/ros/humble/share/ros_gz_sim/launch/gz_sim.launch.py"
gz_sim_launch_path = "/opt/ros/jazzy/share/ros_gz_sim/launch/gz_sim.launch.py"
default_world = os.path.join(pkg_share, "worlds", "default.sdf")
# When headless: server-only (-s) with EGL rendering (--headless-rendering)
# so OGRE2 still renders camera sensors without an X display. Otherwise:
Expand Down
2 changes: 1 addition & 1 deletion launch/joint_preview.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def generate_launch_description():
base_path = LaunchConfiguration("base_path")
controllers_yaml = LaunchConfiguration("controllers_yaml")

# Force value_type=str so ROS 2 launch (Humble) does not try to YAML-parse
# Force value_type=str so ROS 2 launch does not try to YAML-parse
# the xacro output. The URDF starts with `<?xml ...>`, which the YAML
# loader rejects with "Unable to parse the value of parameter robot_description".
robot_description = ParameterValue(
Expand Down
2 changes: 1 addition & 1 deletion launch/rviz.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from launch.actions import (
DeclareLaunchArgument,
)
from launch.substitutions import PathJoinSubstitution, LaunchConfiguration
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare

Expand Down
2 changes: 1 addition & 1 deletion package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<!-- No exec_depend on lucy_ros2_control: would cycle (lucy_ros2_control depends on inmoov_urdf for URDF share). Controller parameters ship in this package as config/controllers.yaml (#95). -->
<exec_depend>controller_manager</exec_depend>
<exec_depend>lucy_control_supervisor</exec_depend>
<!-- autocalibrate_joint_limits.py needs PyBullet (pip: pybullet; installed in Dockerfile.humble) -->
<!-- autocalibrate_joint_limits.py needs PyBullet (pip: pybullet; installed in Dockerfile.jazzy) -->
<exec_depend>python3-yaml</exec_depend>

<test_depend>ament_lint_auto</test_depend>
Expand Down
6 changes: 3 additions & 3 deletions scripts/autocalibrate_joint_limits.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

Usage
-----
# pybullet ships with the lucy_ros2:humble image (Dockerfile: pip install pybullet);
# pybullet ships with the lucy_ros2:jazzy image (Dockerfile.jazzy: pip install pybullet);
# host-side: pip install --user -r scripts/requirements.txt
python3 scripts/autocalibrate_joint_limits.py # headless dry run
python3 scripts/autocalibrate_joint_limits.py --apply # write back
Expand Down Expand Up @@ -96,7 +96,7 @@ def expand_urdf() -> str:
elif shutil.which("ros2"):
cmd = ["ros2", "run", "xacro", "xacro"]
else:
sys.exit("xacro not on PATH (source ROS Humble)")
sys.exit("xacro not on PATH (source ROS 2 Jazzy)")
cmd += [
str(URDF_XACRO),
f"base_path:={BASE_PATH}",
Expand Down Expand Up @@ -178,7 +178,7 @@ def setup(self, p, body, name_to_idx, cid) -> None:
except ImportError:
sys.exit(
"[--view rviz] rclpy/sensor_msgs not importable. "
"Source ROS Humble first (e.g. `source install/setup.bash`)."
"Source ROS 2 Jazzy first (e.g. `source install/setup.bash`)."
)
if not rclpy.ok():
rclpy.init()
Expand Down
2 changes: 1 addition & 1 deletion scripts/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Optional: URDF joint-limit auto-calibration (scripts/autocalibrate_joint_limits.py).
# Installed in the lucy_ros2:humble image via Dockerfile.humble (pip).
# Installed in the lucy_ros2:jazzy image via Dockerfile.jazzy (pip).
pybullet>=3.2.0
2 changes: 1 addition & 1 deletion test/xacro_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@ def run_xacro(args: Sequence[str], *, timeout: int = 120) -> subprocess.Complete
elif shutil.which("ros2"):
cmd = ["ros2", "run", "xacro", "xacro", *args]
else:
pytest.skip("xacro not on PATH (run inside lucy_ros2:humble image)")
pytest.skip("xacro not on PATH (run inside lucy_ros2:jazzy image)")
return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout, check=False)
Loading