00001 #include "evarobot_minimu9/evarobot_minimu9.h"
00002
00003 #include <dynamic_reconfigure/server.h>
00004 #include <evarobot_minimu9/ParamsConfig.h>
00005
00006 int i_error_code = 0;
00007
00008 std::ostream & operator << (std::ostream & os, const vector & vector)
00009 {
00010 return os << FLOAT_FORMAT << vector(0) << ' '
00011 << FLOAT_FORMAT << vector(1) << ' '
00012 << FLOAT_FORMAT << vector(2);
00013 }
00014
00015 std::ostream & operator << (std::ostream & os, const matrix & matrix)
00016 {
00017 return os << (vector)matrix.row(0) << ' '
00018 << (vector)matrix.row(1) << ' '
00019 << (vector)matrix.row(2);
00020 }
00021
00022 std::ostream & operator << (std::ostream & os, const quaternion & quat)
00023 {
00024 return os << FLOAT_FORMAT << quat.w() << ' '
00025 << FLOAT_FORMAT << quat.x() << ' '
00026 << FLOAT_FORMAT << quat.y() << ' '
00027 << FLOAT_FORMAT << quat.z();
00028 }
00029
00030 typedef void rotation_output_function(quaternion& rotation);
00031
00032 void output_quaternion(quaternion & rotation)
00033 {
00034 ROS_DEBUG_STREAM("EvarobotIMU: " << rotation);
00035 }
00036
00037 void output_matrix(quaternion & rotation)
00038 {
00039 ROS_DEBUG_STREAM("EvarobotIMU: " << rotation.toRotationMatrix());
00040 }
00041
00042 void output_euler(quaternion & rotation)
00043 {
00044 ROS_DEBUG_STREAM("EvarobotIMU: " << (vector)(rotation.toRotationMatrix().eulerAngles(2, 1, 0) * (180 / M_PI)));
00045 }
00046
00047 int millis()
00048 {
00049 struct timeval tv;
00050 gettimeofday(&tv, NULL);
00051 return (tv.tv_sec) * 1000 + (tv.tv_usec)/1000;
00052 }
00053
00054 void streamRawValues(IMU& imu, int count)
00055 {
00056 imu.enable();
00057 for(int i = 0; i < count; i++)
00058 {
00059 imu.read();
00060 printf("%7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
00061 imu.raw_m[0], imu.raw_m[1], imu.raw_m[2],
00062 imu.raw_a[0], imu.raw_a[1], imu.raw_a[2],
00063 imu.raw_g[0], imu.raw_g[1], imu.raw_g[2]
00064 );
00065 usleep(20*1000);
00066 }
00067 }
00068
00070
00071
00072
00073 matrix rotationFromCompass(const vector& acceleration, const vector& magnetic_field)
00074 {
00075 vector down = -acceleration;
00076 vector east = down.cross(magnetic_field);
00077 vector north = east.cross(down);
00078
00079 east.normalize();
00080 north.normalize();
00081 down.normalize();
00082
00083 matrix r;
00084 r.row(0) = north;
00085 r.row(1) = east;
00086 r.row(2) = down;
00087 return r;
00088 }
00089
00090 typedef void fuse_function(quaternion& rotation, float dt, const vector& angular_velocity,
00091 const vector& acceleration, const vector& magnetic_field);
00092
00093 void fuse_compass_only(quaternion& rotation, float dt, const vector& angular_velocity,
00094 const vector& acceleration, const vector& magnetic_field)
00095 {
00096
00097 rotation = rotationFromCompass(acceleration, magnetic_field);
00098 }
00099
00100
00101
00102
00103
00104 void rotate(quaternion& rotation, const vector& w, float dt)
00105 {
00106
00107
00108 rotation *= quaternion(1, w(0)*dt/2, w(1)*dt/2, w(2)*dt/2);
00109 rotation.normalize();
00110 }
00111
00112 void fuse_gyro_only(quaternion& rotation, float dt, const vector& angular_velocity,
00113 const vector& acceleration, const vector& magnetic_field)
00114 {
00115 rotate(rotation, angular_velocity, dt);
00116 }
00117
00118 void fuse_default(quaternion& rotation, float dt, const vector& angular_velocity,
00119 const vector& acceleration, const vector& magnetic_field)
00120 {
00121 vector correction = vector(0, 0, 0);
00122
00123 if (abs(acceleration.norm() - 1) <= 0.3)
00124 {
00125
00126
00127
00128 const float correction_strength = 1;
00129
00130 matrix rotationCompass = rotationFromCompass(acceleration, magnetic_field);
00131 matrix rotationMatrix = rotation.toRotationMatrix();
00132
00133 correction = (
00134 rotationCompass.row(0).cross(rotationMatrix.row(0)) +
00135 rotationCompass.row(1).cross(rotationMatrix.row(1)) +
00136 rotationCompass.row(2).cross(rotationMatrix.row(2))
00137 ) * correction_strength;
00138
00139 }
00140
00141 rotate(rotation, angular_velocity + correction, dt);
00142 }
00143
00144 void ahrs(IMU & imu, fuse_function * fuse, rotation_output_function * output)
00145 {
00146 imu.loadCalibration();
00147 imu.enable();
00148 imu.measureOffsets();
00149
00150
00151
00152 quaternion rotation = quaternion::Identity();
00153
00154 int start = millis();
00155 while(1)
00156 {
00157 int last_start = start;
00158 start = millis();
00159 float dt = (start-last_start)/1000.0;
00160 if (dt < 0){
00161 ROS_INFO(GetErrorDescription(-107).c_str());
00162 i_error_code = -107;
00163 throw std::runtime_error("Time went backwards.");
00164 }
00165
00166 vector angular_velocity = imu.readGyro();
00167 vector acceleration = imu.readAcc();
00168 vector magnetic_field = imu.readMag();
00169
00170 fuse(rotation, dt, angular_velocity, acceleration, magnetic_field);
00171
00172 output(rotation);
00173
00174
00175
00176 while(millis() - start < 20)
00177 {
00178 usleep(1000);
00179 }
00180 }
00181 }
00182
00183 bool b_is_received_params = false;
00184
00185 void CallbackReconfigure(evarobot_minimu9::ParamsConfig &config, uint32_t level)
00186 {
00187 b_is_received_params = true;
00188 }
00189
00190 void ProduceDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
00191 {
00192 if(i_error_code<0)
00193 {
00194 stat.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "%s", GetErrorDescription(i_error_code).c_str());
00195 i_error_code = 0;
00196 }
00197 else
00198 {
00199 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "EvarobotIMU: No problem.");
00200 }
00201 }
00202
00203
00204 int main(int argc, char *argv[])
00205 {
00206
00207 key_t key;
00208 sem_t *mutex;
00209 FILE * fd;
00210
00211 std::stringstream ss;
00212
00213
00214 double d_frequency;
00215 double d_min_freq, d_max_freq;
00216
00217
00218
00219 key = 1005;
00220
00221
00222
00223
00224 mutex = sem_open(SEM_NAME,O_CREAT,0644,1);
00225 if(mutex == SEM_FAILED)
00226 {
00227 ROS_INFO(GetErrorDescription(-105).c_str());
00228 i_error_code = -105;
00229 sem_unlink(SEM_NAME);
00230
00231 return(-1);
00232 }
00233
00234
00235 std::string mode, output_mode, i2cDevice;
00236
00237 ros::init(argc, argv, "evarobot_minimu9");
00238 ros::NodeHandle n;
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 n.param<std::string>("evarobot_minimu9/i2cDevice", i2cDevice, "/dev/i2c-1");
00249 n.param("evarobot_odometry/minFreq", d_min_freq, 0.2);
00250 n.param("evarobot_odometry/maxFreq", d_max_freq, 10.0);
00251 n.param("evarobot_minimu9/frequency", d_frequency, 10.0);
00252
00253
00254
00255
00256
00257 realtime_tools::RealtimePublisher<sensor_msgs::Imu> * imu_pub = new realtime_tools::RealtimePublisher<sensor_msgs::Imu>(n, "imu", 10);
00258
00259
00260 dynamic_reconfigure::Server<evarobot_minimu9::ParamsConfig> srv;
00261 dynamic_reconfigure::Server<evarobot_minimu9::ParamsConfig>::CallbackType f;
00262 f = boost::bind(&CallbackReconfigure, _1, _2);
00263 srv.setCallback(f);
00265
00266
00267 diagnostic_updater::Updater updater;
00268 updater.setHardwareID("minimu9");
00269 updater.add("imu", &ProduceDiagnostics);
00270 diagnostic_updater::HeaderlessTopicDiagnostic pub_freq("imu", updater,
00271 diagnostic_updater::FrequencyStatusParam(&d_min_freq, &d_max_freq, 0.1, 10));
00272
00273 output_mode = "matrix";
00274 mode = "normal";
00275
00276 MinIMU9 imu(i2cDevice.c_str());
00277
00278 if (argc == 2 && atoi(argv[1]) > 0)
00279 {
00280 ROS_DEBUG("raw mode");
00281 streamRawValues(imu, atoi(argv[1]));
00282 return 0;
00283 }
00284
00285
00286 try
00287 {
00288 ROS_DEBUG("imu mode");
00289
00290
00291
00292 imu.loadCalibration();
00293 imu.enable();
00294 imu.measureOffsets();
00295
00296
00297
00298 quaternion rotation = quaternion::Identity();
00299
00300 int start = millis();
00301 while(ros::ok())
00302 {
00303
00304 if(b_is_received_params)
00305 {
00306 ROS_DEBUG("EvarobotIMU: Updating IMU Params...");
00307
00308 b_is_received_params = false;
00309 }
00310
00311 int last_start = start;
00312 start = millis();
00313 float dt = (start-last_start)/1000.0;
00314 if (dt < 0){
00315 ROS_INFO(GetErrorDescription(-107).c_str());
00316 i_error_code = -107;
00317 throw std::runtime_error("Time went backwards.");
00318 }
00319
00320 vector angular_velocity = imu.readGyro();
00321 vector acceleration = imu.readAcc();
00322 vector magnetic_field = imu.readMag();
00323
00324 sem_wait(mutex);
00325 fuse_default(rotation, dt, angular_velocity, acceleration, magnetic_field);
00326 sem_post(mutex);
00327
00328 double roll, pitch, yaw;
00329 double qx, qy, qz, qw;
00330 vector euler_angles;
00331
00332 euler_angles = (vector)(rotation.toRotationMatrix().eulerAngles(2, 1, 0));
00333
00334 roll = euler_angles(2);
00335 pitch = -euler_angles(1);
00336 yaw = -euler_angles(0);
00337
00338 qx = sin(roll*0.5) * cos(pitch*0.5) * cos(yaw*0.5) - cos(roll*0.5) * sin(pitch*0.5) * sin(yaw*0.5);
00339 qy = cos(roll*0.5) * sin(pitch*0.5) * cos(yaw*0.5) + sin(roll*0.5) * cos(pitch*0.5) * sin(yaw*0.5);
00340 qz = cos(roll*0.5) * cos(pitch*0.5) * sin(yaw*0.5) - sin(roll*0.5) * sin(pitch*0.5) * cos(yaw*0.5);
00341 qw = cos(roll*0.5) * cos(pitch*0.5) * cos(yaw*0.5) + sin(roll*0.5) * sin(pitch*0.5) * sin(yaw*0.5);
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 ss.str("");
00352 ss << n.resolveName(n.getNamespace(), true) << "/imu_link";
00353 imu_pub->msg_.header.frame_id = ss.str();
00354 imu_pub->msg_.header.stamp = ros::Time::now();
00355
00356 imu_pub->msg_.orientation.x = qx;
00357 imu_pub->msg_.orientation.y = qy;
00358 imu_pub->msg_.orientation.z = qz;
00359 imu_pub->msg_.orientation.w = qw;
00360
00361 if (imu_pub->trylock())
00362 {
00363 imu_pub->unlockAndPublish();
00364 }
00365 pub_freq.tick();
00366
00367 updater.update();
00368 ros::spinOnce();
00369
00370
00371
00372 while(millis() - start < 20)
00373 {
00374 usleep(1000);
00375 }
00376 }
00377
00378
00379 sem_unlink(SEM_NAME);
00380
00381 return 0;
00382 }
00383 catch(const std::system_error & error)
00384 {
00385 std::string what = error.what();
00386 const std::error_code & code = error.code();
00387 ROS_INFO_STREAM("[ERROR] EvarobotIMU: " << what << " " << code.message() << " (" << code << ")");
00388 ROS_ERROR_STREAM("[ERROR] EvarobotIMU: " << what << " " << code.message() << " (" << code << ")");
00389 return 2;
00390 }
00391 catch(const opts::multiple_occurrences & error)
00392 {
00393 ROS_INFO_STREAM("[ERROR] EvarobotIMU: " << error.what() << " of " << error.get_option_name() << " option.");
00394 ROS_ERROR_STREAM("[ERROR] EvarobotIMU: " << error.what() << " of " << error.get_option_name() << " option.");
00395 return 1;
00396 }
00397 catch(const std::exception & error)
00398 {
00399 ROS_INFO_STREAM("[ERROR] EvarobotIMU: " << error.what());
00400 ROS_ERROR_STREAM("[ERROR] EvarobotIMU: " << error.what());
00401 return 9;
00402 }
00403 }
00404