Esempio n. 1
0
	/**
	 * @brief Handle SCALED_IMU MAVlink message.
	 * Message specification: https://mavlink.io/en/messages/common.html/#SCALED_IMU
	 * @param msg		Received Mavlink msg
	 * @param imu_raw	SCALED_IMU msg
	 */
	void handle_scaled_imu(const mavlink::mavlink_message_t *msg, mavlink::common::msg::SCALED_IMU &imu_raw)
	{
		if (has_hr_imu)
			return;

		ROS_INFO_COND_NAMED(!has_scaled_imu, "imu", "IMU: Scaled IMU message used.");
		has_scaled_imu = true;

		auto imu_msg = boost::make_shared<sensor_msgs::Imu>();
		auto header = m_uas->synchronized_header(frame_id, imu_raw.time_boot_ms);

		auto gyro_flu = ftf::transform_frame_aircraft_baselink<Eigen::Vector3d>(
					Eigen::Vector3d(imu_raw.xgyro, imu_raw.ygyro, imu_raw.zgyro) * MILLIRS_TO_RADSEC);
		auto accel_frd = Eigen::Vector3d(Eigen::Vector3d(imu_raw.xacc, imu_raw.yacc, imu_raw.zacc) * MILLIG_TO_MS2);
		auto accel_flu = ftf::transform_frame_aircraft_baselink<Eigen::Vector3d>(accel_frd);

		publish_imu_data_raw(header, gyro_flu, accel_flu, accel_frd);

		/** Magnetic field data:
		 *  @snippet src/plugins/imu.cpp mag_field
		 */
		auto mag_field = ftf::transform_frame_aircraft_baselink<Eigen::Vector3d>(
					Eigen::Vector3d(imu_raw.xmag, imu_raw.ymag, imu_raw.zmag) * MILLIT_TO_TESLA);

		publish_mag(header, mag_field);
	}
Esempio n. 2
0
	/**
	 * @brief Handle ATTITUDE_QUATERNION MAVlink message.
	 * Message specification: https://mavlink.io/en/messages/common.html/#ATTITUDE_QUATERNION
	 * @param msg		Received Mavlink msg
	 * @param att_q		ATTITUDE_QUATERNION msg
	 */
	void handle_attitude_quaternion(const mavlink::mavlink_message_t *msg, mavlink::common::msg::ATTITUDE_QUATERNION &att_q)
	{
		ROS_INFO_COND_NAMED(!has_att_quat, "imu", "IMU: Attitude quaternion IMU detected!");
		has_att_quat = true;

		/** Orientation on the NED-aicraft frame:
		 *  @snippet src/plugins/imu.cpp ned_aircraft_orient2
		 */
		// [ned_aircraft_orient2]
		auto ned_aircraft_orientation = Eigen::Quaterniond(att_q.q1, att_q.q2, att_q.q3, att_q.q4);
		// [ned_aircraft_orient2]

		/** Angular velocity on the NED-aicraft frame:
		 *  @snippet src/plugins/imu.cpp ned_ang_vel2
		 */
		// [frd_ang_vel2]
		auto gyro_frd = Eigen::Vector3d(att_q.rollspeed, att_q.pitchspeed, att_q.yawspeed);
		// [frd_ang_vel2]

		/** MAVLink quaternion exactly matches Eigen convention.
		 *  The RPY describes the rotation: aircraft->NED.
		 *  It is required to change this to aircraft->base_link:
		 *  @snippet src/plugins/imu.cpp ned->baselink->enu
		 */
		auto enu_baselink_orientation = ftf::transform_orientation_aircraft_baselink(
					ftf::transform_orientation_ned_enu(ned_aircraft_orientation));

		/** The angular velocity expressed in the aircraft frame.
		 *  It is required to apply the static rotation to get it into the base_link frame:
		 *  @snippet src/plugins/imu.cpp rotate_gyro
		 */
		auto gyro_flu = ftf::transform_frame_aircraft_baselink(gyro_frd);

		publish_imu_data(att_q.time_boot_ms, enu_baselink_orientation, ned_aircraft_orientation, gyro_flu, gyro_frd);
	}
