diff --git a/CMakeLists.txt b/CMakeLists.txt
index 678a309..b4967ee 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,9 +20,10 @@ target_link_libraries(stim300_driver_lib)
find_package(catkin REQUIRED COMPONENTS
roscpp
sensor_msgs
+ std_srvs
)
catkin_package(
- CATKIN_DEPENDS sensor_msgs
+ CATKIN_DEPENDS sensor_msgs std_srvs
)
add_executable(stim300_driver_node src/stim300_driver_node.cpp)
diff --git a/package.xml b/package.xml
index 271e7f7..5d256ea 100644
--- a/package.xml
+++ b/package.xml
@@ -23,10 +23,13 @@
catkin
roscpp
sensor_msgs
+ std_srvs
roscpp
sensor_msgs
+ std_srvs
roscpp
sensor_msgs
+ std_srvs
diff --git a/src/stim300_driver_node.cpp b/src/stim300_driver_node.cpp
index 79d28f7..19e472f 100644
--- a/src/stim300_driver_node.cpp
+++ b/src/stim300_driver_node.cpp
@@ -1,10 +1,70 @@
#include "driver_stim300.h"
#include "serial_unix.h"
-
+#include "math.h"
#include "ros/ros.h"
#include "sensor_msgs/Imu.h"
+#include "std_srvs/Trigger.h"
+#include "std_srvs/Empty.h"
+#include "iostream"
+
+bool calibration_mode{false};
+constexpr int NUMBER_OF_CALIBRATION_SAMPLES{100};
+constexpr double ACC_TOLERANCE{0.1};
+constexpr double MAX_DROPPED_ACC_X_MSG{5};
+constexpr double MAX_DROPPED_ACC_Y_MSG{5};
+constexpr double MAX_DROPPED_ACC_Z_MSG{5};
+constexpr double MAX_DROPPED_GYRO_X_MSG{5};
+constexpr double MAX_DROPPED_GYRO_Y_MSG{5};
+constexpr double MAX_DROPPED_GYRO_Z_MSG{5};
+constexpr double GYRO_X_PEAK_TO_PEAK_NOISE{0.0002};
+constexpr double GYRO_Y_PEAK_TO_PEAK_NOISE{0.0002};
+constexpr double GYRO_Z_PEAK_TO_PEAK_NOISE{0.0002};
+
+struct Quaternion
+{
+ double w, x, y, z;
+};
+
+struct EulerAngles {
+ double roll, pitch, yaw;
+};
+
+Quaternion FromRPYToQuaternion(EulerAngles angles) // yaw (Z), pitch (Y), roll (X)
+{
+ // Abbreviations for the various angular functions
+ double cy = cos(angles.yaw * 0.5);
+ double sy = sin(angles.yaw * 0.5);
+ double cp = cos(angles.pitch * 0.5);
+ double sp = sin(angles.pitch * 0.5);
+ double cr = cos(angles.roll * 0.5);
+ double sr = sin(angles.roll * 0.5);
-int main(int argc, char **argv) {
+ Quaternion q;
+ q.w = cy * cp * cr + sy * sp * sr;
+ q.x = cy * cp * sr - sy * sp * cr;
+ q.y = sy * cp * sr + cy * sp * cr;
+ q.z = sy * cp * cr - cy * sp * sr;
+
+ return q;
+}
+
+
+bool responseCalibrateIMU(std_srvs::Trigger::Request &calibration_request, std_srvs::Trigger::Response &calibration_response)
+{
+
+ if (calibration_mode == false)
+ {
+ calibration_mode = true;
+ calibration_response.message = "IMU in calibration mode ";
+ calibration_response.success = true;
+ }
+
+ return true;
+}
+
+
+int main(int argc, char** argv)
+{
ros::init(argc, argv, "stim300_driver_node");
ros::NodeHandle node;
@@ -15,29 +75,39 @@ int main(int argc, char **argv) {
int sample_rate{0};
double gravity{0};
+
node.param("device_name", device_name, "/dev/ttyUSB0");
- node.param("variance_gyro", variance_gyro, 0.0001);
- node.param("variance_acc", variance_acc, 4.0);
- node.param("sample_rate", sample_rate, 100);
+
+ node.param("variance_gyro", variance_gyro,0.0001*2*4.6*pow(10,-4));
+ node.param("variance_acc", variance_acc, 0.000055);
+ node.param("sample_rate", sample_rate, 125);
+
node.param("gravity", gravity, 9.80665);
+ // These values have been estimated by having beluga in a pool for a couple of minutes, and then calculate the variance for each values
sensor_msgs::Imu stim300msg{};
- stim300msg.orientation_covariance[0] = -1;
- stim300msg.angular_velocity_covariance[0] = variance_gyro;
- stim300msg.angular_velocity_covariance[4] = variance_gyro;
- stim300msg.angular_velocity_covariance[8] = variance_gyro;
- stim300msg.linear_acceleration_covariance[0] = variance_acc;
- stim300msg.linear_acceleration_covariance[4] = variance_acc;
- stim300msg.linear_acceleration_covariance[8] = variance_acc;
- stim300msg.orientation.x = 0;
- stim300msg.orientation.y = 0;
- stim300msg.orientation.z = 0;
+ stim300msg.angular_velocity_covariance[0] = 0.0000027474;
+ stim300msg.angular_velocity_covariance[4] = 0.0000027474;
+ stim300msg.angular_velocity_covariance[8] = 0.000007312;
+ stim300msg.linear_acceleration_covariance[0] = 0.00041915;
+ stim300msg.linear_acceleration_covariance[4] = 0.00041915;
+ stim300msg.linear_acceleration_covariance[8] = 0.000018995;
+ stim300msg.orientation.x = 0.00000024358;
+ stim300msg.orientation.y = 0.00000024358;
+ stim300msg.orientation.z = 0.00000024358;
stim300msg.header.frame_id = "imu_0";
- ros::Publisher imuSensorPublisher =
- node.advertise("imu/data_raw", 1);
- ros::Rate loop_rate(sample_rate);
+ ros::Publisher imuSensorPublisher = node.advertise("imu/data_raw", 1000);
+ //ros::Publisher orientationPublisher = node.advertise("imu/orientation", 1000);
+ ros::ServiceServer service = node.advertiseService("IMU_calibration",responseCalibrateIMU);
+
+
+ // New messages are sent from the sensor with sample_rate
+ // As loop_rate determines how often we check for new data
+ // on the serial buffer, theoretically loop_rate = sample_rate
+ // should be okey, but to be sure we double it
+ ros::Rate loop_rate(sample_rate * 2);
try {
SerialUnix serial_driver(device_name, stim_const::BaudRate::BAUD_921600);
@@ -45,41 +115,226 @@ int main(int argc, char **argv) {
ROS_INFO("STIM300 IMU driver initialized successfully");
- while (ros::ok()) {
- switch (driver_stim300.update()) {
- case Stim300Status::NORMAL:
- break;
- case Stim300Status::OUTSIDE_OPERATING_CONDITIONS:
- ROS_DEBUG("Stim 300 outside operating conditions");
- case Stim300Status::NEW_MEASURMENT:
- stim300msg.header.stamp = ros::Time::now();
- stim300msg.linear_acceleration.x = driver_stim300.getAccX() * gravity;
- stim300msg.linear_acceleration.y = driver_stim300.getAccY() * gravity;
- stim300msg.linear_acceleration.z = driver_stim300.getAccZ() * gravity;
- stim300msg.angular_velocity.x = driver_stim300.getGyroX();
- stim300msg.angular_velocity.y = driver_stim300.getGyroY();
- stim300msg.angular_velocity.z = driver_stim300.getGyroZ();
- imuSensorPublisher.publish(stim300msg);
- break;
- case Stim300Status::CONFIG_CHANGED:
- ROS_INFO("Updated Stim 300 imu config: ");
- ROS_INFO("%s", driver_stim300.printSensorConfig().c_str());
- loop_rate = driver_stim300.getSampleRate() * 2;
- break;
- case Stim300Status::STARTING_SENSOR:
- ROS_INFO("Stim 300 IMU is warming up.");
- break;
- case Stim300Status::SYSTEM_INTEGRITY_ERROR:
- ROS_WARN("Stim 300 IMU system integrity error.");
- break;
- case Stim300Status::OVERLOAD:
- ROS_WARN("Stim 300 IMU overload.");
- break;
- case Stim300Status::ERROR_IN_MEASUREMENT_CHANNEL:
- ROS_WARN("Stim 300 IMU error in measurement channel.");
- break;
- case Stim300Status::ERROR:
- ROS_WARN("Stim 300 IMU: internal error.");
+ int difference_in_dataGram{0};
+ int count_messages{0};
+ int number_of_samples{0};
+ double inclination_x{0};
+ double inclination_y{0};
+ double inclination_z{0};
+
+ double average_calibration_roll{0};
+ double average_calibration_pitch{0};
+ double inclination_x_calibration_sum{0};
+ double inclination_y_calibration_sum{0};
+ double inclination_z_calibration_sum{0};
+ double inclination_x_average{0};
+ double inclination_y_average{0};
+ double inclination_z_average{0};
+
+ // Acc wild point filter
+ std::vector acceleration_buffer_x{};
+ std::vector acceleration_buffer_y{};
+ std::vector acceleration_buffer_z{};
+ double dropped_acceleration_x_msg{0.0};
+ double dropped_acceleration_y_msg{0.0};
+ double dropped_acceleration_z_msg{0.0};
+
+ // Gyro wild point filter
+ std::vector gyro_buffer_x{};
+ std::vector gyro_buffer_y{};
+ std::vector gyro_buffer_z{};
+ double dropped_gyro_x_msg{0.0};
+ double dropped_gyro_y_msg{0.0};
+ double dropped_gyro_z_msg{0.0};
+
+
+
+
+ while (ros::ok())
+ {
+ switch (driver_stim300.update())
+ {
+ case Stim300Status::NORMAL:
+ break;
+ case Stim300Status::OUTSIDE_OPERATING_CONDITIONS:
+ ROS_DEBUG("Stim 300 outside operating conditions");
+ break;
+ case Stim300Status::NEW_MEASURMENT:
+ inclination_x = driver_stim300.getIncX();
+ inclination_y = driver_stim300.getIncY();
+ inclination_z = driver_stim300.getIncZ();
+ Quaternion q;
+ EulerAngles RPY;
+ if (calibration_mode == true)
+ {
+ //std::cout<<"in calibration_mode"< MAX_DROPPED_ACC_X_MSG )
+ {
+ stim300msg.linear_acceleration.x = acceleration_buffer_x.back();
+ dropped_acceleration_x_msg = 0;
+ }
+ else
+ {
+ ROS_DEBUG("ACC_X_MSG wild point rejected");
+ dropped_acceleration_x_msg +=1;
+ }
+
+ if(std::abs(acceleration_buffer_y.back() - acceleration_buffer_y.front()) < ACC_TOLERANCE || dropped_acceleration_y_msg > MAX_DROPPED_ACC_Y_MSG )
+ {
+ stim300msg.linear_acceleration.y = acceleration_buffer_y.back();
+ dropped_acceleration_y_msg = 0;
+ }
+ else
+ {
+ ROS_DEBUG("ACC_Y_MSG wild point rejected");
+ dropped_acceleration_y_msg +=1;
+ }
+
+ if(std::abs(acceleration_buffer_z.back() - acceleration_buffer_z.front()) < ACC_TOLERANCE || dropped_acceleration_z_msg > MAX_DROPPED_ACC_Z_MSG )
+ {
+ stim300msg.linear_acceleration.z = acceleration_buffer_z.back();
+ dropped_acceleration_z_msg = 0;
+ }
+ else
+ {
+ ROS_DEBUG("ACC_Z_MSG wild point rejected");
+ dropped_acceleration_z_msg +=1;
+ }
+ // Empty acceleration buffers
+ acceleration_buffer_x = std::vector{acceleration_buffer_x.back()};
+ acceleration_buffer_y = std::vector{acceleration_buffer_y.back()};
+ acceleration_buffer_z = std::vector{acceleration_buffer_z.back()};
+ }
+ else
+ {
+ stim300msg.linear_acceleration.x = driver_stim300.getAccX() * gravity;
+ stim300msg.linear_acceleration.y = driver_stim300.getAccY() * gravity;
+ stim300msg.linear_acceleration.z = driver_stim300.getAccZ() * gravity;
+ }
+
+ // Gyro wild point filter
+ gyro_buffer_x.push_back(driver_stim300.getGyroX());
+ gyro_buffer_y.push_back(driver_stim300.getGyroY());
+ gyro_buffer_z.push_back(driver_stim300.getGyroZ());
+
+ if(gyro_buffer_x.size() == 2 && gyro_buffer_y.size() == 2 && gyro_buffer_z.size() == 2)
+ {
+
+ if(std::abs(gyro_buffer_x.back() - gyro_buffer_x.front()) < std::max(2*std::abs(gyro_buffer_x.front()),GYRO_X_PEAK_TO_PEAK_NOISE) || dropped_gyro_x_msg > MAX_DROPPED_GYRO_X_MSG)
+ {
+ stim300msg.angular_velocity.x = gyro_buffer_x.back();
+ dropped_gyro_x_msg = 0;
+ }
+ else
+ {
+ ROS_DEBUG("GYRO_X_MSG wild point rejected");
+ dropped_gyro_x_msg += 1;
+ }
+
+ if(std::abs(gyro_buffer_y.back() - gyro_buffer_y.front()) < std::max(2*std::abs(gyro_buffer_y.front()),GYRO_Y_PEAK_TO_PEAK_NOISE) || dropped_gyro_y_msg > MAX_DROPPED_GYRO_Y_MSG)
+ {
+ stim300msg.angular_velocity.x = gyro_buffer_y.back();
+ dropped_gyro_y_msg = 0;
+ }
+ else
+ {
+ ROS_DEBUG("GYRO_Y_MSG wild point rejected");
+ dropped_gyro_y_msg += 1;
+ }
+
+ if(std::abs(gyro_buffer_z.back() - gyro_buffer_z.front()) < std::max(2*std::abs(gyro_buffer_z.front()),GYRO_Z_PEAK_TO_PEAK_NOISE) || dropped_gyro_z_msg > MAX_DROPPED_GYRO_Z_MSG)
+ {
+ stim300msg.angular_velocity.z = gyro_buffer_z.back();
+ dropped_gyro_z_msg = 0;
+ }
+ else
+ {
+ ROS_DEBUG("GYRO_Z_MSG wild point rejected");
+ dropped_gyro_z_msg += 1;
+ }
+
+ // Empty buffers
+ gyro_buffer_x = std::vector{gyro_buffer_x.back()};
+ gyro_buffer_y = std::vector{gyro_buffer_y.back()};
+ gyro_buffer_z = std::vector{gyro_buffer_z.back()};
+ }
+ else
+ {
+ stim300msg.angular_velocity.x = driver_stim300.getGyroX();
+ stim300msg.angular_velocity.y = driver_stim300.getGyroY();
+ stim300msg.angular_velocity.z = driver_stim300.getGyroZ();
+ }
+ stim300msg.orientation.w = q.w;
+ stim300msg.orientation.x = q.x;
+ stim300msg.orientation.y = q.y;
+ stim300msg.orientation.z = q.z;
+ imuSensorPublisher.publish(stim300msg);
+ break;
+ }
+ case Stim300Status::CONFIG_CHANGED:
+ ROS_INFO("Updated Stim 300 imu config: ");
+ ROS_INFO("%s", driver_stim300.printSensorConfig().c_str());
+ loop_rate = driver_stim300.getSampleRate()*2;
+ break;
+ case Stim300Status::STARTING_SENSOR:
+ ROS_INFO("Stim 300 IMU is warming up.");
+ break;
+ case Stim300Status::SYSTEM_INTEGRITY_ERROR:
+ ROS_WARN("Stim 300 IMU system integrity error.");
+ break;
+ case Stim300Status::OVERLOAD:
+ ROS_WARN("Stim 300 IMU overload.");
+ break;
+ case Stim300Status::ERROR_IN_MEASUREMENT_CHANNEL:
+ ROS_WARN("Stim 300 IMU error in measurement channel.");
+ break;
+ case Stim300Status::ERROR:
+ ROS_WARN("Stim 300 IMU: internal error.");
+
}
loop_rate.sleep();