-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/real arm urdf import #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
richardnguyen165
wants to merge
37
commits into
main
Choose a base branch
from
feature/real-arm-urdf-import
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
e73e3d4
Setup clean Waybionic foundation and placeholder arm
Haroldmin1028 77bacc9
Add build instructions for basic robot setup
Haroldmin1028 03cfd84
Managed to get the urdf working, but still waiting
f4e60a0
Clean foundation PR, automate RViz launch
Haroldmin1028 3c8b930
Got latest STL files fromNoah
3237c6f
Created readme file for documentation
461ad64
Address PR comments, ignore Annin packages, fix display.launch.py
Haroldmin1028 fcce00e
Add ignore file for external annin package
Haroldmin1028 ee099be
Python files for testing
e757099
Merge branch 'rebuild/waybionic-foundation' into waybionic_arm_demo_v2
723cb03
Revert "Merge branch 'rebuild/waybionic-foundation' into waybionic_ar…
be22501
Reverted the merge, created a file that shows all the parts
c014417
Deleted old annin packages, updates BuildInstructions.md, added meshe…
Haroldmin1028 1d9709a
Reapply "Merge branch 'rebuild/waybionic-foundation' into waybionic_a…
ab3c142
Merge remote-tracking branch 'origin/rebuild/waybionic-foundation' in…
fd78b2a
Updated model import checklist (task #6)
4bccbb2
Mechanical team requirements laid out - must send the URDF file for t…
d8513ca
Updated demanded version of urdf
ad4f4b4
Merge remote-tracking branch 'origin/main' into waybionic_arm_demo_v2
9b13b38
Merge pull request #3 from Waybionic/waybionic_arm_demo_v2
richardnguyen165 2fd5d5a
Add real-arm URDF exported from SolidWorks + launch fixes
93d481a
Merge remote-tracking branch 'origin/main' into feature/real-arm-urdf…
fc6acde
Merge remote-tracking branch 'origin/main' into feature/real-arm-urdf…
32f8481
Deleted the unused STL parts.
a8cf615
Deleted old markdown files.
00dc68a
Restored placeholder urdf file.
a6ce2ca
Added KDL, updated documentation to include testing instructions.
298f707
Added dummy link.
611d93d
Fixed up moveit config to demonstrate basic movement
95219a1
Merge remote-tracking branch 'origin/main' into feature/real-arm-urdf…
1911f30
Add interactive XYZ inverse kinematics demo
yassinsolim e80e397
Center arm model on RViz ground plane
yassinsolim 80c6c4f
Polish and verify the IK demo
yassinsolim 5c283ae
Fix model verification commands
yassinsolim cd9acea
Abort IK demo when a target fails
yassinsolim 6dc9b3e
Harden model verification checks
yassinsolim d84b943
Harden IK demo and arm model validation
yassinsolim File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,220 @@ | ||
| # Waybionic Model Import Runbook | ||
| # Waybionic Model Import & Validation Runbook | ||
|
|
||
| This guide is for importing and testing real URDF and mechanical mesh exports (STLs) without breaking the clean ROS 2 foundation or editing Python launch files. | ||
| How to import, run, and validate a robot model in this workspace without editing | ||
| the launch files. Run every command from the **workspace root** — the folder | ||
| containing `waybionic_bringup/` and `waybionic_description/`. | ||
|
|
||
| ## 1. Where to put the files | ||
| - **Meshes (.stl, .dae):** Place all 3D mesh files into `waybionic_description/meshes/`. | ||
| - **URDF/Xacro (.urdf, .xacro):** Place your exported robot description file into `waybionic_description/urdf/`. | ||
| ## Models in this package | ||
|
|
||
| *Important: Inside the URDF, ensure the mesh paths use the standard ROS package syntax. Example:* | ||
| `<mesh filename="package://waybionic_description/meshes/base_link.stl"/>` | ||
| Both live in `waybionic_description/urdf/`: | ||
|
|
||
| ## 2. Rebuild the Workspace | ||
| Any time new files are added, rebuild the foundation so CMake can install them to the ROS 2 share directory. | ||
| From the root of your workspace (`~/waybionic_ws`): | ||
| ``` | ||
| colcon build --packages-select waybionic_description | ||
| | File | Role | Meshes | | ||
| |------|------|--------| | ||
| | `full_arm_mar24.urdf` | **Default.** The real arm — a 5-link serial chain `base_link → shoulder → elbow → forearm → wrist` with articulated (revolute/continuous) joints. | 5 STLs in `meshes/` | | ||
| | `waybionic_placeholder.urdf` | Fallback / test asset. A primitive box + cylinder on one revolute joint. | **None** — pure URDF primitives, always loads | | ||
|
|
||
| The real arm's meshes are the only files kept in `waybionic_description/meshes/`: | ||
| `base_link.STL`, `shoulder.STL`, `elbow.STL`, `forearm.STL`, `wrist.STL`. | ||
|
|
||
| ## 1. Import files | ||
|
|
||
| - **URDF/Xacro** (`.urdf`, `.xacro`) → `waybionic_description/urdf/` | ||
| - **Meshes** (`.stl`, `.dae`) → `waybionic_description/meshes/` | ||
|
|
||
| Inside the URDF, reference meshes with the ROS package path, e.g. | ||
| `<mesh filename="package://waybionic_description/meshes/base_link.STL"/>`. | ||
|
|
||
| ## 2. Build | ||
|
|
||
| These are `ament_cmake` packages that *copy* files into `install/` at build | ||
| time, so **rebuild after any change** to a URDF, mesh, or launch file — edits in | ||
| the source tree are invisible to `ros2 launch` until you do. | ||
|
|
||
| ```bash | ||
| source /opt/ros/jazzy/setup.bash | ||
| colcon build --packages-select waybionic_description waybionic_bringup | ||
| source install/setup.bash | ||
| ``` | ||
|
|
||
| ## 3. Test the model | ||
| Don't edit `display.launch.py` to test the model. Instead, pass the path to the new URDF using the `model:=` argument. | ||
| From the root of your workspace, run: | ||
| If packages were renamed/removed (e.g. after a merge), do a clean rebuild so | ||
| stale copies don't linger: `rm -rf build install log && colcon build`. | ||
|
|
||
| ## 3. Run | ||
|
|
||
| `display.launch.py` defaults to the real arm and opens RViz (pre-configured with | ||
| `waybionic.rviz`) plus the Joint State Publisher GUI for driving the joints. | ||
|
|
||
| ```bash | ||
| # Real arm (default) | ||
| ros2 launch waybionic_bringup display.launch.py | ||
|
|
||
| # Placeholder (fallback / test) — needs no meshes | ||
| ros2 launch waybionic_bringup display.launch.py \ | ||
| model:=$(ros2 pkg prefix waybionic_description --share)/urdf/waybionic_placeholder.urdf | ||
|
|
||
| # Any other model — no need to edit the launch file | ||
| ros2 launch waybionic_bringup display.launch.py \ | ||
| model:=$(ros2 pkg prefix waybionic_description --share)/urdf/YOUR_FILE.urdf | ||
| ``` | ||
| ros2 launch waybionic_bringup display.launch.py model:=$(ros2 pkg prefix waybionic_description --share)/urdf/YOUR_NEW_FILE.urdf | ||
|
|
||
| The `model` argument accepts a plain `.urdf` (read directly) or a `.xacro` | ||
| (expanded via `xacro`). If a model doesn't appear, errors print in the terminal. | ||
|
|
||
| ## 4. Test & validate | ||
|
|
||
| Run these from the workspace root after building. Steps 4.1–4.4 are automated | ||
| (no GUI); 4.5 is the manual RViz/joint check. Expected results below are from the | ||
| last verified run. | ||
|
|
||
| ### 4.1 Structural check — `check_urdf` | ||
|
|
||
| Needs `liburdfdom-tools` (`sudo apt install liburdfdom-tools`). | ||
|
|
||
| ```bash | ||
| check_urdf install/waybionic_description/share/waybionic_description/urdf/full_arm_mar24.urdf | ||
| check_urdf install/waybionic_description/share/waybionic_description/urdf/waybionic_placeholder.urdf | ||
| ``` | ||
|
|
||
| **Expect:** `Successfully Parsed XML` and, for the arm, **`root Link: world`** with | ||
| the chain `world → base_link → shoulder → elbow → forearm → wrist`. The `world` | ||
| root is what stops KDL from ignoring `base_link`'s inertia — if the root prints as | ||
| `base_link`, the massless `world` root link is missing. | ||
|
|
||
| ### 4.2 Build + unit tests | ||
|
|
||
| ```bash | ||
| colcon build # or select the description, bringup, MoveIt, and RViz packages | ||
| colcon test | ||
| colcon test-result --all | ||
| ``` | ||
| If parsed correctly, RViz will automatically open and display the model. If there are issues, errors will print in the terminal. | ||
|
|
||
| **Expect:** build finishes with no errors; `colcon test-result` ends with | ||
| `0 errors, 0 failures` (last run: **52 tests, 0 failures** across the workspace). | ||
|
|
||
| ### 4.3 KDL root-inertia check (headless) | ||
|
|
||
| Confirms the "root link has inertia — KDL ignores it" warning is gone. | ||
|
|
||
| ```bash | ||
| if ! rsp_prefix="$(ros2 pkg prefix robot_state_publisher 2>&1)"; then | ||
| printf '%s\n' "$rsp_prefix" | ||
| echo "ERROR — robot_state_publisher package is unavailable" | ||
| exit 1 | ||
| fi | ||
| rsp_executable="$rsp_prefix/lib/robot_state_publisher/robot_state_publisher" | ||
| if [ ! -x "$rsp_executable" ]; then | ||
| echo "ERROR — robot_state_publisher executable is missing" | ||
| exit 1 | ||
| fi | ||
|
|
||
| kdl_log="$(mktemp)" | ||
| "$rsp_executable" \ | ||
| install/waybionic_description/share/waybionic_description/urdf/full_arm_mar24.urdf \ | ||
| >"$kdl_log" 2>&1 & | ||
| kdl_pid=$! | ||
| sleep 5 | ||
| if kill -0 "$kdl_pid" 2>/dev/null; then | ||
| kdl_was_running=true | ||
| kill -INT "$kdl_pid" 2>/dev/null || kdl_was_running=false | ||
| else | ||
| kdl_was_running=false | ||
| fi | ||
| if wait "$kdl_pid" 2>/dev/null; then | ||
| kdl_status=0 | ||
| else | ||
| kdl_status=$? | ||
| fi | ||
| kdl_output="$(cat "$kdl_log")" | ||
| rm -f "$kdl_log" | ||
| printf '%s\n' "$kdl_output" | ||
| if [ "$kdl_was_running" != true ] \ | ||
| || { [ "$kdl_status" -ne 0 ] && [ "$kdl_status" -ne 130 ]; }; then | ||
| echo "ERROR — robot_state_publisher exited unexpectedly (status $kdl_status)" | ||
| exit 1 | ||
| elif ! printf '%s\n' "$kdl_output" | grep -q 'Robot initialized'; then | ||
| echo "ERROR — robot_state_publisher did not initialize within 5 seconds" | ||
| exit 1 | ||
| elif printf '%s\n' "$kdl_output" | grep -qiE 'root link.*inertia|KDL.*inertia'; then | ||
| echo "ERROR — KDL root-inertia warning found" | ||
| exit 1 | ||
| else | ||
| echo "OK — no KDL root-inertia warning" | ||
| fi | ||
| ``` | ||
|
|
||
| **Expect:** `OK — no KDL root-inertia warning` and `Robot initialized`. | ||
|
|
||
| ### 4.4 Part & mesh audit (simulation running in another terminal) | ||
|
|
||
| Don't count parts by eye — they range from a ~30 cm housing to a few-mm screw. | ||
|
|
||
| ```bash | ||
| if ! robot_description="$( | ||
| ros2 param get /robot_state_publisher robot_description 2>&1 | ||
| )"; then | ||
| printf '%s\n' "$robot_description" | ||
| echo "ERROR — could not read the live robot_description parameter" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Robot links in the LIVE model loaded by RViz, excluding only the world frame | ||
| printf '%s\n' "$robot_description" \ | ||
| | grep -oE '<link name="[^"]+"' | sed -E 's/<link name="//;s/"//' \ | ||
| | grep -vE '^world$' | wc -l | ||
|
|
||
| # Confirm every referenced mesh exists in the installed package RViz is using | ||
| if ! description_share="$(ros2 pkg prefix --share waybionic_description 2>&1)"; then | ||
| printf '%s\n' "$description_share" | ||
| echo "ERROR — installed waybionic_description package is unavailable" | ||
| exit 1 | ||
| fi | ||
| mesh_root="$description_share/meshes" | ||
| mesh_names="$( | ||
| printf '%s\n' "$robot_description" \ | ||
| | grep -oE 'meshes/[^"]+\.STL' | sed 's#meshes/##' | sort -u | ||
| )" | ||
| if [ -z "$mesh_names" ]; then | ||
| echo "ERROR — live robot_description does not reference any STL meshes" | ||
| exit 1 | ||
| fi | ||
| missing_mesh=false | ||
| while IFS= read -r m; do | ||
| if [ -f "$mesh_root/$m" ]; then | ||
| echo "OK $m" | ||
| else | ||
| echo "MISS $m" | ||
| missing_mesh=true | ||
| fi | ||
| done <<< "$mesh_names" | ||
| [ "$missing_mesh" = false ] || exit 1 | ||
| ``` | ||
|
|
||
| A missing mesh still parses and still counts as a link — it just renders | ||
| invisibly — so check disk presence separately. | ||
|
|
||
| ### 4.5 Joint check (RViz + Joint State Publisher GUI) | ||
|
|
||
| ```bash | ||
| ros2 launch waybionic_bringup display.launch.py | ||
| ``` | ||
|
|
||
| Drive the bounded revolute sliders through their full ranges and move continuous | ||
| `joint3` through representative positive and negative angles. Confirm each link | ||
| rotates about the intended axis. Movable joints in `full_arm_mar24.urdf` (all | ||
| axis `[0 0 1]`, placeholder limits `effort=100 velocity=1`): | ||
|
|
||
| | Joint | Type | Moves | Range | Notes / known limitations | | ||
| |-------|------|-------|-------|---------------------------| | ||
| | `joint1` | revolute | `base_link → shoulder` | ±3.14 rad | limits are exporter defaults, not real RoM | | ||
| | `joint2` | revolute | `shoulder → elbow` | ±3.14 rad | limits are exporter defaults, not real RoM | | ||
| | `joint3` | continuous | `elbow → forearm` | unbounded | `continuous` = no limit; bound it if the real joint is limited | | ||
| | `joint4` | revolute | `forearm → wrist` | ±3.14 rad | wrist is a **differential** (pitch+roll) modeled as one joint — may need 2 | | ||
|
|
||
| `world_to_base` is `fixed` (not movable). Record any joint that rotates the wrong | ||
| way (bad `<axis>`) or exceeds its true range **by exact joint name**. | ||
|
|
||
| --- | ||
|
|
||
| *Model provenance:* `full_arm_mar24.urdf` was exported from the | ||
| `full-arm-mar24.SLDASM` SolidWorks assembly via the `sw2urdf` exporter. Joint | ||
| axes and limits are authored in the URDF (they can't be recovered from STLs). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # WayBionic MoveIt demo | ||
|
|
||
| The canonical setup and operating guide lives with the package: | ||
| [`waybionic_moveit_config/README.md`](../waybionic_moveit_config/README.md). | ||
|
|
||
| Use the MoveIt launch when you need planning, position-only IK, collision | ||
| checking, or mock trajectory execution: | ||
|
|
||
| ```bash | ||
| ros2 launch waybionic_moveit_config demo.launch.py | ||
| ``` | ||
|
|
||
| The lighter `waybionic_bringup/display.launch.py` only displays the robot and | ||
| jogs individual joints. Do not run both launches together because they publish | ||
| competing joint states. | ||
|
|
||
| The MoveIt demo supplies the semantic robot description, mock ros2_control | ||
| hardware, controllers, planner, RViz MotionPlanning UI, and an XYZ IK replay | ||
| service. Click **Replay XYZ Demo** in RViz, or start the launch with | ||
| `auto_demo:=true`. The arm has four degrees of freedom, so its IK intentionally | ||
| solves position (XYZ) rather than an arbitrary six-degree-of-freedom pose. | ||
|
|
||
| Visuals use the imported STL files. Collision checking uses conservative boxes | ||
| and cylinders so both macOS and Ubuntu avoid loading high-resolution meshes into | ||
| FCL. See the package README for limitations and test commands. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| """Regression checks for the imported full-arm model.""" | ||
|
|
||
| from pathlib import Path | ||
| import struct | ||
| import xml.etree.ElementTree as ET | ||
|
|
||
|
|
||
| PACKAGE_ROOT = Path(__file__).resolve().parent.parent | ||
|
|
||
|
|
||
| def _binary_stl_bounds(path): | ||
| """Return the axis-aligned bounds of a binary STL.""" | ||
| data = path.read_bytes() | ||
| triangle_count = struct.unpack_from('<I', data, 80)[0] | ||
| assert len(data) == 84 + triangle_count * 50 | ||
|
|
||
| bounds_min = [float('inf')] * 3 | ||
| bounds_max = [float('-inf')] * 3 | ||
| for triangle_index in range(triangle_count): | ||
| offset = 84 + triangle_index * 50 + 12 | ||
| coordinates = struct.unpack_from('<9f', data, offset) | ||
| for coordinate_index, value in enumerate(coordinates): | ||
| axis = coordinate_index % 3 | ||
| bounds_min[axis] = min(bounds_min[axis], value) | ||
| bounds_max[axis] = max(bounds_max[axis], value) | ||
| return bounds_min, bounds_max | ||
|
|
||
|
|
||
| def test_base_center_of_mass_is_inside_its_mesh_bounds(): | ||
| """Keep the base inertia origin in the mesh/link coordinate frame.""" | ||
| urdf_path = PACKAGE_ROOT / 'urdf' / 'full_arm_mar24.urdf' | ||
| root = ET.parse(urdf_path).getroot() | ||
| base_link = root.find('link[@name="base_link"]') | ||
| assert base_link is not None | ||
|
|
||
| inertial_origin = base_link.find('inertial/origin') | ||
| assert inertial_origin is not None | ||
| center_of_mass = [ | ||
| float(value) | ||
| for value in inertial_origin.get('xyz').split() | ||
| ] | ||
|
|
||
| mesh_path = PACKAGE_ROOT / 'meshes' / 'base_link.STL' | ||
| bounds_min, bounds_max = _binary_stl_bounds(mesh_path) | ||
| assert all( | ||
| lower <= coordinate <= upper | ||
| for coordinate, lower, upper in zip( | ||
| center_of_mass, | ||
| bounds_min, | ||
| bounds_max, | ||
| ) | ||
| ), ( | ||
| f'base COM {center_of_mass} is outside its mesh bounds ' | ||
| f'{bounds_min} .. {bounds_max}' | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.