16 super().
__init__(
"vehicle_dynamics_publisher")
17 self.get_logger().info(
"Vehicle Dynamics Node started")
19 velocity_sub = message_filters.Subscriber(
20 self, Velocities,
"/state_estimation/velocities"
22 yaw_rate_sub = message_filters.Subscriber(
23 self, Vector3Stamped,
"/imu/acceleration"
25 steering_angle_sub = message_filters.Subscriber(
26 self, SteeringAngle,
"/vehicle/bosch_steering_angle"
28 angle_sync = message_filters.ApproximateTimeSynchronizer(
29 [velocity_sub, yaw_rate_sub, steering_angle_sub], queue_size=10, slop=0.05
33 rl_rpm_sub = message_filters.Subscriber(self, WheelRPM,
"/vehicle/rl_rpm")
34 rr_rpm_sub = message_filters.Subscriber(self, WheelRPM,
"/vehicle/rr_rpm")
35 fl_rpm_sub = message_filters.Subscriber(self, WheelRPM,
"/vehicle/fl_rpm")
36 fr_rpm_sub = message_filters.Subscriber(self, WheelRPM,
"/vehicle/fr_rpm")
37 rpm_sync = message_filters.ApproximateTimeSynchronizer(
38 [rl_rpm_sub, rr_rpm_sub, fl_rpm_sub, fr_rpm_sub], queue_size=10, slop=0.05
43 Float64MultiArray,
"/vehicle/slip_angles", 10
46 Float64MultiArray,
"/vehicle/slip_ratio", 10
50 Float64MultiArray,
"/vehicle/wheels_distance", 10
54 Float64MultiArray,
"/vehicle/cg_distance", 10
58 Float64MultiArray,
"/vehicle/path_curvatures", 10
76 Callback function for synchronized velocity, yaw_rate, and steering angle data.
77 Computes slip angles for the vehicle's center of gravity and all four wheels.
80 velocities_msg (Velocities): Estimated vehicle velocity data.
81 yaw_rate_msg (Vector3Stamped): IMU acc with yaw_rate component.
82 steering_angle_msg (SteeringAngle): Steering angle input from the vehicle.
87 vx = velocities_msg.velocity_x
88 vy = velocities_msg.velocity_y
89 steering_angle = steering_angle_msg.steering_angle
90 yaw_rate = yaw_rate_msg.vector.x
100 slip_angle_beta = math.atan2(vy, vx)
102 v_FL_x = vx - yaw_rate * (T / 2)
103 v_FL_y = vy + yaw_rate * (L * wf)
104 alpha_FL = abs(steering_angle - math.atan2(v_FL_y, v_FL_x))
106 v_FR_x = vx + yaw_rate * (T / 2)
107 v_FR_y = vy + yaw_rate * (L * wf)
108 alpha_FR = abs(steering_angle - math.atan2(v_FR_y, v_FR_x))
110 v_RL_x = vx - yaw_rate * (T / 2)
111 v_RL_y = vy - yaw_rate * (L * (1 - wf))
112 alpha_RL = abs(math.atan2(v_RL_y, v_RL_x))
114 v_RR_x = vx + yaw_rate * (T / 2)
115 v_RR_y = vy - yaw_rate * (L * (1 - wf))
116 alpha_RR = abs(math.atan2(v_RR_y, v_RR_x))
118 slip_angles_msg = Float64MultiArray()
119 slip_angles_msg.data = [
120 math.degrees(slip_angle_beta),
121 math.degrees(alpha_FL),
122 math.degrees(alpha_FR),
123 math.degrees(alpha_RL),
124 math.degrees(alpha_RR),
129 self.get_logger().info(
130 f
"Published Slip Angles (deg): CG: {math.degrees(slip_angle_beta):.2f}, FL: {math.degrees(alpha_FL):.2f}, FR: {math.degrees(alpha_FR):.2f}, RL: {math.degrees(alpha_RL):.2f}, RR: {math.degrees(alpha_RR):.2f}, Yaw Rate: {yaw_rate:.3f}"
135 current_time = self.get_clock().now().nanoseconds / 1e9
138 v_total = math.sqrt(vx**2 + vy**2)
139 distance_cg = v_total * dt
142 distance_cg_msg = Float64MultiArray()
145 self.get_logger().info(
146 f
"Published Distance CG: {distance_cg:.3f} m, Time Delta: {dt:.3f} s"
151 Callback function for synchronized wheel speed sensor (WSS) data.
152 Computes the left and right slip ratio using front and rear wheel velocities.
155 rl_rpm_msg (WheelRPM): Rear left wheel RPM message.
156 rr_rpm_msg (WheelRPM): Rear right wheel RPM message.
157 fl_rpm_msg (WheelRPM): Front left wheel RPM message.
158 fr_rpm_msg (WheelRPM): Front right wheel RPM message.
165 V_RL = (rl_rpm_msg.rl_rpm * 2 * math.pi * wheel_radius) / 60
166 V_RR = (rr_rpm_msg.rr_rpm * 2 * math.pi * wheel_radius) / 60
167 V_FL = (fl_rpm_msg.fl_rpm * 2 * math.pi * wheel_radius) / 60
168 V_FR = (fr_rpm_msg.fr_rpm * 2 * math.pi * wheel_radius) / 60
170 avg_rear_velocity = 0.5 * (V_RR + V_RL)
171 slip_ratio_left = (avg_rear_velocity / V_FL) - 1
if V_FL != 0
else float(
"nan")
172 slip_ratio_right = (avg_rear_velocity / V_FR) - 1
if V_FR != 0
else float(
"nan")
174 slip_ratios_msg = Float64MultiArray()
175 slip_ratios_msg.data = [slip_ratio_left, slip_ratio_right]
181 rl_rpm_msg.header.stamp.sec + rl_rpm_msg.header.stamp.nanosec * 1e-9
185 distance_fr = V_FR * dt
186 distance_fl = V_FL * dt
187 distance_rl = V_RL * dt
188 distance_rr = V_RR * dt
193 distance_msg = Float64MultiArray()
194 distance_msg.data = [
206 self.get_logger().info(
"First RPM sync received, skipping distance calc.")
220 curvature_msg = Float64MultiArray()
221 curvature_msg.data = [cinematic, dynamic]
222 self.path_curvature_pub.publish(curvature_msg)
224 self.get_logger().info(
225 f
"Published Path Curvature: Cinematic = {cinematic:.4f}, Dynamic = {dynamic:.4f}"
228 self.get_logger().info(
229 f
"Published Slip Ratio: Left: {slip_ratio_left:.3f}, Right: {slip_ratio_right:.3f}"