Skip to content

Commit 0776dbb

Browse files
committed
more fixes for real life testing
1 parent ea8713e commit 0776dbb

6 files changed

Lines changed: 63 additions & 54 deletions

File tree

src/simulation/scripts/heading_publisher.py

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44

55
import rclpy
66
from rclpy.node import Node
7-
<<<<<<< HEAD
8-
from rclpy.qos import QoSPresetProfiles
9-
=======
107
from rclpy.qos import SensorDataQoS
11-
>>>>>>> f33dc56 (building)
128
from sensor_msgs.msg import MagneticField
139
from msgs.msg import Heading
1410

@@ -26,69 +22,34 @@ def __init__(self):
2622
self.heading_acc_ = self.get_parameter('heading_acc').get_parameter_value().double_value
2723

2824
self.pub_ = self.create_publisher(Heading, heading_topic, 10)
29-
<<<<<<< HEAD
30-
31-
# Always cache the first heading to start at 0 degrees
32-
self.initial_heading_enu = None
33-
=======
34-
>>>>>>> f33dc56 (building)
3525

3626
self.sub_ = self.create_subscription(
3727
MagneticField,
3828
mag_topic,
3929
self.on_mag,
40-
<<<<<<< HEAD
41-
QoSPresetProfiles.SENSOR_DATA.value,
42-
)
43-
44-
self.get_logger().info(
45-
f'Heading publisher: {mag_topic} -> {heading_topic} (Force Initial Offset: Enabled)'
46-
=======
4730
SensorDataQoS(),
4831
)
4932

5033
self.get_logger().info(
5134
f'Heading publisher: {mag_topic} -> {heading_topic}'
52-
>>>>>>> f33dc56 (building)
5335
)
5436

5537
def on_mag(self, msg: MagneticField):
5638
bx = msg.magnetic_field.x
5739
by = msg.magnetic_field.y
5840

59-
<<<<<<< HEAD
60-
# In Gazebo's magnetometer the field is reported in the robot body frame
61-
# with the simulated Earth field pointing North (+Y world). For a robot
62-
# with x=forward, y=left this gives:
63-
# bx = H * sin(yaw_enu) (North projected onto forward axis)
64-
# by = H * cos(yaw_enu) (North projected onto left axis)
65-
# So atan2(bx, by) = atan2(sin θ, cos θ) = θ, the correct CCW-from-East
66-
# ENU heading. Using atan2(by, bx) would give a CW compass bearing
67-
# instead, inverting the sign of every turn.
68-
heading_enu_raw = math.degrees(math.atan2(bx, by))
69-
70-
if self.initial_heading_enu is None:
71-
self.initial_heading_enu = heading_enu_raw
72-
self.get_logger().info(f'Initial raw heading cached: {self.initial_heading_enu:.2f} deg. Starting at 0.00 deg.')
73-
74-
# Apply offset so we start at 0 (East)
75-
# ENU heading: degrees CCW from East
76-
heading_enu = (heading_enu_raw - self.initial_heading_enu + 360.0) % 360.0
41+
# Gazebo magnetometer reports field in robot body frame (x=forward, y=left).
42+
# Earth's horizontal field points North, so:
43+
# bx = H*sin(yaw_enu), by = H*cos(yaw_enu)
44+
# atan2(bx, by) = atan2(sin θ, cos θ) = θ = ENU heading directly.
45+
heading_enu_deg = math.degrees(math.atan2(bx, by))
7746

7847
# Compass bearing: degrees clockwise from North
79-
# North is 90 deg ENU.
80-
compass_bearing = (90.0 - heading_enu + 360.0) % 360.0
81-
=======
82-
# compass bearing: degrees clockwise from north
83-
compass_bearing = (math.degrees(math.atan2(-by, bx)) + 360.0) % 360.0
84-
85-
# ENU heading: degrees CCW from east
86-
heading_enu = (90.0 - compass_bearing + 360.0) % 360.0
87-
>>>>>>> f33dc56 (building)
48+
compass_bearing = (90.0 - heading_enu_deg + 360.0) % 360.0
8849

8950
out = Heading()
9051
out.header = msg.header
91-
out.heading = heading_enu
52+
out.heading = heading_enu_deg # degrees — gps_pose_publisher applies * pi/180
9253
out.heading_acc = self.heading_acc_
9354
out.compass_bearing = compass_bearing
9455
self.pub_.publish(out)

