orientation_filter.cpp
Go to the documentation of this file.
00001 
00012 #include <carl_phidgets/orientation_filter.h>
00013 
00014 OrientationFilter::OrientationFilter()
00015 {
00016   //initialize joint states
00017   jointStates.name.push_back("base_footprint_base_link_pitch_joint");
00018   jointStates.name.push_back("base_footprint_base_link_roll_joint");
00019   jointStates.name.push_back("left_rear_strut_link_left_rear_strut_top_link_joint");
00020   jointStates.name.push_back("right_rear_strut_link_right_rear_strut_top_link_joint");
00021   jointStates.position.resize(4);
00022   jointStates.velocity.resize(4);
00023   jointStates.effort.resize(4);
00024 
00025   baseOrientationInitialized = false;
00026   output = false;
00027 
00028   // create the ROS topics
00029   frameJointStatePublisher = n.advertise<sensor_msgs::JointState>("frame_joint_states", 1);
00030   baseImuSubscriber = n.subscribe<sensor_msgs::Imu>("imu_base/data_raw", 1, &OrientationFilter::baseImuCallback, this);
00031   topImuSubscriber = n.subscribe<sensor_msgs::Imu>("imu_top/data_raw", 1, &OrientationFilter::topImuCallback, this);
00032 
00033   //initialize filter stuff
00034   prevUpdateTimeTop = ros::Time::now();
00035   prevUpdateTime = ros::Time::now();
00036   PPrevTop = 0;
00037   PPrev[0] = 0;
00038   PPrev[1] = 0;
00039 }
00040 
00041 void OrientationFilter::topImuCallback(const sensor_msgs::Imu::ConstPtr& data)
00042 {
00043   if (!baseOrientationInitialized)
00044   {
00045     if (!output)
00046     {
00047       ROS_INFO("Waiting for base orientation to be initialized before calculating frame pitch...");
00048       output = true;
00049     }
00050     return;
00051   }
00052 
00053   /**************************** Read IMU data *****************************/
00054   //gyro measurement
00055   float w = data->angular_velocity.y;
00056 
00057   //gyro covariance
00058   float Q = data->angular_velocity_covariance[4];
00059 
00060   //accelerometer measurement
00061   float x = data->linear_acceleration.x;
00062   float y = data->linear_acceleration.y;
00063   float z = data->linear_acceleration.z;
00064   float a = atan2(x, z) + jointStates.position[0]; //frame pitch
00065 
00066   //accelerometer covariance
00067   float R = 100*data->linear_acceleration_covariance[4];
00068   //NOTE: this value is adjusted to bias the filter towards preferring the gyro measurements
00069 
00070   //Previous orientation
00071   float thetaPrev = jointStates.position[3];
00072 
00073   //Time step
00074   float deltaT = (ros::Time::now() - prevUpdateTimeTop).toSec();
00075   //update time for next time step
00076   prevUpdateTimeTop = ros::Time::now();
00077 
00078   /******************** Calculate Filtered Orientation ********************/
00079   float thetaPredicted = thetaPrev + w*deltaT;
00080   float P = PPrevTop + Q;
00081 
00082   float J = P/(P + R);
00083   //if significant acceleration other than gravity is detected, don't use the accelerometer measurement
00084   float pitch;
00085   if (fabs(G - sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2))) < .05)
00086     pitch = thetaPredicted + J*(a - thetaPredicted);
00087   else
00088     pitch = thetaPredicted;
00089   //update P for next time step
00090   PPrevTop = (1 - J)*P;
00091 
00092   /*
00093   float x = data->linear_acceleration.x; //value is inverted to account for IMU mounting angle
00094   float z = data->linear_acceleration.z;
00095   float pitch = atan2(x, z) + jointStates.position[0];
00096   */
00097 
00098   jointStates.position[2] = -pitch;  //left strut
00099   jointStates.position[3] = pitch; //right strut
00100   frameJointStatePublisher.publish(jointStates);
00101 }
00102 
00103 void OrientationFilter::baseImuCallback(const sensor_msgs::Imu::ConstPtr& data)
00104 {
00105   /**************************** Read IMU data *****************************/
00106   //gyro measurement
00107   float w[2];
00108   w[0] = -data->angular_velocity.x; //value is inverted to account for IMU mounting angle
00109   w[1] = data->angular_velocity.y;
00110 
00111   //gyro covariance
00112   float Q[2];
00113   Q[0] = data->angular_velocity_covariance[0];
00114   Q[1] = data->angular_velocity_covariance[4];
00115 
00116   //accelerometer measurement
00117   float x = -data->linear_acceleration.x; //value is inverted to account for IMU mounting angle
00118   float y = data->linear_acceleration.y;
00119   float z = -data->linear_acceleration.z; //value is inverted to account for IMU mounting angle
00120   float a[2];
00121   a[0] = atan2(y, z); //base pitch
00122   a[1] = atan2(x, z); //base roll
00123 
00124   //accelerometer covariance
00125   float R[2];
00126   R[0] = 100*data->linear_acceleration_covariance[0];
00127   R[1] = 100*data->linear_acceleration_covariance[4];
00128   //NOTE: these values are adjusted to bias the filter towards preferring the gyro measurements
00129 
00130   //Previous orientation
00131   float thetaPrev[2];
00132   thetaPrev[0] = jointStates.position[0];
00133   thetaPrev[1] = jointStates.position[1];
00134 
00135   //Time step
00136   float deltaT = (ros::Time::now() - prevUpdateTime).toSec();
00137   //update time for next time step
00138   prevUpdateTime = ros::Time::now();
00139 
00140   /******************** Calculate Filtered Orientation ********************/
00141   float thetaPredicted[2];
00142   float P[2];
00143   float J[2];
00144   thetaPredicted[0] = thetaPrev[0] + w[0]*deltaT;
00145   thetaPredicted[1] = thetaPrev[1] + w[1]*deltaT;
00146   P[0] = PPrev[0] + Q[0];
00147   P[1] = PPrev[1] + Q[1];
00148   J[0] = P[0]/(P[0] + R[0]);
00149   J[1] = P[1]/(P[1] + R[1]);
00150 
00151   //if significant acceleration other than gravity is detected, don't use the accelerometer measurement
00152   if (fabs(G - sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2))) < .05)
00153   {
00154     jointStates.position[0] = thetaPredicted[0] + J[0]*(a[0] - thetaPredicted[0]);
00155     jointStates.position[1] = thetaPredicted[1] + J[1]*(a[1] - thetaPredicted[1]);
00156   }
00157   else
00158   {
00159     jointStates.position[0] = thetaPredicted[0];
00160     jointStates.position[1] = thetaPredicted[1];
00161   }
00162   //update P for next time step
00163   PPrev[0] = (1 - J[0])*P[0];
00164   PPrev[1] = (1 - J[1])*P[1];
00165 
00166   //ROS_INFO("a:%f, w:%f Q:%f, R:%f, P:%f, J:%f, thetaPrev:%f, thetaPredicted:%f, theta:%f", a[1], w[1], Q[1], R[1], P[1], J[1], thetaPrev[1], thetaPredicted[1], jointStates.position[1]);
00167 
00168   /*
00169   jointStates.position[0] = atan2(y, z);  //base pitch
00170   jointStates.position[1] = atan2(x, z);  //base roll
00171   */
00172   frameJointStatePublisher.publish(jointStates);
00173 
00174   if (!baseOrientationInitialized)
00175   {
00176     ROS_INFO("Base orientation initialized!");
00177     baseOrientationInitialized = true;
00178   }
00179 }
00180 
00181 int main(int argc, char **argv)
00182 {
00183   // initialize ROS and the node
00184   ros::init(argc, argv, "orientation_filter");
00185 
00186   // initialize the joystick controller
00187   OrientationFilter of;
00188 
00189   ros::spin();
00190 
00191   return EXIT_SUCCESS;
00192 }


carl_phidgets
Author(s): David Kent , Russell Toris
autogenerated on Thu Jun 6 2019 21:09:54