From 063fbe8b4ed3e846ebccdc6ddd1f45ef23cf7e72 Mon Sep 17 00:00:00 2001 From: lesh Date: Sun, 13 Jul 2025 17:07:03 -0700 Subject: [PATCH 1/4] lcmgen change spec init --- dimos/core/test_lcmmsg_gen.py | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 dimos/core/test_lcmmsg_gen.py diff --git a/dimos/core/test_lcmmsg_gen.py b/dimos/core/test_lcmmsg_gen.py new file mode 100644 index 0000000000..4cabead22f --- /dev/null +++ b/dimos/core/test_lcmmsg_gen.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 + +# Copyright 2025 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from lcm_msgs.geometry_msgs import Orientation, Pose, PoseStamped, Vector3 +from lcm_msgs.std_msgs import Header + + +def test_vector_init(): + vector = Vector3(x=1.0, y=2.0, z=3.0) + assert vector.x == 1.0 + assert vector.y == 2.0 + assert vector.z == 3.0 + + +def test_vector_defaults(): + vector = Vector3() + assert vector.x == 0.0 + assert vector.y == 0.0 + assert vector.z == 0.0 + + +def test_vector_partial_defaults(): + vector = Vector3(x=1.0) + assert vector.x == 1.0 + assert vector.y == 0.0 + assert vector.z == 0.0 + + +def test_vector_encode_decode(): + msg = Vector3(x=1.0, y=2.0, z=3.0).encode() + assert isinstance(msg, bytes) + vector = Vector3.decode(msg) + assert vector.x == 1.0 + assert vector.y == 2.0 + assert vector.z == 3.0 + + +def test_pose_stamped_init(): + pose = PoseStamped( + pose=Pose( + position=Vector3(1.0, 2.0, 3.0), + orientation=Orientation(1.0, 2.0, 3.0, 4.0), + ), + header=Header(stamp=1234567890, frame_id="test_frame"), + ) From ccbcadf29c166ca47b92afe271095ad488f17bd7 Mon Sep 17 00:00:00 2001 From: lesh Date: Sun, 13 Jul 2025 17:17:37 -0700 Subject: [PATCH 2/4] aditional information on lcmgen --- dimos/core/test_lcmmsg_gen.py | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/dimos/core/test_lcmmsg_gen.py b/dimos/core/test_lcmmsg_gen.py index 4cabead22f..5f979d72bc 100644 --- a/dimos/core/test_lcmmsg_gen.py +++ b/dimos/core/test_lcmmsg_gen.py @@ -25,6 +25,28 @@ def test_vector_init(): assert vector.z == 3.0 +# I'm not sure if easily achievable, +# but this is a much better interface +def test_vector_args_init(): + vector = Vector3(1.0, 2.0, 3.0) + assert vector.x == 1.0 + assert vector.y == 2.0 + assert vector.z == 3.0 + + +# if we are using these types across the platform, they are the most common +# objects used, we have to be able to subclass and implement convinience +# methods (like above positional arg init) +# +# how can we hand- add to a specific autogenerated lcm_msg type? +# while also keeping the new class within the original dep structure +# (so Pose would refer to the new convinient Vector3 subclass, +# without recoding the Pose itself?) +# +# for example I'd also subclass Header to take datetime as timestamp, +# Quaternion to have to_euler() -> Vector3 conversion, .yaw() .pitch() etc etc + + def test_vector_defaults(): vector = Vector3() assert vector.x == 0.0 @@ -56,3 +78,30 @@ def test_pose_stamped_init(): ), header=Header(stamp=1234567890, frame_id="test_frame"), ) + + +# not sure if we can achieve this automatically easily, but this is +# a much better interface +def test_pose_fancy_init(): + pose = PoseStamped( + # depeer init implicit + position=Vector3(1.0, 2.0, 3.0), + orientation=Orientation(1.0, 2.0, 3.0, 4.0), + stamp=1234567890, + frame_id="test_frame", + ) + + +def test_pose_partial_fancy_init(): + # partially implicit init + pose = PoseStamped( + # pose explicit + pose=Pose( + # I'm hoping for positional argument support here + position=Vector3(1.0, 2.0, 3.0), + orientation=Orientation(1.0, 2.0, 3.0, 4.0), + ), + # header implicit + stamp=1234567890, + frame_id="test_frame", + ) From bfd24388e6c41e7e5b6ea47954eb7e483ee8eaab Mon Sep 17 00:00:00 2001 From: lesh Date: Sun, 13 Jul 2025 17:25:25 -0700 Subject: [PATCH 3/4] aditional lcmgen comments --- dimos/core/test_lcmmsg_gen.py | 39 ++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/dimos/core/test_lcmmsg_gen.py b/dimos/core/test_lcmmsg_gen.py index 5f979d72bc..d4f95f2924 100644 --- a/dimos/core/test_lcmmsg_gen.py +++ b/dimos/core/test_lcmmsg_gen.py @@ -18,6 +18,35 @@ from lcm_msgs.std_msgs import Header +# None of the tests actually pass apart from the first two. +# The rest of the tests are a proposal for functionality to be added. +# +# Below mutable init is how current lcmgen can only be used, +# This is not very ergonomical, and these are the most common objects we use, +# so we need a way to both have a better init for them by default, coming +# out of lcmgen, +# as well as to have a better way to modify individual types by hand for +# type specific convinience methods. +# +# Some examples: +# header taking datetime or float, instead of a weird ros timestamp dictionary format, +# Quaternion having .yaw() pitch() or to_euler() -> Vector3 methods,etc +# Vector taking a list or tuple as init, not just kwargs +# +def test_vector_current_init(): + vector = Vector3() + vector.x = 1.0 + vector.y = 2.0 + vector.z = 3.0 + + +def test_vector_defaults(): + vector = Vector3() + assert vector.x == 0.0 + assert vector.y == 0.0 + assert vector.z == 0.0 + + def test_vector_init(): vector = Vector3(x=1.0, y=2.0, z=3.0) assert vector.x == 1.0 @@ -42,16 +71,6 @@ def test_vector_args_init(): # while also keeping the new class within the original dep structure # (so Pose would refer to the new convinient Vector3 subclass, # without recoding the Pose itself?) -# -# for example I'd also subclass Header to take datetime as timestamp, -# Quaternion to have to_euler() -> Vector3 conversion, .yaw() .pitch() etc etc - - -def test_vector_defaults(): - vector = Vector3() - assert vector.x == 0.0 - assert vector.y == 0.0 - assert vector.z == 0.0 def test_vector_partial_defaults(): From 99c35ff4574dac0aace40a30157cc8ab31491a36 Mon Sep 17 00:00:00 2001 From: lesh Date: Sun, 13 Jul 2025 17:51:29 -0700 Subject: [PATCH 4/4] stamped accessor proposal --- dimos/core/test_lcmmsg_gen.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dimos/core/test_lcmmsg_gen.py b/dimos/core/test_lcmmsg_gen.py index d4f95f2924..231a3ce9ad 100644 --- a/dimos/core/test_lcmmsg_gen.py +++ b/dimos/core/test_lcmmsg_gen.py @@ -110,6 +110,8 @@ def test_pose_fancy_init(): frame_id="test_frame", ) + assert pose.pose.position.x == 1.0 + def test_pose_partial_fancy_init(): # partially implicit init @@ -124,3 +126,9 @@ def test_pose_partial_fancy_init(): stamp=1234567890, frame_id="test_frame", ) + + assert pose.pose.position.x == 1.0 + + # can Stamped modules provide access to the underlying data + # directly? Maybe manual Stamped subclass? + assert pose.position.y == 2.0