src/subsystems/navigation/mag_heading/mag_heading/mag_heading_node.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,18 @@ def _mag_cb(self, msg: MagneticField):
8383
raw = np.array([msg.magnetic_field.x, msg.magnetic_field.y, msg.magnetic_field.z])
8484
corrected = self.soft_iron @ (raw - self.hard_iron)
8585

86-
# compass_bearing: magnetic north, 0=North CW degrees [0, 360)
87-
mag_heading_rad = math.atan2(corrected[1], corrected[0])
86+
# Body-frame magnetometer (x=forward, y=left):
87+
# bx = H*sin(yaw_enu), by = H*cos(yaw_enu)
88+
# so atan2(bx, by) = atan2(sin θ, cos θ) = θ = ENU heading directly.
89+
# (Same swap used by the simulation heading publisher.)
90+
mag_heading_rad = math.atan2(corrected[0], corrected[1])
91+
92+
# compass_bearing: 0=North CW degrees [0, 360)
8893
compass_bearing_deg = (90.0 - math.degrees(mag_heading_rad)) % 360.0
8994

90-
# heading: true north if declination known, magnetic otherwise
91-
# ROS convention: 0=East, CCW, radians
95+
# heading: true north if declination known, magnetic otherwise.
96+
# Published in degrees to match the simulation heading publisher so that
97+
# gps_pose_publisher can apply its (* M_PI / 180.0) conversion uniformly.
9298
if self.declination_rad is not None:
9399
heading_rad = mag_heading_rad + self.declination_rad
94100
else:
@@ -98,15 +104,15 @@ def _mag_cb(self, msg: MagneticField):
98104
cov = msg.magnetic_field_covariance
99105
b_xy_mag = math.hypot(corrected[0], corrected[1])
100106
if b_xy_mag > 1e-9 and cov[0] > 0.0:
101-
heading_acc = math.sqrt((cov[0] + cov[4]) / 2.0) / b_xy_mag
107+
heading_acc_deg = math.degrees(math.sqrt((cov[0] + cov[4]) / 2.0) / b_xy_mag)
102108
else:
103-
heading_acc = 0.0
109+
heading_acc_deg = 0.0
104110

105111
out = Heading()
106112
out.header.stamp = msg.header.stamp
107113
out.header.frame_id = self.frame_id
108-
out.heading = heading_rad
109-
out.heading_acc = heading_acc
114+
out.heading = math.degrees(heading_rad) # degrees — matches sim heading publisher
115+
out.heading_acc = heading_acc_deg
110116
out.compass_bearing = compass_bearing_deg
111117
self.pub.publish(out)
112118

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
rosbag2_bagfile_information:
2+
version: 5
3+
storage_identifier: sqlite3
4+
duration:
5+
nanoseconds: 0
6+
starting_time:
7+
nanoseconds_since_epoch: 9223372036854775807
8+
message_count: 0
9+
topics_with_message_count:
10+
[]
11+
compression_format: ""
12+
compression_mode: ""
13+
relative_file_paths:
14+
- rosbag2_1969_12_31-19_14_31_0.db3
15+
files:
16+
- path: rosbag2_1969_12_31-19_14_31_0.db3
17+
starting_time:
18+
nanoseconds_since_epoch: 9223372036854775807
19+
duration:
20+
nanoseconds: 0
21+
message_count: 0
Binary file not shown.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
rosbag2_bagfile_information:
2+
version: 5
3+
storage_identifier: sqlite3
4+
duration:
5+
nanoseconds: 0
6+
starting_time:
7+
nanoseconds_since_epoch: 9223372036854775807
8+
message_count: 0
9+
topics_with_message_count:
10+
[]
11+
compression_format: ""
12+
compression_mode: ""
13+
relative_file_paths:
14+
- rosbag2_1969_12_31-19_15_26_0.db3
15+
files:
16+
- path: rosbag2_1969_12_31-19_15_26_0.db3
17+
starting_time:
18+
nanoseconds_since_epoch: 9223372036854775807
19+
duration:
20+
nanoseconds: 0
21+
message_count: 0
Binary file not shown.

0 commit comments

Comments
 (0)