ROS 2 Message Types Used by Waypoint
Use this page when a guide step mentions a message field you do not recognize. The official message definitions are still the source of truth, but this page explains the parts this robot actually uses.
Reading a Message
Section titled “Reading a Message”Use this method every time:
- Run
ros2 interface show MESSAGE_TYPE. - Find nested messages and arrays.
- Identify the fields your node must set or read.
- Check units.
- Set headers and frames when they exist.
- Compare the result with
ros2 topic echo.
geometry_msgs/msg/Twist
Section titled “geometry_msgs/msg/Twist”Twist+-- linear: Vector3| +-- x: float64| +-- y: float64| +-- z: float64+-- angular: Vector3 +-- x: float64 +-- y: float64 +-- z: float64Waypoint uses linear.x in meters per second and angular.z in radians per second.
message = Twist()message.linear.x = 0.10message.angular.z = 0.30publisher.publish(message)The other fields stay zero because this is a ground robot that does not strafe, fly, roll, or pitch.
std_msgs/msg/Header
Section titled “std_msgs/msg/Header”Header+-- stamp| +-- sec| +-- nanosec+-- frame_id: stringstamp says when the data applies. frame_id says which coordinate frame the data is expressed in.
message.header.stamp = self.get_clock().now().to_msg()message.header.frame_id = 'imu_link'Let ROS fill sec and nanosec from the clock. Do not fill those two fields by hand unless you are writing a special time tool.
geometry_msgs/msg/Quaternion
Section titled “geometry_msgs/msg/Quaternion”ROS uses 3D orientations even for a flat ground robot. For yaw-only motion:
half_yaw = yaw / 2.0qx = 0.0qy = 0.0qz = math.sin(half_yaw)qw = math.cos(half_yaw)(0, 0, 0, 1) means no rotation. (0, 0, 0, 0) is not a valid orientation.
sensor_msgs/msg/Imu
Section titled “sensor_msgs/msg/Imu”Imu+-- header: Header+-- orientation: Quaternion+-- orientation_covariance: float64[9]+-- angular_velocity: Vector3+-- angular_velocity_covariance: float64[9]+-- linear_acceleration: Vector3+-- linear_acceleration_covariance: float64[9]| Field | MPU6050 provides it? | Required handling |
|---|---|---|
| timestamp | no | use the ROS clock |
| frame | no | use the configured IMU frame |
| orientation | no | do not fabricate it |
| angular velocity | yes | scale and convert to rad/s |
| linear acceleration | yes | scale and convert to m/s^2 |
| covariance | not directly | use honest documented values |
Minimum population pattern:
message = Imu()message.header.stamp = self.get_clock().now().to_msg()message.header.frame_id = 'imu_link'message.orientation.w = 1.0message.orientation_covariance[0] = -1.0message.angular_velocity.x = gyro_x_rad_smessage.angular_velocity.y = gyro_y_rad_smessage.angular_velocity.z = gyro_z_rad_smessage.linear_acceleration.x = accel_x_mps2message.linear_acceleration.y = accel_y_mps2message.linear_acceleration.z = accel_z_mps2The orientation_covariance[0] = -1.0 marker says orientation is unavailable. Setting orientation.w = 1.0 avoids an invalid all-zero quaternion, but it does not claim the IMU knows the robot’s orientation because the covariance marker already says it does not.
nav_msgs/msg/Odometry
Section titled “nav_msgs/msg/Odometry”Odometry+-- header: Header+-- child_frame_id: string+-- pose: PoseWithCovariance| +-- pose: Pose| | +-- position: Point| | +-- orientation: Quaternion| +-- covariance: float64[36]+-- twist: TwistWithCovariance +-- twist: Twist +-- covariance: float64[36]message.pose.pose is not a typo. The outer pose contains a pose and covariance. The inner pose is the actual position and orientation. message.twist.twist follows the same pattern.
For this package:
message.header.frame_id = 'odom'message.child_frame_id = 'base_link'- pose is expressed in
odom - velocity is associated with
base_link
odom = Odometry()odom.header.stamp = stampodom.header.frame_id = 'odom'odom.child_frame_id = 'base_link'odom.pose.pose.position.x = xodom.pose.pose.position.y = yodom.pose.pose.orientation.z = qzodom.pose.pose.orientation.w = qwodom.twist.twist.linear.x = linear_mpsodom.twist.twist.angular.z = angular_rad_snav_msgs/msg/Path
Section titled “nav_msgs/msg/Path”Path+-- header: Header+-- poses: list of PoseStampedposes is a Python sequence. Append poses and trim it so RViz does not grow forever.
pose = PoseStamped()pose.header = odom.headerpose.pose = odom.pose.poseself.path.header.stamp = odom.header.stampself.path.header.frame_id = 'odom'self.path.poses.append(pose)self.path.poses = self.path.poses[-self.path_max_poses:]geometry_msgs/msg/TransformStamped
Section titled “geometry_msgs/msg/TransformStamped”TransformStamped+-- header: Header| +-- stamp| +-- frame_id+-- child_frame_id: string+-- transform +-- translation: Vector3 +-- rotation: QuaternionA transform connects two frames. For odometry:
transform = TransformStamped()transform.header.stamp = stamptransform.header.frame_id = 'odom'transform.child_frame_id = 'base_link'transform.transform.translation.x = xtransform.transform.translation.y = ytransform.transform.rotation.z = qztransform.transform.rotation.w = qwself.tf_broadcaster.sendTransform(transform)For a fixed IMU mounting, publish or describe base_link -> imu_link. The transform must match the physical mounting, and you should not also rotate the raw IMU axes the same way in code.
Parameter YAML Shape
Section titled “Parameter YAML Shape”node_name: ros__parameters: parameter_name: valueThe outer node_name must match the node name in the launch file. YAML indentation matters: use spaces, not tabs.