44 physics::ModelPtr _model, sdf::ElementPtr _sdf) {
50 const char* env_alt = std::getenv(
"PX4_HOME_ALT");
52 gzmsg <<
"Home altitude is set to " << env_alt <<
".\n";
57 if (_sdf->HasElement(
"robotNamespace")) {
58 namespace_ = _sdf->GetElement(
"robotNamespace")->Get<std::string>();
60 gzerr <<
"[gazebo_mavlink_interface] Please specify a robotNamespace.\n";
63 if (_sdf->HasElement(
"protocol_version")) {
67 node_handle_ = transport::NodePtr(
new transport::Node());
70 getSdfParam<std::string>(
73 gzdbg <<
"motorSpeedCommandPubTopic = \"" 74 << motor_velocity_reference_pub_topic_ <<
"\"." << std::endl;
76 getSdfParam<std::string>(
78 getSdfParam<std::string>(
87 pids_[i].Init(0, 0, 0, 0, 0, 0, 0);
91 if (_sdf->HasElement(
"control_channels")) {
92 sdf::ElementPtr control_channels = _sdf->GetElement(
"control_channels");
93 sdf::ElementPtr channel = control_channels->GetElement(
"channel");
95 if (channel->HasElement(
"input_index")) {
96 int index = channel->Get<
int>(
"input_index");
97 if (index < kNOutMax) {
101 channel->Get<
double>(
"zero_position_disarmed");
103 channel->Get<
double>(
"zero_position_armed");
104 if (channel->HasElement(
"joint_control_type")) {
106 channel->Get<std::string>(
"joint_control_type");
108 gzwarn <<
"joint_control_type[" << index
109 <<
"] not specified, using velocity.\n";
116 if (channel->HasElement(
"gztopic"))
118 channel->Get<std::string>(
"gztopic");
124 node_handle_->Advertise<gazebo::msgs::Any>(gztopic_[index]);
127 if (channel->HasElement(
"joint_name")) {
128 std::string joint_name = channel->Get<std::string>(
"joint_name");
130 if (joints_[index] ==
nullptr) {
131 gzwarn <<
"joint [" << joint_name <<
"] not found for channel[" 132 << index <<
"] no joint control for this channel.\n";
134 gzdbg <<
"joint [" << joint_name <<
"] found for channel[" 135 << index <<
"] joint control active for this channel.\n";
138 gzdbg <<
"<joint_name> not found for channel[" << index
139 <<
"] no joint control will be performed for this channel.\n";
143 if (channel->HasElement(
"joint_control_pid")) {
144 sdf::ElementPtr pid = channel->GetElement(
"joint_control_pid");
146 if (pid->HasElement(
"p"))
147 p = pid->Get<
double>(
"p");
149 if (pid->HasElement(
"i"))
150 i = pid->Get<
double>(
"i");
152 if (pid->HasElement(
"d"))
153 d = pid->Get<
double>(
"d");
155 if (pid->HasElement(
"iMax"))
156 iMax = pid->Get<
double>(
"iMax");
158 if (pid->HasElement(
"iMin"))
159 iMin = pid->Get<
double>(
"iMin");
161 if (pid->HasElement(
"cmdMax"))
162 cmdMax = pid->Get<
double>(
"cmdMax");
164 if (pid->HasElement(
"cmdMin"))
165 cmdMin = pid->Get<
double>(
"cmdMin");
166 pids_[index].Init(p, i, d, iMax, iMin, cmdMax, cmdMin);
169 gzerr <<
"input_index[" << index <<
"] out of range, not parsing.\n";
172 gzerr <<
"no input_index, not parsing.\n";
175 channel = channel->GetNextElement(
"channel");
197 node_handle_->Advertise<gz_mav_msgs::CommandMotorSpeed>(
206 if (_sdf->HasElement(
"imu_rate")) {
219 if (_sdf->HasElement(
"hil_state_level")) {
220 hil_mode_ = _sdf->GetElement(
"hil_mode")->Get<
bool>();
223 if (_sdf->HasElement(
"hil_state_level")) {
228 if (_sdf->HasElement(
"serialEnabled")) {
234 if (_sdf->HasElement(
"serialDevice")) {
235 device_ = _sdf->GetElement(
"serialDevice")->Get<std::string>();
238 if (_sdf->HasElement(
"baudRate")) {
239 baudrate_ = _sdf->GetElement(
"baudRate")->Get<
int>();
251 if (_sdf->HasElement(
"mavlink_addr")) {
252 std::string mavlink_addr =
253 _sdf->GetElement(
"mavlink_addr")->Get<std::string>();
254 if (mavlink_addr !=
"INADDR_ANY") {
257 fprintf(stderr,
"invalid mavlink_addr \"%s\"\n", mavlink_addr.c_str());
262 if (_sdf->HasElement(
"mavlink_udp_port")) {
266 auto worldName =
world_->Name();
271 if (_sdf->HasElement(
"qgc_addr")) {
272 std::string qgc_addr = _sdf->GetElement(
"qgc_addr")->Get<std::string>();
273 if (qgc_addr !=
"INADDR_ANY") {
274 qgc_addr_ = inet_addr(qgc_addr.c_str());
275 if (qgc_addr_ == INADDR_NONE) {
276 fprintf(stderr,
"invalid qgc_addr \"%s\"\n", qgc_addr.c_str());
281 if (_sdf->HasElement(
"qgc_udp_port")) {
282 qgc_udp_port_ = _sdf->GetElement(
"qgc_udp_port")->Get<
int>();
286 if ((
_fd =
socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
287 printf(
"create socket failed\n");
291 memset((
char*)&
myaddr_, 0,
sizeof(myaddr_));
292 myaddr_.sin_family = AF_INET;
304 myaddr_.sin_addr.s_addr = htonl(INADDR_ANY);
306 myaddr_.sin_port = htons(0);
313 if (bind(
_fd, (
struct sockaddr*)&myaddr_,
sizeof(myaddr_)) < 0) {
314 printf(
"bind failed\n");
319 fds[0].events = POLLIN;
326 gzmsg <<
"Using MAVLink protocol v2.0\n";
329 gzmsg <<
"Using MAVLink protocol v1.0\n";
338 common::Time current_time =
world_->SimTime();
339 double dt = (current_time -
last_time_).Double();
346 gz_mav_msgs::CommandMotorSpeed turning_velocities_msg;
351 turning_velocities_msg.add_motor_speed(0);
369 assert(message !=
nullptr);
371 gzerr <<
"Serial port closed! \n";
381 tx_q_.emplace_back(message);
390 struct sockaddr_in dest_addr;
393 if (destination_port != 0) {
394 dest_addr.sin_port = htons(destination_port);
397 ssize_t
len = sendto(
398 _fd, buffer, packetlen, 0, (
struct sockaddr*)&
srcaddr_,
402 printf(
"Failed sending mavlink message\n");
408 common::Time current_time =
world_->SimTime();
411 ignition::math::Quaterniond q_br(0, 1, 0, 0);
412 ignition::math::Quaterniond q_ng(0, 0.70711, 0.70711, 0);
414 ignition::math::Quaterniond q_gr = ignition::math::Quaterniond(
415 imu_message->orientation().w(), imu_message->orientation().x(),
416 imu_message->orientation().y(), imu_message->orientation().z());
418 ignition::math::Quaterniond q_gb = q_gr * q_br.Inverse();
419 ignition::math::Quaterniond q_nb = q_ng * q_gb;
421 ignition::math::Vector3d pos_g =
model_->WorldPose().Pos();
422 ignition::math::Vector3d pos_n = q_ng.RotateVector(pos_g);
426 ignition::math::Quaterniond q_dn(0.0, 0.0, declination);
427 ignition::math::Vector3d mag_n = q_dn.RotateVector(
mag_d_);
429 ignition::math::Vector3d vel_b =
430 q_br.RotateVector(
model_->RelativeLinearVel());
431 ignition::math::Vector3d vel_n = q_ng.RotateVector(
model_->WorldLinearVel());
432 ignition::math::Vector3d omega_nb_b =
433 q_br.RotateVector(
model_->RelativeAngularVel());
435 ignition::math::Vector3d mag_noise_b(
438 ignition::math::Vector3d accel_b = q_br.RotateVector(ignition::math::Vector3d(
439 imu_message->linear_acceleration().x(),
440 imu_message->linear_acceleration().y(),
441 imu_message->linear_acceleration().z()));
442 ignition::math::Vector3d gyro_b = q_br.RotateVector(ignition::math::Vector3d(
443 imu_message->angular_velocity().x(), imu_message->angular_velocity().y(),
444 imu_message->angular_velocity().z()));
445 ignition::math::Vector3d mag_b =
446 q_nb.RotateVectorReverse(mag_n) + mag_noise_b;
449 mavlink_hil_sensor_t sensor_msg;
450 sensor_msg.time_usec =
world_->SimTime().Double() * 1e6;
451 sensor_msg.xacc = accel_b.X();
452 sensor_msg.yacc = accel_b.Y();
453 sensor_msg.zacc = accel_b.Z();
454 sensor_msg.xgyro = gyro_b.X();
455 sensor_msg.ygyro = gyro_b.Y();
456 sensor_msg.zgyro = gyro_b.Z();
457 sensor_msg.xmag = mag_b.X();
458 sensor_msg.ymag = mag_b.Y();
459 sensor_msg.zmag = mag_b.Z();
463 const float lapse_rate =
465 const float temperature_msl = 288.0f;
467 float temperature_local = temperature_msl - lapse_rate * alt_msl;
468 float pressure_ratio = powf((temperature_msl / temperature_local), 5.256
f);
469 const float pressure_msl = 101325.0f;
470 sensor_msg.abs_pressure = pressure_msl / pressure_ratio;
474 double x1, x2, w, y1, y2;
476 x1 = 2.0 * (rand() * (1.0 / (double)RAND_MAX)) - 1.0;
477 x2 = 2.0 * (rand() * (1.0 / (double)RAND_MAX)) - 1.0;
478 w = x1 * x1 + x2 * x2;
485 float abs_pressure_noise = 1.0f * (
float)w;
486 sensor_msg.abs_pressure += abs_pressure_noise;
489 sensor_msg.abs_pressure *= 0.01f;
493 const float density_ratio =
494 powf((temperature_msl / temperature_local), 4.256
f);
495 float rho = 1.225f / density_ratio;
498 sensor_msg.pressure_alt =
499 alt_msl - abs_pressure_noise / (
gravity_W_.Length() * rho);
502 sensor_msg.diff_pressure = 0.005f * rho * vel_b.X() * vel_b.X();
505 sensor_msg.temperature = temperature_local - 273.0f;
507 sensor_msg.fields_updated = 4095;
510 static uint32_t last_dt_us = sensor_msg.time_usec;
511 uint32_t dt_us = sensor_msg.time_usec - last_dt_us;
514 last_dt_us = sensor_msg.time_usec;
518 mavlink_msg_hil_sensor_encode_chan(
533 ignition::math::Vector3d accel_true_b =
534 q_br.RotateVector(
model_->RelativeLinearAccel());
537 mavlink_hil_state_quaternion_t hil_state_quat;
538 hil_state_quat.time_usec =
world_->SimTime().Double() * 1e6;
539 hil_state_quat.attitude_quaternion[0] = q_nb.W();
540 hil_state_quat.attitude_quaternion[1] = q_nb.X();
541 hil_state_quat.attitude_quaternion[2] = q_nb.Y();
542 hil_state_quat.attitude_quaternion[3] = q_nb.Z();
544 hil_state_quat.rollspeed = omega_nb_b.X();
545 hil_state_quat.pitchspeed = omega_nb_b.Y();
546 hil_state_quat.yawspeed = omega_nb_b.Z();
550 hil_state_quat.alt = (-pos_n.Z() +
kAltZurich_m) * 1000;
552 hil_state_quat.vx = vel_n.X() * 100;
553 hil_state_quat.vy = vel_n.Y() * 100;
554 hil_state_quat.vz = vel_n.Z() * 100;
557 hil_state_quat.ind_airspeed = vel_b.X();
558 hil_state_quat.true_airspeed =
559 model_->WorldLinearVel().Length() * 100;
561 hil_state_quat.xacc = accel_true_b.X() * 1000;
562 hil_state_quat.yacc = accel_true_b.Y() * 1000;
563 hil_state_quat.zacc = accel_true_b.Z() * 1000;
566 mavlink_msg_hil_state_quaternion_encode_chan(
580 mavlink_distance_sensor_t sensor_msg;
581 sensor_msg.time_boot_ms = lidar_message->time_msec();
582 sensor_msg.min_distance = lidar_message->min_distance() * 100.0;
583 sensor_msg.max_distance = lidar_message->max_distance() * 100.0;
584 sensor_msg.current_distance = lidar_message->current_distance() * 100.0;
587 sensor_msg.orientation = 25;
588 sensor_msg.covariance = 0;
594 mavlink_msg_distance_sensor_encode_chan(
601 mavlink_hil_optical_flow_t sensor_msg;
602 sensor_msg.time_usec =
world_->SimTime().Double() * 1e6;
603 sensor_msg.sensor_id = opticalFlow_message->sensor_id();
604 sensor_msg.integration_time_us = opticalFlow_message->integration_time_us();
605 sensor_msg.integrated_x = opticalFlow_message->integrated_x();
606 sensor_msg.integrated_y = opticalFlow_message->integrated_y();
607 sensor_msg.integrated_xgyro =
609 sensor_msg.integrated_ygyro =
611 sensor_msg.integrated_zgyro = opticalFlow_message->quality()
614 sensor_msg.temperature = opticalFlow_message->temperature();
615 sensor_msg.quality = opticalFlow_message->quality();
616 sensor_msg.time_delta_distance_us =
617 opticalFlow_message->time_delta_distance_us();
624 mavlink_msg_hil_optical_flow_encode_chan(
630 double _dt, uint32_t _timeoutMs) {
633 tv.tv_sec = _timeoutMs / 1000;
634 tv.tv_usec = (_timeoutMs % 1000) * 1000UL;
637 ::poll(&
fds[0], (
sizeof(
fds[0]) /
sizeof(
fds[0])), 0);
639 if (
fds[0].revents & POLLIN) {
645 for (
unsigned i = 0; i <
len; ++i) {
660 switch (msg->
msgid) {
661 case MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS:
662 mavlink_hil_actuator_controls_t controls;
663 mavlink_msg_hil_actuator_controls_decode(msg, &controls);
666 if ((controls.mode & MAV_MODE_FLAG_SAFETY_ARMED) > 0) {
672 for (
unsigned i = 0; i <
kNOutMax; i++) {
706 for (
unsigned i = 0; i <
kNOutMax; ++i) {
729 double err = current - target;
730 double force =
pids_[i].Update(err, _dt);
731 joints_[i]->SetForce(0, force);
734 double err = current - target;
735 double force =
pids_[i].Update(err, _dt);
736 joints_[i]->SetForce(0, force);
739 m.set_type(gazebo::msgs::Any_ValueType_DOUBLE);
740 m.set_double_value(target);
761 serial_dev_.set_option(boost::asio::serial_port_base::character_size(8));
762 serial_dev_.set_option(boost::asio::serial_port_base::parity(
763 boost::asio::serial_port_base::parity::none));
764 serial_dev_.set_option(boost::asio::serial_port_base::stop_bits(
765 boost::asio::serial_port_base::stop_bits::one));
766 serial_dev_.set_option(boost::asio::serial_port_base::flow_control(
767 boost::asio::serial_port_base::flow_control::none));
768 gzdbg <<
"Opened serial device " <<
device_ <<
"\n";
769 }
catch (boost::system::system_error& err) {
770 gzerr <<
"Error opening serial device: " << err.what() <<
"\n";
791 boost::asio::placeholders::error,
792 boost::asio::placeholders::bytes_transferred));
797 const boost::system::error_code& err, std::size_t bytes_t) {
800 uint8_t* buf = this->
rx_buf_.data();
802 assert(
rx_buf_.size() >= bytes_t);
804 for (; bytes_t > 0; bytes_t--) {
807 auto msg_received =
static_cast<Framing>(
839 auto& buf_ref =
tx_q_.front();
842 boost::asio::buffer(buf_ref.dpos(), buf_ref.nbytes()),
844 boost::system::error_code error,
size_t bytes_transferred) {
845 assert(bytes_transferred <= buf_ref.len);
847 gzerr <<
"Serial error: " << error.message() <<
"\n";
858 buf_ref.pos += bytes_transferred;
859 if (buf_ref.nbytes() == 0) {
863 if (!
tx_q_.empty()) {
static const float kEarthRadius_m
transport::SubscriberPtr lidar_sub_
transport::SubscriberPtr opticalFlow_sub_
__BEGIN_DECLS float get_mag_declination(float lat, float lon)
static const u_int32_t kServoPositionFlag
std::lock_guard< std::recursive_mutex > lock_guard
double input_offset_[kNOutMax]
void send_mavlink_message(const mavlink_message_t *message, const int destination_port=0)
std::string motor_velocity_reference_pub_topic_
MAVLINK_HELPER void mavlink_start_checksum(mavlink_message_t *msg)
void parse_buffer(const boost::system::error_code &err, std::size_t bytes_t)
ignition::math::Vector3d mag_d_
double imu_update_interval_
#define MAVLINK_MAX_PACKET_LEN
void pollForMAVLinkMessages(double _dt, uint32_t _timeoutMs)
void ImuCallback(ImuPtr &imu_msg)
mavlink_message_t m_buffer_
static constexpr size_t MAX_TXQ_SIZE
static const size_t kNumMotors
struct sockaddr_in srcaddr_
SITL instance.
transport::NodePtr node_handle_
std::atomic< bool > tx_in_progress_
void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
void do_write(bool check_tx_state)
static const double kLatZurich_rad
std::string lidar_sub_topic_
std::string to_string(MAV_SENSOR_ORIENTATION orientation)
mavlink_parse_state_t parse_state
void OnUpdate(const common::UpdateInfo &)
transport::PublisherPtr motor_velocity_reference_pub_
ignition::math::Vector3d gravity_W_
static const size_t kNumServos
unsigned char buf_[65535]
boost::asio::serial_port serial_dev_
void LidarCallback(LidarPtr &lidar_msg)
mavlink_status_t m_status_
double zero_position_armed_[kNOutMax]
static const u_int32_t kMotorSpeedFlag
MAVLINK_HELPER uint8_t mavlink_frame_char_buffer(mavlink_message_t *rxmsg, mavlink_status_t *status, uint8_t c, mavlink_message_t *r_message, mavlink_status_t *r_mavlink_status)
void OpticalFlowCallback(OpticalFlowPtr &opticalFlow_msg)
std::recursive_mutex mutex_
common::Time last_imu_time_
Framing
Rx packer framing status. (same as mavlink::mavlink_framing_t)
Eigen::VectorXd input_reference_
std::string imu_sub_topic_
bool received_first_reference_
#define MAVLINK_STATUS_FLAG_OUT_MAVLINK1
static const double kLonZurich_rad
~GazeboMavlinkInterface()
MAVLINK_HELPER mavlink_status_t * mavlink_get_channel_status(uint8_t chan)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
std::string joint_control_type_[kNOutMax]
std::vector< common::PID > pids_
double zero_position_disarmed_[kNOutMax]
struct sockaddr_in myaddr_
The locally bound address.
int input_index_[kNOutMax]
std::string gztopic_[kNOutMax]
boost::asio::io_service io_service_
MAVLINK_PARSE_STATE_GOT_STX
transport::SubscriberPtr imu_sub_
event::ConnectionPtr updateConnection_
Pointer to the update event connection.
boost::asio::ip::tcp::socket socket
std::array< uint8_t, MAX_SIZE > rx_buf_
GZ_REGISTER_MODEL_PLUGIN(GazeboRosP3D)
std::deque< MsgBuffer > tx_q_
MAVLINK_FRAMING_INCOMPLETE
std::normal_distribution< float > randn_
MAVLINK_HELPER uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_message_t *r_message, mavlink_status_t *r_mavlink_status)
common::Time last_actuator_time_
void handle_control(double _dt)
transport::PublisherPtr joint_control_pub_[kNOutMax]
MAVLINK_HELPER uint16_t mavlink_msg_to_send_buffer(uint8_t *buffer, const mavlink_message_t *msg)
std::default_random_engine rand_
ignition::math::Vector3d optflow_gyro_
std::vector< physics::JointPtr > joints_
static const size_t kNOutMax
double input_scaling_[kNOutMax]
void handle_message(mavlink_message_t *msg)
std::string opticalFlow_sub_topic_
static const double kAltZurich_m
void model_param(const std::string &world_name, const std::string &model_name, const std::string ¶m, T ¶m_value)