Esempio n. 3
0
	// almost the same as handle_attitude(), but for ATTITUDE_QUATERNION
	void handle_attitude_quaternion(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
		mavlink_attitude_quaternion_t att_q;
		mavlink_msg_attitude_quaternion_decode(msg, &att_q);

		ROS_INFO_COND_NAMED(!has_att_quat, "imu", "Attitude quaternion IMU detected!");
		has_att_quat = true;

		sensor_msgs::ImuPtr imu_msg = boost::make_shared<sensor_msgs::Imu>();

		// PX4 NED (w x y z) -> ROS ENU (x -y -z w) (body-fixed)
		tf::Quaternion orientation(att_q.q2, -att_q.q3, -att_q.q4, att_q.q1);

		fill_imu_msg_attitude(imu_msg, orientation,
				att_q.rollspeed,
				-att_q.pitchspeed,
				-att_q.yawspeed);

		uas_store_attitude(orientation,
				imu_msg->angular_velocity,
				imu_msg->linear_acceleration);

		// publish data
		imu_msg->header.frame_id = frame_id;
		imu_msg->header.stamp = ros::Time::now();
		imu_pub.publish(imu_msg);
	}
Esempio n. 4
0
	void handle_rc_channels(const mavlink::mavlink_message_t *msg, mavlink::common::msg::RC_CHANNELS &channels)
	{
		constexpr size_t MAX_CHANCNT = 18;
		lock_guard lock(mutex);

		ROS_INFO_COND_NAMED(!has_rc_channels_msg, "rc", "RC_CHANNELS message detected!");
		has_rc_channels_msg = true;

		if (channels.chancount > MAX_CHANCNT) {
			ROS_WARN_THROTTLE_NAMED(60, "rc",
						"FCU receives %u RC channels, but RC_CHANNELS can store %zu",
						channels.chancount, MAX_CHANCNT);

			channels.chancount = MAX_CHANCNT;
		}

		raw_rc_in.resize(channels.chancount);

		// switch works as start point selector.
		switch (channels.chancount) {
		// [[[cog:
		// for i in range(18, 0, -1):
		//     cog.outl("case %2d: raw_rc_in[%2d] = channels.chan%d_raw;" % (i, i - 1, i))
		// ]]]
		case 18: raw_rc_in[17] = channels.chan18_raw;
		case 17: raw_rc_in[16] = channels.chan17_raw;
		case 16: raw_rc_in[15] = channels.chan16_raw;
		case 15: raw_rc_in[14] = channels.chan15_raw;
		case 14: raw_rc_in[13] = channels.chan14_raw;
		case 13: raw_rc_in[12] = channels.chan13_raw;
		case 12: raw_rc_in[11] = channels.chan12_raw;
		case 11: raw_rc_in[10] = channels.chan11_raw;
		case 10: raw_rc_in[ 9] = channels.chan10_raw;
		case  9: raw_rc_in[ 8] = channels.chan9_raw;
		case  8: raw_rc_in[ 7] = channels.chan8_raw;
		case  7: raw_rc_in[ 6] = channels.chan7_raw;
		case  6: raw_rc_in[ 5] = channels.chan6_raw;
		case  5: raw_rc_in[ 4] = channels.chan5_raw;
		case  4: raw_rc_in[ 3] = channels.chan4_raw;
		case  3: raw_rc_in[ 2] = channels.chan3_raw;
		case  2: raw_rc_in[ 1] = channels.chan2_raw;
		case  1: raw_rc_in[ 0] = channels.chan1_raw;
		// [[[end]]] (checksum: 56e9ab5407bd2c864abde230a6cf3fed)
		case  0: break;
		}

		auto rcin_msg = boost::make_shared<mavros_msgs::RCIn>();

		rcin_msg->header.stamp = m_uas->synchronise_stamp(channels.time_boot_ms);
		rcin_msg->rssi = channels.rssi;
		rcin_msg->channels = raw_rc_in;

		rc_in_pub.publish(rcin_msg);
	}
Esempio n. 5
0
	void handle_highres_imu(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
		mavlink_highres_imu_t imu_hr;
		mavlink_msg_highres_imu_decode(msg, &imu_hr);

		ROS_INFO_COND_NAMED(!has_hr_imu, "imu", "High resolution IMU detected!");
		has_hr_imu = true;

		std_msgs::Header header;
		header.stamp = ros::Time::now();
		header.frame_id = frame_id;

		/* imu/data_raw filled by HR IMU */
		if (imu_hr.fields_updated & ((7<<3)|(7<<0))) {
			sensor_msgs::ImuPtr imu_msg = boost::make_shared<sensor_msgs::Imu>();

			fill_imu_msg_raw(imu_msg,
					imu_hr.xgyro, -imu_hr.ygyro, -imu_hr.zgyro,
					imu_hr.xacc, -imu_hr.yacc, -imu_hr.zacc);

			imu_msg->header = header;
			imu_raw_pub.publish(imu_msg);
		}

		if (imu_hr.fields_updated & (7<<6)) {
			sensor_msgs::MagneticFieldPtr magn_msg = boost::make_shared<sensor_msgs::MagneticField>();

			// Convert from local NED plane to ENU
			magn_msg->magnetic_field.x = imu_hr.ymag * GAUSS_TO_TESLA;
			magn_msg->magnetic_field.y = imu_hr.xmag * GAUSS_TO_TESLA;
			magn_msg->magnetic_field.z = -imu_hr.zmag * GAUSS_TO_TESLA;

			magn_msg->magnetic_field_covariance = magnetic_cov;

			magn_msg->header = header;
			magn_pub.publish(magn_msg);
		}

		if (imu_hr.fields_updated & (1<<9)) {
			sensor_msgs::FluidPressurePtr atmp_msg = boost::make_shared<sensor_msgs::FluidPressure>();

			atmp_msg->fluid_pressure = imu_hr.abs_pressure * MILLIBAR_TO_PASCAL;
			atmp_msg->header = header;
			press_pub.publish(atmp_msg);
		}

		if (imu_hr.fields_updated & (1<<12)) {
			sensor_msgs::TemperaturePtr temp_msg = boost::make_shared<sensor_msgs::Temperature>();

			temp_msg->temperature = imu_hr.temperature;
			temp_msg->header = header;
			temp_pub.publish(temp_msg);
		}
	}
