27 #include <geometry_msgs/Twist.h> 28 #include <geometry_msgs/Vector3Stamped.h> 29 #include <sensor_msgs/MagneticField.h> 43 void getData(std::vector<sensor_msgs::MagneticField>& data)
49 void callback(
const sensor_msgs::MagneticFieldConstPtr& msg)
51 data_.push_back(*msg);
55 std::vector<sensor_msgs::MagneticField>
data_;
58 int main(
int argc,
char** argv)
60 ros::init(argc, argv,
"magnetometer_calibration");
70 bool soft_iron =
false;
74 ROS_ERROR(
"Soft Iron Calibration Is Not Yet Available.");
81 double rotation_velocity = 0.2;
82 double rotation_duration = 60.0;
83 nh.
getParam(
"rotation_velocity", rotation_velocity);
84 nh.
getParam(
"rotation_duration", rotation_duration);
90 bool rotation_manual =
false;
91 nh.
getParam(
"rotation_manual", rotation_manual);
94 std::string bag_file_name =
"/tmp/magnetometer_calibration.bag";
95 nh.
getParam(
"bag_file_name", bag_file_name);
98 std::string mag_topic_name =
"/imu/mag";
102 std::vector<sensor_msgs::MagneticField> data;
103 if (rotation_velocity <= 0.0 && rotation_duration <= 0.0 && !rotation_manual)
118 for (
auto m : bag_view)
120 sensor_msgs::MagneticField::ConstPtr msg = m.instantiate<sensor_msgs::MagneticField>();
124 geometry_msgs::Vector3Stamped::ConstPtr vec = m.instantiate<geometry_msgs::Vector3Stamped>();
127 sensor_msgs::MagneticField field;
128 field.header = vec->header;
129 field.magnetic_field.x = vec->vector.x;
130 field.magnetic_field.y = vec->vector.y;
131 field.magnetic_field.z = vec->vector.z;
132 data.push_back(field);
137 data.push_back(*msg);
155 ROS_INFO(
"Rotate the sensor to many orientations.");
156 ROS_INFO(
"Press key when done rotating");
157 std::string throwaway;
158 std::getline(std::cin, throwaway);
166 geometry_msgs::Twist msg;
167 msg.angular.z = rotation_velocity;
169 ROS_INFO_STREAM(
"Rotating robot for " << rotation_duration <<
" seconds.");
190 ROS_INFO_STREAM(
"Saving bag file with " << data.size() <<
" samples.");
193 for (
auto msg : data)
195 bag.write(mag_topic_name, msg.header.stamp, msg);
200 size_t num_params = 4;
205 double* free_params =
new double[num_params];
207 free_params[0] = 0.45;
213 for (
auto msg : data)
215 bias_x += msg.magnetic_field.x;
216 bias_y += msg.magnetic_field.y;
217 bias_z += msg.magnetic_field.z;
219 bias_x /= data.size();
220 bias_y /= data.size();
221 bias_z /= data.size();
223 free_params[1] = bias_x;
224 free_params[2] = bias_y;
225 free_params[3] = bias_z;
234 ceres::Problem* problem =
new ceres::Problem();
235 ceres::TrivialLoss loss;
236 for (
auto msg : data)
238 auto m = msg.magnetic_field;
245 problem->AddResidualBlock(
253 ceres::Solver::Options
options;
254 options.use_nonmonotonic_steps =
true;
255 options.function_tolerance = 1e-10;
256 options.linear_solver_type = ceres::DENSE_QR;
257 options.max_num_iterations = 1000;
258 options.minimizer_progress_to_stdout =
false;
260 ceres::Solver::Summary summary;
261 ceres::Solve(options, problem, &summary);
265 ROS_INFO_STREAM(
"Estimated total magnetic field: " << free_params[0] <<
"T");
266 ROS_INFO(
"You can compare to expected values from");
267 ROS_INFO(
" https://www.ngdc.noaa.gov/geomag/calculators/magcalc.shtml#igrfwmm");
269 std::cout <<
"mag_bias_x: " << free_params[1] << std::endl;
270 std::cout <<
"mag_bias_y: " << free_params[2] << std::endl;
271 std::cout <<
"mag_bias_z: " << free_params[3] << std::endl;
272 delete[] free_params;
void publish(const boost::shared_ptr< M > &message) const
void open(std::string const &filename, uint32_t mode=bagmode::Read)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void getData(std::vector< sensor_msgs::MagneticField > &data)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
ROSCPP_DECL std::string resolve(const std::string &name, bool remap=true)
ros::Subscriber subscriber_
MagnetometerCapture(const std::string &topic, ros::NodeHandle &nh)
#define ROS_FATAL_STREAM(args)
static ceres::CostFunction * Create(double x, double y, double z)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void callback(const sensor_msgs::MagneticFieldConstPtr &msg)
int main(int argc, char **argv)
std::vector< sensor_msgs::MagneticField > data_
#define ROS_INFO_STREAM(args)
bool getParam(const std::string &key, std::string &s) const
ROSCPP_DECL void spinOnce()