From 508957b901d4c8b57e287a90cc8e5950d64506ae Mon Sep 17 00:00:00 2001 From: Paul D'Angio <pcdangio@gmail.com> Date: Mon, 26 Oct 2020 21:16:06 -0400 Subject: [PATCH] added gyroscope calibration service and routine --- driver_mpu9250/CMakeLists.txt | 1 + driver_mpu9250/package.xml | 1 + driver_mpu9250/src/calibration.cpp | 4 ++ driver_mpu9250/src/calibration.h | 4 ++ driver_mpu9250/src/ros_node.cpp | 67 ++++++++++++++++++++++++++++++ driver_mpu9250/src/ros_node.h | 23 +++++++++- 6 files changed, 99 insertions(+), 1 deletion(-) diff --git a/driver_mpu9250/CMakeLists.txt b/driver_mpu9250/CMakeLists.txt index 8655047..f83966c 100644 --- a/driver_mpu9250/CMakeLists.txt +++ b/driver_mpu9250/CMakeLists.txt @@ -9,6 +9,7 @@ add_compile_options(-std=c++11) ## is used, also find other catkin packages find_package(catkin REQUIRED COMPONENTS roscpp + driver_mpu9250_msgs sensor_msgs_ext ) diff --git a/driver_mpu9250/package.xml b/driver_mpu9250/package.xml index aabfc13..f7b34db 100644 --- a/driver_mpu9250/package.xml +++ b/driver_mpu9250/package.xml @@ -10,6 +10,7 @@ <buildtool_depend>catkin</buildtool_depend> <depend>roscpp</depend> + <depend>driver_mpu9250_msgs</depend> <depend>sensor_msgs_ext</depend> </package> diff --git a/driver_mpu9250/src/calibration.cpp b/driver_mpu9250/src/calibration.cpp index e1be334..2ef0c54 100644 --- a/driver_mpu9250/src/calibration.cpp +++ b/driver_mpu9250/src/calibration.cpp @@ -40,6 +40,10 @@ void calibration::load(ros::NodeHandle& node_handle, std::string param_name) } } } +void calibration::update(const Eigen::Matrix4d& new_transform) +{ + calibration::m_calibration = new_transform; +} // CALIBRATION void calibration::calibrate(double& x, double& y, double& z) diff --git a/driver_mpu9250/src/calibration.h b/driver_mpu9250/src/calibration.h index 357e02c..9e54531 100644 --- a/driver_mpu9250/src/calibration.h +++ b/driver_mpu9250/src/calibration.h @@ -15,11 +15,15 @@ public: /// \brief Creates a new calibration instance with a unity calibration matrix. calibration(); + // CONFIGURATION /// \brief Loads a calibration matrix from a ROS parameter. /// \param node_handle The node handle to read the parameter from. /// \param param_name The name of the ROS parameter to read from. /// \note If the parameter doesn't exist or is invalid, the calibration remains unchanged. void load(ros::NodeHandle& node_handle, std::string param_name); + /// \brief Updates the calibration's transformation matrix. + /// \param new_calibration The new transformation matrix to set. + void update(const Eigen::Matrix4d& new_transform); // CALIBRATION /// \brief Performs an in-place calibration on a 3D point. diff --git a/driver_mpu9250/src/ros_node.cpp b/driver_mpu9250/src/ros_node.cpp index d7f9213..2c26b76 100644 --- a/driver_mpu9250/src/ros_node.cpp +++ b/driver_mpu9250/src/ros_node.cpp @@ -10,6 +10,9 @@ // CONSTRUCTORS ros_node::ros_node(driver *driver, int argc, char **argv) { + // Initialize flags. + ros_node::f_gyroscope_calibrating = false; + // Create a new driver. ros_node::m_driver = driver; @@ -63,6 +66,9 @@ ros_node::ros_node(driver *driver, int argc, char **argv) // Quit the node. ros::shutdown(); } + + // Perform initial gyroscope calibration. + ros_node::calibrate_gyroscope(500); } ros_node::~ros_node() { @@ -81,6 +87,67 @@ void ros_node::spin() ros_node::deinitialize_driver(); } +// SERVICES +bool ros_node::service_calibrate_gyroscope(driver_mpu9250_msgs::calibrate_gyroscopeRequest& request, driver_mpu9250_msgs::calibrate_gyroscopeResponse& response) +{ + response.success = ros_node::calibrate_gyroscope(request.averaging_period); + if(!response.success) + { + response.message = "failed to collect enough points for calibration"; + } + + return true; +} +bool ros_node::calibrate_gyroscope(uint32_t averaging_period) +{ + // Convert averaging period to duration. + ros::Duration averaging_duration(static_cast<double>(averaging_period) / 1000.0); + + // Clear the collection window. + ros_node::m_gyroscope_calibration_window.clear(); + + // Enable the data collection. + ros_node::f_gyroscope_calibrating = true; + + // Sleep while gyro data is collected on interrupt thread. + averaging_duration.sleep(); + + // Disable the data collection. + ros_node::f_gyroscope_calibrating = false; + + // Check if the window contains data. + if(ros_node::m_gyroscope_calibration_window.size() < 5) + { + ROS_ERROR_STREAM("gyroscope calibration failed (not enough data: " << ros_node::m_gyroscope_calibration_window.size() << " points)"); + return false; + } + + // Iterate through window to calculate average. + Eigen::Vector3d average; + average.setZero(); + for(auto point = ros_node::m_gyroscope_calibration_window.cbegin(); point != ros_node::m_gyroscope_calibration_window.cend(); ++point) + { + average += *point; + } + average /= static_cast<double>(ros_node::m_gyroscope_calibration_window.size()); + + // Clear window. + ros_node::m_gyroscope_calibration_window.clear(); + + // Create new homogeneous transform by subtracting out bias. + Eigen::Matrix4d calibration; + calibration.setIdentity(); + calibration.block(0, 3, 3, 1) = -average; + + // Update gyroscope calibration. + ros_node::m_calibration_gyroscope.update(calibration); + + // Log success. + ROS_INFO_STREAM("gyroscope calibration completed with averaging period of " << averaging_period << " ms"); + + return true; +} + // METHODS void ros_node::deinitialize_driver() { diff --git a/driver_mpu9250/src/ros_node.h b/driver_mpu9250/src/ros_node.h index f533bd9..b4e93df 100644 --- a/driver_mpu9250/src/ros_node.h +++ b/driver_mpu9250/src/ros_node.h @@ -7,7 +7,9 @@ #include "calibration.h" #include <ros/ros.h> -#include <std_srvs/Trigger.h> +#include <driver_mpu9250_msgs/calibrate_gyroscope.h> + +#include <deque> /// \brief Implements the driver's ROS node functionality. class ros_node @@ -38,6 +40,16 @@ private: /// \brief The magnetometer's calibration. calibration m_calibration_magnetometer; + // GYROSCOPE CALIBRATION + /// \brief The calibration data window for the gyroscope. + std::deque<Eigen::Vector3d> m_gyroscope_calibration_window; + /// \brief Flag indiciating if the gyroscope is currently calibrating. + std::atomic<bool> f_gyroscope_calibrating; + /// \brief Runs a zero-velocity calibration on the gyroscope to remove bias. + /// \param averaging_period The number of milliseconds to average data over to calculate bias. + /// \returns TRUE if the calibration succeeded, otherwise FALSE. + bool calibrate_gyroscope(uint32_t averaging_period); + // ROS /// \brief m_node The node's handle. ros::NodeHandle* m_node; @@ -52,6 +64,15 @@ private: /// \brief Publisher for temperature data. ros::Publisher m_publisher_temperature; + // SERVICES + /// \brief Service server for calibrating the gyroscope. + ros::ServiceServer m_service_calibrate_gyroscope; + /// \brief A service for calibrating the gyroscope. + /// \param request The service request. + /// \param response The service response. + /// \returns TRUE if the service completed successfully, otherwise FALSE. + bool service_calibrate_gyroscope(driver_mpu9250_msgs::calibrate_gyroscopeRequest& request, driver_mpu9250_msgs::calibrate_gyroscopeResponse& response); + // METHODS /// \brief deinitialize_driver Deinitializes the driver. void deinitialize_driver(); -- GitLab