Esempio n. 6
0
	/**
	 * @brief Handle RAW_IMU MAVlink message.
	 * Message specification: https://mavlink.io/en/messages/common.html/#RAW_IMU
	 * @param msg		Received Mavlink msg
	 * @param imu_raw	RAW_IMU msg
	 */
	void handle_raw_imu(const mavlink::mavlink_message_t *msg, mavlink::common::msg::RAW_IMU &imu_raw)
	{
		ROS_INFO_COND_NAMED(!has_raw_imu, "imu", "IMU: Raw IMU message used.");
		has_raw_imu = true;

		if (has_hr_imu || has_scaled_imu)
			return;

		auto imu_msg = boost::make_shared<sensor_msgs::Imu>();
		auto header = m_uas->synchronized_header(frame_id, imu_raw.time_usec);

		/** @note APM send SCALED_IMU data as RAW_IMU
		 */
		auto gyro_flu = ftf::transform_frame_aircraft_baselink<Eigen::Vector3d>(
					Eigen::Vector3d(imu_raw.xgyro, imu_raw.ygyro, imu_raw.zgyro) * MILLIRS_TO_RADSEC);
		auto accel_frd = Eigen::Vector3d(imu_raw.xacc, imu_raw.yacc, imu_raw.zacc);
		auto accel_flu = ftf::transform_frame_aircraft_baselink<Eigen::Vector3d>(accel_frd);

		if (m_uas->is_ardupilotmega()) {
			accel_frd *= MILLIG_TO_MS2;
			accel_flu *= MILLIG_TO_MS2;
		} else if (m_uas->is_px4()) {
			accel_frd *= MILLIMS2_TO_MS2;
			accel_flu *= MILLIMS2_TO_MS2;
		}

		publish_imu_data_raw(header, gyro_flu, accel_flu, accel_frd);

		if (!m_uas->is_ardupilotmega()) {
			ROS_WARN_THROTTLE_NAMED(60, "imu", "IMU: linear acceleration on RAW_IMU known on APM only.");
			ROS_WARN_THROTTLE_NAMED(60, "imu", "IMU: ~imu/data_raw stores unscaled raw acceleration report.");
			linear_accel_vec_flu.setZero();
			linear_accel_vec_frd.setZero();
		}

		/** Magnetic field data:
		 *  @snippet src/plugins/imu.cpp mag_field
		 */
		// [mag_field]
		auto mag_field = ftf::transform_frame_aircraft_baselink<Eigen::Vector3d>(
					Eigen::Vector3d(imu_raw.xmag, imu_raw.ymag, imu_raw.zmag) * MILLIT_TO_TESLA);
		// [mag_field]

		publish_mag(header, mag_field);
	}
