Skip to content

Commit 771d4fa

Browse files
authored
Magnetometer: correct field calculation (#2460)
- The magnetic intensity table has units centi gauss not centi tesla - Add conversion to publish field in telsa. - Field is calculated in NED frame. - Convert to ENU frame for Gazebo world frame convention. Signed-off-by: Rhys Mainwaring <rhys.mainwaring@me.com>
1 parent b8bbf1d commit 771d4fa

File tree

2 files changed

+61
-8
lines changed

2 files changed

+61
-8
lines changed

src/systems/magnetometer/Magnetometer.cc

+54-8
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ static constexpr const int8_t inclination_table[13][37] = \
9898
{ 71, 71, 72, 73, 75, 77, 78, 80, 81, 81, 80, 79, 77, 76, 74, 73, 73, 73, 73, 73, 73, 74, 74, 75, 76, 77, 78, 78, 78, 78, 77, 75, 73, 72, 71, 71, 71 }, // NOLINT
9999
};
100100

101-
// strength data in centi-Tesla
101+
// strength data in centi gauss
102102
static constexpr const int8_t strength_table[13][37] = \
103103
{
104104
{ 62, 60, 58, 56, 54, 52, 49, 46, 43, 41, 38, 36, 34, 32, 31, 31, 30, 30, 30, 31, 33, 35, 38, 42, 46, 51, 55, 59, 62, 64, 66, 67, 67, 66, 65, 64, 62 }, // NOLINT
@@ -134,6 +134,12 @@ class gz::sim::systems::MagnetometerPrivate
134134
/// True if the rendering component is initialized
135135
public: bool initialized = false;
136136

137+
/// \brief True if the magnetic field is reported in gauss rather than tesla.
138+
public: bool useUnitsGauss = true;
139+
140+
/// \brief True if the magnetic field earth frame is NED rather than ENU.
141+
public: bool useEarthFrameNED = true;
142+
137143
/// \brief Create sensor
138144
/// \param[in] _ecm Immutable reference to ECM.
139145
/// \param[in] _entity Entity of the IMU
@@ -226,7 +232,7 @@ class gz::sim::systems::MagnetometerPrivate
226232
return get_table_data(lat, lon, inclination_table);
227233
}
228234

229-
// return magnetic field strength in centi-Tesla
235+
// return magnetic field strength in centi-Gauss
230236
float get_mag_strength(float lat, float lon)
231237
{
232238
return get_table_data(lat, lon, strength_table);
@@ -242,6 +248,29 @@ Magnetometer::Magnetometer() : System(), dataPtr(
242248
//////////////////////////////////////////////////
243249
Magnetometer::~Magnetometer() = default;
244250

251+
//////////////////////////////////////////////////
252+
void Magnetometer::Configure(const Entity &/*_entity*/,
253+
const std::shared_ptr<const sdf::Element> &_sdf,
254+
EntityComponentManager &/*_ecm*/,
255+
EventManager &/*_eventMgr*/)
256+
{
257+
if (_sdf->HasElement("use_units_gauss"))
258+
{
259+
this->dataPtr->useUnitsGauss = _sdf->Get<bool>("use_units_gauss");
260+
}
261+
gzdbg << "Magnetometer: using param [use_units_gauss: "
262+
<< this->dataPtr->useUnitsGauss << "]."
263+
<< std::endl;
264+
265+
if (_sdf->HasElement("use_earth_frame_ned"))
266+
{
267+
this->dataPtr->useEarthFrameNED = _sdf->Get<bool>("use_earth_frame_ned");
268+
}
269+
gzdbg << "Magnetometer: using param [use_earth_frame_ned: "
270+
<< this->dataPtr->useEarthFrameNED << "]."
271+
<< std::endl;
272+
}
273+
245274
//////////////////////////////////////////////////
246275
void Magnetometer::PreUpdate(const UpdateInfo &/*_info*/,
247276
EntityComponentManager &_ecm)
@@ -446,16 +475,32 @@ void MagnetometerPrivate::Update(
446475
get_mag_inclination(
447476
lat_rad * 180 / GZ_PI, lon_rad * 180 / GZ_PI) * GZ_PI / 180;
448477

449-
// Magnetic strength (10^5xnanoTesla)
478+
// Magnetic strength in gauss (10^5 nano tesla = 10^-2 centi gauss)
450479
float strength_ga =
451480
0.01f *
452481
get_mag_strength(lat_rad * 180 / GZ_PI, lon_rad * 180 / GZ_PI);
453482

454-
// Magnetic filed components are calculated by http://geomag.nrcan.gc.ca/mag_fld/comp-en.php
455-
float H = strength_ga * cosf(inclination_rad);
456-
float Z = tanf(inclination_rad) * H;
457-
float X = H * cosf(declination_rad);
458-
float Y = H * sinf(declination_rad);
483+
// Magnetic intensity measured in telsa
484+
float strength_tesla = 1.0E-4 * strength_ga;
485+
486+
// Magnetic field components are calculated in world NED frame using:
487+
// http://geomag.nrcan.gc.ca/mag_fld/comp-en.php
488+
float H = cosf(inclination_rad);
489+
H *= this->useUnitsGauss ? strength_ga : strength_tesla;
490+
float Z_ned = tanf(inclination_rad) * H;
491+
float X_ned = H * cosf(declination_rad);
492+
float Y_ned = H * sinf(declination_rad);
493+
494+
float X = X_ned;
495+
float Y = Y_ned;
496+
float Z = Z_ned;
497+
if (!this->useEarthFrameNED)
498+
{
499+
// Use ENU convention for earth frame.
500+
X = Y_ned;
501+
Y = X_ned;
502+
Z = -1.0 * Z_ned;
503+
}
459504

460505
math::Vector3d magnetic_field_I(X, Y, Z);
461506
it->second->SetWorldMagneticField(magnetic_field_I);
@@ -494,6 +539,7 @@ void MagnetometerPrivate::RemoveMagnetometerEntities(
494539
}
495540

496541
GZ_ADD_PLUGIN(Magnetometer, System,
542+
Magnetometer::ISystemConfigure,
497543
Magnetometer::ISystemPreUpdate,
498544
Magnetometer::ISystemPostUpdate
499545
)

src/systems/magnetometer/Magnetometer.hh

+7
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace systems
3737
/// current location.
3838
class Magnetometer:
3939
public System,
40+
public ISystemConfigure,
4041
public ISystemPreUpdate,
4142
public ISystemPostUpdate
4243
{
@@ -46,6 +47,12 @@ namespace systems
4647
/// \brief Destructor
4748
public: ~Magnetometer() override;
4849

50+
// Documentation inherited
51+
public: void Configure(const Entity &_entity,
52+
const std::shared_ptr<const sdf::Element> &_sdf,
53+
EntityComponentManager &_ecm,
54+
EventManager &_eventMgr) override;
55+
4956
/// Documentation inherited
5057
public: void PreUpdate(const UpdateInfo &_info,
5158
EntityComponentManager &_ecm) final;

0 commit comments

Comments
 (0)