]> defiant.homedns.org Git - a4wd3.git/commitdiff
Added urdf, generated by hermes/Qwen-3.8
authorErik Andresen <erik@vontaene.de>
Sun, 11 Oct 2026 17:40:04 +0000 (19:40 +0200)
committerErik Andresen <erik@vontaene.de>
Sun, 11 Oct 2026 17:40:04 +0000 (19:40 +0200)
CMakeLists.txt
launch/a4wd3_launch.py
meshes/a4wd3_base_rviz.stl [new file with mode: 0644]
meshes/rplidar_a2m4_decimated.stl [new file with mode: 0644]
urdf/a4wd3.urdf [new file with mode: 0644]

index bd8f72ac89ef60dc3ef52ccba7dfbcf64b6f60c6..3a44de744dfe38b64554934b1490a605228dc54b 100644 (file)
@@ -56,6 +56,10 @@ install(DIRECTORY params
   DESTINATION share/${PROJECT_NAME})
 install(DIRECTORY maps
   DESTINATION share/${PROJECT_NAME})
+install(DIRECTORY urdf
+  DESTINATION share/${PROJECT_NAME})
+install(DIRECTORY meshes
+  DESTINATION share/${PROJECT_NAME})
 install(PROGRAMS scripts/cpu_temp_pub.py DESTINATION lib/${PROJECT_NAME})
 
 if(BUILD_TESTING)
index 72293ac1e8dc463202e7e49e94c145e0a5f222b7..88eab0c88321869cd05b9b75584bb4b1cfb40d95 100644 (file)
@@ -8,11 +8,13 @@ from launch_xml.launch_description_sources import XMLLaunchDescriptionSource
 from launch import LaunchDescription
 from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument, EmitEvent, RegisterEventHandler, LogInfo
 from launch.events import matches_action
+from launch.substitutions import LaunchConfiguration, PathJoinSubstitution, Command, FileContent
+from launch.conditions import IfCondition
 from launch_ros.actions import Node, LifecycleNode
 from launch_ros.events.lifecycle import ChangeState
 from launch_ros.event_handlers import OnStateTransition
-from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
-from launch.conditions import IfCondition
+from launch_ros.parameter_descriptions import ParameterValue
+from launch_ros.substitutions import FindPackageShare
 from lifecycle_msgs.msg import Transition
 
 # save map: ros2 run nav2_map_server map_saver_cli -f /mapfolder/mapfilename
@@ -55,6 +57,16 @@ def generate_launch_description():
             name='a4wd3_display',
            output="screen",
         ),
+        # URDF-based static frames (base_link -> laser, imu). Replaces the former
+        # tf_base_scan / tf_base_imu static_transform_publisher nodes (duplicate
+        # publishers of the same static TF cause conflicts).
+        Node(
+            package='robot_state_publisher',
+            executable='robot_state_publisher',
+            name='robot_state_publisher',
+            parameters=[{'robot_description': ParameterValue(FileContent(PathJoinSubstitution([FindPackageShare('a4wd3'), 'urdf', 'a4wd3.urdf'])), value_type=str)}],
+            output="screen"
+        ),
         Node(
             package='bno085_uart',
             executable='bno085',
@@ -62,13 +74,8 @@ def generate_launch_description():
            parameters=[{"port": "/dev/ttyS2"}],
            output="screen",
         ),
-        Node(
-            package='tf2_ros',
-            executable='static_transform_publisher',
-            name='tf_base_imu',
-           arguments = ['--x', '-0.02', '--y', '-0.013', '--roll', '3.1416', '--yaw', '0.0', '--frame-id', 'base_link', '--child-frame-id', 'imu'],
-           output="screen"
-        ),
+        # NOTE: base_link -> imu and base_link -> laser static transforms now come from
+        # robot_state_publisher (urdf/a4wd3.urdf) instead of static_transform_publisher.
         Node(
             condition=IfCondition(with_gps),
             package='tf2_ros',
@@ -77,13 +84,7 @@ def generate_launch_description():
            arguments = ['--x', '-0.04', '--y', '-0.035', '--frame-id', 'base_link', '--child-frame-id', 'gps'],
            output="screen"
         ),
