Skip to content

Commit 8603d60

Browse files
authored
Add support for mimic tags in URDFs (#9)
1 parent 227d504 commit 8603d60

File tree

11 files changed

+114
-9
lines changed

11 files changed

+114
-9
lines changed

.cruft.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"template": "https://github.com/UrbanMachine/create-ros-app.git",
3-
"commit": "5d14b64b8a4c2ac85f57a19dd962216de9c7a28a",
3+
"commit": "3d4731e5661e8cbac11d71c60c8e925a989c150c",
44
"checkout": null,
55
"context": {
66
"cookiecutter": {

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
*.mp3 filter=lfs diff=lfs merge=lfs -binary
1818
*.mp4 filter=lfs diff=lfs merge=lfs -binary
1919
*.ogg filter=lfs diff=lfs merge=lfs -binary
20+
*.dae filter=lfs diff=lfs merge=lfs -binary
21+
*.usd filter=lfs diff=lfs merge=lfs -binary
22+
2023
# ReadTheDocs does not support Git LFS
2124
docs/** !filter !diff !merge binary
2225

launch-profiles/node_helpers_showcase/parameters/parameters.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ example_node_namespace:
99
ExampleNode:
1010
ros__parameters:
1111
root_config:
12-
publish_value: "hello"
13-
publish_hz: 10.0
12+
forklift_speed: 0.25
13+
forklift_max_extent: 0.5
1414

1515
urdf_arrangement:
1616
interactive_transform_publisher:
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""This module demonstrates how to define a `node_helpers` URDFConstants object for a
2+
basic URDF, specify necessary joint and frame names, and register the URDF with the
3+
`node_helpers` package.
4+
5+
By registering it, the URDF can be accessed _by name_ in configuration files.
6+
"""
7+
8+
from typing import NamedTuple
9+
10+
from node_helpers.urdfs import URDFConstants
11+
12+
13+
class ForkliftJoints(NamedTuple):
14+
FORKS: str = "forks"
15+
FORKS_PARENT_DATUM: str = "forks_parent_datum"
16+
17+
18+
class ForkliftFrames(NamedTuple):
19+
BASE_LINK: str = "forklift_body"
20+
21+
# Joint tracking
22+
FORKS_ORIGIN: str = "forks_origin"
23+
FORKS: str = "forks"
24+
25+
26+
ForkliftURDF = URDFConstants[ForkliftJoints, ForkliftFrames](
27+
from_package="node_helpers",
28+
registration_name="forklift",
29+
urdf_paths=[(None, "sample_urdfs/forklift/robot.urdf")],
30+
joints=ForkliftJoints(),
31+
frames=ForkliftFrames(),
32+
)

pkgs/node_helpers/node_helpers/nodes/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
TransformModel,
66
TransformsFile,
77
)
8+
from .node_helpers_node import ExampleNode
89
from .sound_player import SoundPlayer
910

1011
__all__ = [
1112
"HelpfulNode",
13+
"ExampleNode",
1214
"InteractiveTransformPublisher",
1315
"TransformModel",
1416
"TransformsFile",
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""This is a total example node to show off some simple node_helpers features. It's not
2+
meant to be a comprehensive example, but rather a simple one to show off some of the
3+
features of the node_helpers package.
4+
"""
5+
6+
from typing import Any
7+
8+
from pydantic import BaseModel
9+
from rclpy.qos import qos_profile_services_default
10+
from sensor_msgs.msg import JointState
11+
12+
from node_helpers.example_urdf import ForkliftURDF
13+
from node_helpers.nodes import HelpfulNode
14+
from node_helpers.spinning import create_spin_function
15+
16+
17+
class ExampleNode(HelpfulNode):
18+
class Parameters(BaseModel):
19+
# Define your ROS parameters here
20+
forklift_speed: float # m/s
21+
forklift_max_extent: float
22+
23+
def __init__(self, **kwargs: Any):
24+
super().__init__("ExampleNode", **kwargs)
25+
# Load parameters from the ROS parameter server
26+
self.params = self.declare_from_pydantic_model(self.Parameters, "root_config")
27+
self.urdf = ForkliftURDF.with_namespace(self.get_namespace())
28+
29+
# Track the forks position and direction, so we can move them up and down
30+
self.forklift_position = 0.0
31+
self.forklift_direction = 1
32+
33+
# Create publishers
34+
self.joint_state_publisher = self.create_publisher(
35+
JointState, "desired_joint_states", qos_profile_services_default
36+
)
37+
38+
# Create a timer to publish joint values
39+
self._publish_hz = 20
40+
self.create_timer(1 / self._publish_hz, self.on_publish_joints)
41+
42+
def on_publish_joints(self) -> None:
43+
if self.forklift_position >= self.params.forklift_max_extent:
44+
self.forklift_direction = -1
45+
elif self.forklift_position <= 0:
46+
self.forklift_direction = 1
47+
48+
self.forklift_position += (
49+
self.forklift_direction * self.params.forklift_speed / self._publish_hz
50+
)
51+
52+
joint_positions = {self.urdf.joints.FORKS: self.forklift_position}
53+
54+
self.joint_state_publisher.publish(
55+
JointState(
56+
name=list(joint_positions.keys()),
57+
position=list(joint_positions.values()),
58+
)
59+
)
60+
61+
62+
main = create_spin_function(ExampleNode)

pkgs/node_helpers/node_helpers/urdfs/loading.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
_CHILD_TAG = "child"
1212
_NAME_KEY = "name"
1313
_LINK_KEY = "link"
14+
_MIMIC_TAG = "mimic"
1415

1516

1617
def load_urdf(package: str, relative_urdf_path: Path | str) -> str:
@@ -134,5 +135,9 @@ def prepend_namespace(urdf_str: str, namespace: str) -> str:
134135
"link",
135136
NAMESPACE_FMT.format(namespace=namespace, name=node.get(_LINK_KEY)),
136137
)
137-
138+
elif node.tag == _MIMIC_TAG:
139+
node.set(
140+
"joint",
141+
NAMESPACE_FMT.format(namespace=namespace, name=node.get(_NAME_KEY)),
142+
)
138143
return ElementTree.tostring(urdf, encoding="unicode")

pkgs/node_helpers/node_helpers_test/integration/urdfs/example_urdf_constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class ForkliftFrames(NamedTuple):
1818

1919
ForkliftURDF = URDFConstants[ForkliftJoints, ForkliftFrames](
2020
from_package="node_helpers",
21-
registration_name="forklift",
21+
registration_name="test_forklift",
2222
urdf_paths=[(None, "sample_urdfs/forklift/robot.urdf")],
2323
joints=ForkliftJoints(),
2424
frames=ForkliftFrames(),
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:df4ea50d48402ad056343e980fb0ce717b644fbee6f1f2a3fc20952a253870e4
3-
size 3191
2+
oid sha256:a491f06f81ec4d696b9a1ea2eb8297bcd04ffcb8c9878a70cfeee3c261518d0b
3+
size 4452

pkgs/node_helpers/node_helpers_test/unit/urdfs/test_loading.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
from node_helpers.urdfs.loading import NAMESPACE_FMT
44
from node_helpers_test.resources import GENERIC_URDF
55

6-
EXPECTED_JOINT_NAMES = ["shuttle1-joint", "clamp1-joint"]
7-
EXPECTED_LINK_NAMES = ["base_link", "shuttle1", "clamp1"]
6+
EXPECTED_JOINT_NAMES = ["shuttle1-joint", "clamp1-joint", "clamp-mimic-joint"]
7+
EXPECTED_LINK_NAMES = ["base_link", "shuttle1", "clamp1", "clamp-mimic"]
88

99

1010
def test_fix_urdf_paths_makes_path_replacements() -> None:

0 commit comments

Comments
 (0)