/// \brief This function adds noise to acceleration and angular rates for /// accelerometer and gyroscope measurement simulation. void GazeboImuPlugin::addNoise(Eigen::Vector3d* linear_acceleration, Eigen::Vector3d* angular_velocity, const double dt) { ROS_ASSERT(linear_acceleration != nullptr); ROS_ASSERT(angular_velocity != nullptr); ROS_ASSERT(dt > 0.0); // Gyrosocpe double tau_g = imu_parameters_.gyroscope_bias_correlation_time; // Discrete-time standard deviation equivalent to an "integrating" sampler // with integration time dt. double sigma_g_d = 1 / sqrt(dt) * imu_parameters_.gyroscope_noise_density; double sigma_b_g = imu_parameters_.gyroscope_random_walk; // Compute exact covariance of the process after dt [Maybeck 4-114]. double sigma_b_g_d = sqrt( - sigma_b_g * sigma_b_g * tau_g / 2.0 * (exp(-2.0 * dt / tau_g) - 1.0)); // Compute state-transition. double phi_g_d = exp(-1.0 / tau_g * dt); // Simulate gyroscope noise processes and add them to the true angular rate. for (int i = 0; i < 3; ++i) { gyroscope_bias_[i] = phi_g_d * gyroscope_bias_[i] + sigma_b_g_d * standard_normal_distribution_(random_generator_); (*angular_velocity)[i] = (*angular_velocity)[i] + gyroscope_bias_[i] + sigma_g_d * standard_normal_distribution_(random_generator_) + gyroscope_turn_on_bias_[i]; } // Accelerometer double tau_a = imu_parameters_.accelerometer_bias_correlation_time; // Discrete-time standard deviation equivalent to an "integrating" sampler // with integration time dt. double sigma_a_d = 1 / sqrt(dt) * imu_parameters_.accelerometer_noise_density; double sigma_b_a = imu_parameters_.accelerometer_random_walk; // Compute exact covariance of the process after dt [Maybeck 4-114]. double sigma_b_a_d = sqrt( - sigma_b_a * sigma_b_a * tau_a / 2.0 * (exp(-2.0 * dt / tau_a) - 1.0)); // Compute state-transition. double phi_a_d = exp(-1.0 / tau_a * dt); // Simulate accelerometer noise processes and add them to the true linear // acceleration. for (int i = 0; i < 3; ++i) { accelerometer_bias_[i] = phi_a_d * accelerometer_bias_[i] + sigma_b_a_d * standard_normal_distribution_(random_generator_); (*linear_acceleration)[i] = (*linear_acceleration)[i] + accelerometer_bias_[i] + sigma_a_d * standard_normal_distribution_(random_generator_) + accelerometer_turn_on_bias_[i]; } }
void GazeboAltimeterPlugin::OnUpdate(const common::UpdateInfo& _info) { // check if time to publish common::Time current_time = world_->GetSimTime(); if((current_time - last_time_).Double() > 1.0/pub_rate_){ // pull z measurement out of Gazebo math::Pose current_state_LFU = link_->GetWorldPose(); alt_message_.range = current_state_LFU.pos.z; // zero measurement when messages are out of range if(alt_message_.range > max_range_ || alt_message_.range < min_range_){ alt_message_.range = 0.0; } // add noise, if requested if(alt_noise_on_){ alt_message_.range += standard_normal_distribution_(random_generator_); } // publish message alt_message_.header.stamp = ros::Time::now(); if(publish_float_) { std_msgs::Float32 msg; msg.data = alt_message_.range; alt_pub_.publish(msg); } else alt_pub_.publish(alt_message_); last_time_ = current_time; } }
void GazeboMavlinkInterface::ImuCallback(ImuPtr& imu_message) { math::Pose T_W_I = model_->GetWorldPose(); math::Vector3 pos_W_I = T_W_I.pos; // Use the models'world position for GPS and pressure alt. math::Quaternion C_W_I; C_W_I.w = imu_message->orientation().w(); C_W_I.x = imu_message->orientation().x(); C_W_I.y = imu_message->orientation().y(); C_W_I.z = imu_message->orientation().z(); math::Vector3 mag_I = C_W_I.RotateVectorReverse(mag_W_); // TODO: Add noise based on bais and variance like for imu and gyro math::Vector3 body_vel = C_W_I.RotateVectorReverse(model_->GetWorldLinearVel()); standard_normal_distribution_ = std::normal_distribution<float>(0, 0.01f); float mag_noise = standard_normal_distribution_(random_generator_); if(use_mavlink_udp){ mavlink_hil_sensor_t sensor_msg; sensor_msg.time_usec = world_->GetSimTime().nsec*1000; sensor_msg.xacc = imu_message->linear_acceleration().x(); sensor_msg.yacc = imu_message->linear_acceleration().y(); sensor_msg.zacc = imu_message->linear_acceleration().z(); sensor_msg.xgyro = imu_message->angular_velocity().x(); sensor_msg.ygyro = imu_message->angular_velocity().y(); sensor_msg.zgyro = imu_message->angular_velocity().z(); sensor_msg.xmag = mag_I.x + mag_noise; sensor_msg.ymag = mag_I.y + mag_noise; sensor_msg.zmag = mag_I.z + mag_noise; sensor_msg.abs_pressure = 0.0; sensor_msg.diff_pressure = 0.5*1.2754*body_vel.x*body_vel.x; sensor_msg.pressure_alt = pos_W_I.z; sensor_msg.temperature = 0.0; sensor_msg.fields_updated = 4095; send_mavlink_message(MAVLINK_MSG_ID_HIL_SENSOR, &sensor_msg, 200); } else{ hil_sensor_msg_.set_time_usec(world_->GetSimTime().nsec*1000); hil_sensor_msg_.set_xacc(imu_message->linear_acceleration().x()); hil_sensor_msg_.set_yacc(imu_message->linear_acceleration().y()); hil_sensor_msg_.set_zacc(imu_message->linear_acceleration().z()); hil_sensor_msg_.set_xgyro(imu_message->angular_velocity().x()); hil_sensor_msg_.set_ygyro(imu_message->angular_velocity().y()); hil_sensor_msg_.set_zgyro(imu_message->angular_velocity().z()); hil_sensor_msg_.set_xmag(mag_I.x); hil_sensor_msg_.set_ymag(mag_I.y); hil_sensor_msg_.set_zmag(mag_I.z); hil_sensor_msg_.set_abs_pressure(0.0); hil_sensor_msg_.set_diff_pressure(0.5*1.2754*body_vel.x*body_vel.x); hil_sensor_msg_.set_pressure_alt(pos_W_I.z); hil_sensor_msg_.set_temperature(0.0); hil_sensor_msg_.set_fields_updated(4095); // 0b1111111111111 (All updated since new data with new noise added always) hil_sensor_pub_->Publish(hil_sensor_msg_); } }
void GazeboMavlinkInterface::ImuCallback(ImuPtr& imu_message) { math::Pose T_W_I = model_->GetWorldPose(); math::Vector3 pos_W_I = T_W_I.pos; // Use the models'world position for GPS and pressure alt. math::Quaternion C_W_I; C_W_I.w = imu_message->orientation().w(); C_W_I.x = imu_message->orientation().x(); C_W_I.y = imu_message->orientation().y(); C_W_I.z = imu_message->orientation().z(); // gzerr << "got imu: " << C_W_I << "\n"; float declination = get_mag_declination(lat_rad, lon_rad); math::Quaternion C_D_I(0.0, 0.0, declination); math::Vector3 mag_decl = C_D_I.RotateVectorReverse(mag_W_); // TODO replace mag_W_ in the line below with mag_decl math::Vector3 mag_I = C_W_I.RotateVectorReverse(mag_decl); // TODO: Add noise based on bais and variance like for imu and gyro math::Vector3 body_vel = C_W_I.RotateVectorReverse(model_->GetWorldLinearVel()); standard_normal_distribution_ = std::normal_distribution<float>(0, 0.01f); float mag_noise = standard_normal_distribution_(random_generator_); mavlink_hil_sensor_t sensor_msg; sensor_msg.time_usec = world_->GetSimTime().nsec*1000; sensor_msg.xacc = imu_message->linear_acceleration().x(); sensor_msg.yacc = imu_message->linear_acceleration().y(); sensor_msg.zacc = imu_message->linear_acceleration().z(); sensor_msg.xgyro = imu_message->angular_velocity().x(); sensor_msg.ygyro = imu_message->angular_velocity().y(); sensor_msg.zgyro = imu_message->angular_velocity().z(); sensor_msg.xmag = mag_I.x + mag_noise; sensor_msg.ymag = mag_I.y + mag_noise; sensor_msg.zmag = mag_I.z + mag_noise; sensor_msg.abs_pressure = 0.0; sensor_msg.diff_pressure = 0.5*1.2754*(body_vel.z + body_vel.x)*(body_vel.z + body_vel.x) / 100; sensor_msg.pressure_alt = pos_W_I.z; sensor_msg.temperature = 0.0; sensor_msg.fields_updated = 4095; //gyro needed for optical flow message optflow_xgyro = imu_message->angular_velocity().x(); optflow_ygyro = imu_message->angular_velocity().y(); optflow_zgyro = imu_message->angular_velocity().z(); send_mavlink_message(MAVLINK_MSG_ID_HIL_SENSOR, &sensor_msg, 200); }
void GazeboMavlinkInterface::ImuCallback(const sensor_msgs::ImuConstPtr& imu_message) { mavlink_message_t mmsg; math::Pose T_W_I = model_->GetWorldPose(); math::Vector3 pos_W_I = T_W_I.pos; // Use the models'world position for GPS and pressure alt. math::Quaternion C_W_I; C_W_I.w = imu_message->orientation.w; C_W_I.x = imu_message->orientation.x; C_W_I.y = imu_message->orientation.y; C_W_I.z = imu_message->orientation.z; math::Vector3 mag_I = C_W_I.RotateVectorReverse(mag_W_); // TODO: Add noise based on bais and variance like for imu and gyro math::Vector3 body_vel = C_W_I.RotateVectorReverse(model_->GetWorldLinearVel()); standard_normal_distribution_ = std::normal_distribution<float>(0, 0.01f); float mag_noise = standard_normal_distribution_(random_generator_); hil_sensor_msg_.time_usec = imu_message->header.stamp.nsec*1000; hil_sensor_msg_.xacc = imu_message->linear_acceleration.x; hil_sensor_msg_.yacc = imu_message->linear_acceleration.y; hil_sensor_msg_.zacc = imu_message->linear_acceleration.z; hil_sensor_msg_.xgyro = imu_message->angular_velocity.x; hil_sensor_msg_.ygyro = imu_message->angular_velocity.y; hil_sensor_msg_.zgyro = imu_message->angular_velocity.z; hil_sensor_msg_.xmag = mag_I.x + mag_noise; hil_sensor_msg_.ymag = mag_I.y + mag_noise;; hil_sensor_msg_.zmag = mag_I.z + mag_noise;; hil_sensor_msg_.abs_pressure = 0.0; hil_sensor_msg_.diff_pressure = 0.5*1.2754*body_vel.x*body_vel.x; hil_sensor_msg_.pressure_alt = pos_W_I.z; hil_sensor_msg_.temperature = 0.0; hil_sensor_msg_.fields_updated = 4095; // 0b1111111111111 (All updated since new data with new noise added always) mavlink_hil_sensor_t* hil_msg = &hil_sensor_msg_; mavlink_msg_hil_sensor_encode(1, 240, &mmsg, hil_msg); mavlink_message_t* msg = &mmsg; mavros_msgs::MavlinkPtr rmsg = boost::make_shared<mavros_msgs::Mavlink>(); rmsg->header.stamp = ros::Time::now(); mavros_msgs::mavlink::convert(*msg, *rmsg); hil_sensor_pub_.publish(rmsg); }
// This gets called by the world update start event. void GazeboAirspeedPlugin::OnUpdate(const common::UpdateInfo& _info) { // Calculate Airspeed math::Vector3 C_linear_velocity_W_C = link_->GetRelativeLinearVel(); double u = C_linear_velocity_W_C.x; double v = -C_linear_velocity_W_C.y; double w = -C_linear_velocity_W_C.z; double ur = u - wind_.N; double vr = v - wind_.E; double wr = w - wind_.D; // double Va = sqrt(pow(ur,2.0) + pow(vr,2.0) + pow(wr,2.0)); double Va = sqrt(pow(u,2.0) + pow(v,2.0) + pow(w,2.0)); // Invert Airpseed to get sensor measurement double y = rho_*Va*Va/2.0; // Page 130 in the UAV Book y += pressure_bias_ + pressure_noise_sigma_*standard_normal_distribution_(random_generator_); y = (y>max_pressure_)?max_pressure_:y; y = (y<min_pressure_)?min_pressure_:y; airspeed_message_.fluid_pressure = y; airspeed_pub_.publish(airspeed_message_); }
void GazeboImuPlugin::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf) { // Store the pointer to the model model_ = _model; world_ = model_->GetWorld(); // default params namespace_.clear(); if (_sdf->HasElement("robotNamespace")) namespace_ = _sdf->GetElement("robotNamespace")->Get<std::string>(); else gzerr << "[gazebo_imu_plugin] Please specify a robotNamespace.\n"; node_handle_ = new ros::NodeHandle(namespace_); if (_sdf->HasElement("linkName")) link_name_ = _sdf->GetElement("linkName")->Get<std::string>(); else gzerr << "[gazebo_imu_plugin] Please specify a linkName.\n"; // Get the pointer to the link link_ = model_->GetLink(link_name_); if (link_ == NULL) gzthrow("[gazebo_imu_plugin] Couldn't find specified link \"" << link_name_ << "\"."); frame_id_ = link_name_; getSdfParam<std::string>(_sdf, "imuTopic", imu_topic_, kDefaultImuTopic); getSdfParam<double>(_sdf, "gyroscopeNoiseDensity", imu_parameters_.gyroscope_noise_density, imu_parameters_.gyroscope_noise_density); getSdfParam<double>(_sdf, "gyroscopeBiasRandomWalk", imu_parameters_.gyroscope_random_walk, imu_parameters_.gyroscope_random_walk); getSdfParam<double>(_sdf, "gyroscopeBiasCorrelationTime", imu_parameters_.gyroscope_bias_correlation_time, imu_parameters_.gyroscope_bias_correlation_time); assert(imu_parameters_.gyroscope_bias_correlation_time > 0.0); getSdfParam<double>(_sdf, "gyroscopeTurnOnBiasSigma", imu_parameters_.gyroscope_turn_on_bias_sigma, imu_parameters_.gyroscope_turn_on_bias_sigma); getSdfParam<double>(_sdf, "accelerometerNoiseDensity", imu_parameters_.accelerometer_noise_density, imu_parameters_.accelerometer_noise_density); getSdfParam<double>(_sdf, "accelerometerRandomWalk", imu_parameters_.accelerometer_random_walk, imu_parameters_.accelerometer_random_walk); getSdfParam<double>(_sdf, "accelerometerBiasCorrelationTime", imu_parameters_.accelerometer_bias_correlation_time, imu_parameters_.accelerometer_bias_correlation_time); assert(imu_parameters_.accelerometer_bias_correlation_time > 0.0); getSdfParam<double>(_sdf, "accelerometerTurnOnBiasSigma", imu_parameters_.accelerometer_turn_on_bias_sigma, imu_parameters_.accelerometer_turn_on_bias_sigma); last_time_ = world_->GetSimTime(); // Listen to the update event. This event is broadcast every // simulation iteration. this->updateConnection_ = event::Events::ConnectWorldUpdateBegin( boost::bind(&GazeboImuPlugin::OnUpdate, this, _1)); imu_pub_ = node_handle_->advertise<sensor_msgs::Imu>(imu_topic_, 10); // Fill imu message. imu_message_.header.frame_id = frame_id_; // We assume uncorrelated noise on the 3 channels -> only set diagonal // elements. Only the broadband noise component is considered, specified as a // continuous-time density (two-sided spectrum); not the true covariance of // the measurements. // Angular velocity measurement covariance. imu_message_.angular_velocity_covariance[0] = imu_parameters_.gyroscope_noise_density * imu_parameters_.gyroscope_noise_density; imu_message_.angular_velocity_covariance[4] = imu_parameters_.gyroscope_noise_density * imu_parameters_.gyroscope_noise_density; imu_message_.angular_velocity_covariance[8] = imu_parameters_.gyroscope_noise_density * imu_parameters_.gyroscope_noise_density; // Linear acceleration measurement covariance. imu_message_.linear_acceleration_covariance[0] = imu_parameters_.accelerometer_noise_density * imu_parameters_.accelerometer_noise_density; imu_message_.linear_acceleration_covariance[4] = imu_parameters_.accelerometer_noise_density * imu_parameters_.accelerometer_noise_density; imu_message_.linear_acceleration_covariance[8] = imu_parameters_.accelerometer_noise_density * imu_parameters_.accelerometer_noise_density; // Orientation estimate covariance (no estimate provided). imu_message_.orientation_covariance[0] = -1.0; gravity_W_ = world_->GetPhysicsEngine()->GetGravity(); imu_parameters_.gravity_magnitude = gravity_W_.GetLength(); standard_normal_distribution_ = std::normal_distribution<double>(0.0, 1.0); double sigma_bon_g = imu_parameters_.gyroscope_turn_on_bias_sigma; double sigma_bon_a = imu_parameters_.accelerometer_turn_on_bias_sigma; for (int i = 0; i < 3; ++i) { gyroscope_turn_on_bias_[i] = sigma_bon_g * standard_normal_distribution_(random_generator_); accelerometer_turn_on_bias_[i] = sigma_bon_a * standard_normal_distribution_(random_generator_); } // TODO(nikolicj) incorporate steady-state covariance of bias process gyroscope_bias_.setZero(); accelerometer_bias_.setZero(); }