-        Node(
-            package='tf2_ros',
-            executable='static_transform_publisher',
-            name='tf_base_scan',
-           arguments = ['--x', '0.08125', '--y', '0.07425', '--yaw', '3.141592653589793', '--frame-id', 'base_link', '--child-frame-id', 'laser'],
-           output="screen"
-        ),
+        # (tf_base_scan removed: base_link -> laser now comes from the URDF via robot_state_publisher)
         Node(
             package='robot_localization',
             executable='ekf_node',
diff --git a/meshes/a4wd3_base_rviz.stl b/meshes/a4wd3_base_rviz.stl
new file mode 100644 (file)
index 0000000..1fbb7cf
Binary files /dev/null and b/meshes/a4wd3_base_rviz.stl differ
diff --git a/meshes/rplidar_a2m4_decimated.stl b/meshes/rplidar_a2m4_decimated.stl
new file mode 100644 (file)
index 0000000..d83d6b5
Binary files /dev/null and b/meshes/rplidar_a2m4_decimated.stl differ
diff --git a/urdf/a4wd3.urdf b/urdf/a4wd3.urdf
new file mode 100644 (file)
index 0000000..cf67184
--- /dev/null
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+<!-- A4WD3 chassis URDF (no manipulator). Generated 2026-10-11.
+     Sources:
+       - /home/erik/a4wd3-git/launch/a4wd3_launch.py static transforms (tf_base_scan, tf_base_imu)
+       - A4WD3-Wheeled.stp (user CAD, true scale: overall width 437.0 mm matches measurement)
+       - rplidar-a2m4-r1.stl (Slamtec official model; flat-panel lidar, scan axis = mesh Z)
+     Frame conventions:
+       LIVE base_link (as published by hw_node.cpp odom TF): x = forward, y = left, z = up,
+       ORIGIN AT WHEELBASE CENTER / AXLE HEIGHT (z=0 at axle plane; ground ~79 mm below,
+       i.e. one wheel rolling radius of ~158 mm dia).
+       The launch-file static_transform_publisher values are expressed in THIS live frame,
+       so they are used VERBATIM as fixed joints here (this URDF replaces those publishers).
+       Chassis CAD frame (for reference): x_c = right, y_c = up, z_c = aft (+z_c = aft,
+       verified via waffle M3-pair labels: FRONT pairs at z_c=-125, BACK at z_c=+125).
+       Mesh transform applied to the chassis STL: live_x = -cad_z, live_y = -cad_x,
+       live_z = cad_y - 35.0 mm (wheel centers sit at cad_y = 35.0 mm).
+     Masses: REAL (scale 2026-10-11: 7.0 kg total incl. lidar + battery; A2M4(r1) = 0.19 kg per
+     manufacturer). Inertia tensors: ESTIMATED from mass + footprint - refine if precision needed. -->
+<robot name="a4wd3">
+
+  <link name="base_link">
+    <!-- COM from STEP BRep analysis: CAD (0.07, 38.69, 0.53) mm -> live (-0.53, -0.07, 3.69) mm -->
+    <inertial>
+      <origin xyz="-0.00053 -0.00007 0.00369" rpy="0 0 0"/>
+      <!-- REAL MASS (user scale 2026-10-11): whole robot incl. lidar + battery = 7.0 kg;
+           laser link = 0.19 kg (manufacturer spec A2M4(r1)) => base_link = 6.81 kg.
+           NOTE: the visual/collision mesh EXCLUDES the 4 wheel solids (they were removed from
+           the STEP before tessellation); their mass is still counted here. Inertia scaled from
+           the 9 kg placeholder by 6.81/9. -->
+      <mass value="6.81"/>
+      <inertia ixx="0.21" ixy="0" ixz="0" iyy="0.15" iyz="0" izz="0.32"/>
+    </inertial>
+    <visual>
+      <origin xyz="0 0 0" rpy="0 0 0"/>
+      <geometry>
+        <mesh filename="package://a4wd3/meshes/a4wd3_base_rviz.stl"/>
+      </geometry>
+      <material name="chassis_grey">
+        <color rgba="0.45 0.45 0.45 1.0"/>
+      </material>
+    </visual>
+    <collision>
+      <origin xyz="0 0 0" rpy="0 0 0"/>
+      <geometry>
+        <mesh filename="package://a4wd3/meshes/a4wd3_base_rviz.stl"/>
+      </geometry>
+    </collision>
+  </link>
+
+  <!-- RP-LIDAR A2M4 (r1), flat panel. Launch tf_base_scan VERBATIM:
+       t=(+0.08125, +0.07425, 0) m, yaw = pi (live base_link frame).
+       => 81.25 mm forward, 74.25 mm left, at axle height; scan plane ~74 mm above axles
+       (~153 mm above floor). Visual origin offset puts the mesh's scan plane
+       (mesh z=+0.1125, body axis at mesh x=-0.006, y=+0.028) onto the laser frame origin. -->
+  <joint name="base_to_laser" type="fixed">
+    <parent link="base_link"/>
+    <child link="laser"/>
+    <origin xyz="0.08125 0.07425 0" rpy="0 0 3.14159"/>
+  </joint>
+  <link name="laser">
+    <inertial>
+      <origin xyz="0 0 0" rpy="0 0 0"/>
+      <!-- 0.19 kg: manufacturer spec for A2M4(r1) -->
+      <mass value="0.19"/>
+      <inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0002"/>
+    </inertial>
+    <visual>
+      <origin xyz="0.006 -0.028 -0.1125" rpy="0 0 0"/>
+      <geometry>
+        <mesh filename="package://a4wd3/meshes/rplidar_a2m4_decimated.stl"/>
+      </geometry>
+      <material name="lidar_black">
+        <color rgba="0.1 0.1 0.1 1.0"/>
+      </material>
+    </visual>
+    <collision>
+      <origin xyz="0 0 0" rpy="0 0 0"/>
+      <geometry>
+        <box size="0.136 0.041 0.075"/>
+      </geometry>
+    </collision>
+  </link>
+
+  <!-- BNO085 IMU. Launch tf_base_imu VERBATIM: t=(-0.02, -0.013, 0) m, roll = pi. -->
+  <joint name="base_to_imu" type="fixed">
+    <parent link="base_link"/>
+    <child link="imu"/>
+    <origin xyz="-0.02 -0.013 0" rpy="3.14159 0 0"/>
+  </joint>
+  <link name="imu">
+    <inertial>
+      <origin xyz="0 0 0" rpy="0 0 0"/>
+      <mass value="0.01"/>
+      <inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6"/>
+    </inertial>
+  </link>
+
+</robot>