Esempio n. 7
0
	void handle_scaled_imu(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
		if (has_hr_imu)
			return;

		ROS_INFO_COND_NAMED(!has_scaled_imu, "imu", "Scaled IMU message used.");
		has_scaled_imu = true;

		sensor_msgs::ImuPtr imu_msg = boost::make_shared<sensor_msgs::Imu>();
		mavlink_scaled_imu_t imu_raw;
		mavlink_msg_scaled_imu_decode(msg, &imu_raw);

		std_msgs::Header header;
		header.stamp = ros::Time::now();
		header.frame_id = frame_id;

		fill_imu_msg_raw(imu_msg,
				imu_raw.xgyro * MILLIRS_TO_RADSEC,
				-imu_raw.ygyro * MILLIRS_TO_RADSEC,
				-imu_raw.zgyro * MILLIRS_TO_RADSEC,
				imu_raw.xacc * MILLIG_TO_MS2,
				-imu_raw.yacc * MILLIG_TO_MS2,
				-imu_raw.zacc * MILLIG_TO_MS2);

		imu_msg->header = header;
		imu_raw_pub.publish(imu_msg);

		/* -*- magnetic vector -*- */
		sensor_msgs::MagneticFieldPtr magn_msg = boost::make_shared<sensor_msgs::MagneticField>();

		// Convert from local NED plane to ENU
		magn_msg->magnetic_field.x = imu_raw.ymag * MILLIT_TO_TESLA;
		magn_msg->magnetic_field.y = imu_raw.xmag * MILLIT_TO_TESLA;
		magn_msg->magnetic_field.z = -imu_raw.zmag * MILLIT_TO_TESLA;

		magn_msg->magnetic_field_covariance = magnetic_cov;

		magn_msg->header = header;
		magn_pub.publish(magn_msg);
	}
Esempio n. 8
0
	/**
	 * @brief Handle HIGHRES_IMU MAVlink message.
	 * Message specification: https://mavlink.io/en/messages/common.html/#HIGHRES_IMU
	 * @param msg		Received Mavlink msg
	 * @param imu_hr	HIGHRES_IMU msg
	 */
	void handle_highres_imu(const mavlink::mavlink_message_t *msg, mavlink::common::msg::HIGHRES_IMU &imu_hr)
	{
		ROS_INFO_COND_NAMED(!has_hr_imu, "imu", "IMU: High resolution IMU detected!");
		has_hr_imu = true;

		auto header = m_uas->synchronized_header(frame_id, imu_hr.time_usec);
		/** @todo Make more paranoic check of HIGHRES_IMU.fields_updated
		 */

		/** Check if accelerometer + gyroscope data are available.
		 *  Data is expressed in aircraft frame it is required to rotate to the base_link frame:
		 *  @snippet src/plugins/imu.cpp accel_available
		 */
		// [accel_available]
		if (imu_hr.fields_updated & ((7 << 3) | (7 << 0))) {
			auto gyro_flu = ftf::transform_frame_aircraft_baselink(Eigen::Vector3d(imu_hr.xgyro, imu_hr.ygyro, imu_hr.zgyro));

			auto accel_frd = Eigen::Vector3d(imu_hr.xacc, imu_hr.yacc, imu_hr.zacc);
			auto accel_flu = ftf::transform_frame_aircraft_baselink(accel_frd);

			publish_imu_data_raw(header, gyro_flu, accel_flu, accel_frd);
		}
		// [accel_available]

		/** Check if magnetometer data is available:
		 *  @snippet src/plugins/imu.cpp mag_available
		 */
		// [mag_available]
		if (imu_hr.fields_updated & (7 << 6)) {
			auto mag_field = ftf::transform_frame_aircraft_baselink<Eigen::Vector3d>(
						Eigen::Vector3d(imu_hr.xmag, imu_hr.ymag, imu_hr.zmag) * GAUSS_TO_TESLA);

			publish_mag(header, mag_field);
		}
		// [mag_available]

		/** Check if static pressure sensor data is available:
		 *  @snippet src/plugins/imu.cpp static_pressure_available
		 */
		// [static_pressure_available]
		if (imu_hr.fields_updated & (1 << 9)) {
			auto static_pressure_msg = boost::make_shared<sensor_msgs::FluidPressure>();

			static_pressure_msg->header = header;
			static_pressure_msg->fluid_pressure = imu_hr.abs_pressure;

			static_press_pub.publish(static_pressure_msg);
		}
		// [static_pressure_available]

		/** Check if differential pressure sensor data is available:
		 *  @snippet src/plugins/imu.cpp differential_pressure_available
		 */
		// [differential_pressure_available]
		if (imu_hr.fields_updated & (1 << 10)) {
			auto differential_pressure_msg = boost::make_shared<sensor_msgs::FluidPressure>();

			differential_pressure_msg->header = header;
			differential_pressure_msg->fluid_pressure = imu_hr.diff_pressure;

			diff_press_pub.publish(differential_pressure_msg);
		}
		// [differential_pressure_available]

		/** Check if temperature data is available:
		 *  @snippet src/plugins/imu.cpp temperature_available
		 */
		// [temperature_available]
		if (imu_hr.fields_updated & (1 << 12)) {
			auto temp_msg = boost::make_shared<sensor_msgs::Temperature>();

			temp_msg->header = header;
			temp_msg->temperature = imu_hr.temperature;

			temp_imu_pub.publish(temp_msg);
		}
		// [temperature_available]
	}