gazebo_mavlink_interface.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2015 Fadri Furrer, ASL, ETH Zurich, Switzerland
3  * Copyright 2015 Michael Burri, ASL, ETH Zurich, Switzerland
4  * Copyright 2015 Mina Kamel, ASL, ETH Zurich, Switzerland
5  * Copyright 2015 Janosch Nikolic, ASL, ETH Zurich, Switzerland
6  * Copyright 2015 Markus Achtelik, ASL, ETH Zurich, Switzerland
7  * Copyright 2015-2018 PX4 Pro Development Team
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
23 
24 namespace gazebo {
25 
26 // Set global reference point
27 // Zurich Irchel Park: 47.397742, 8.545594, 488m
28 // Seattle downtown (15 deg declination): 47.592182, -122.316031, 86m
29 // Moscow downtown: 55.753395, 37.625427, 155m
30 
31 // Zurich Irchel Park
32 static const double kLatZurich_rad = 47.397742 * M_PI / 180; // rad
33 static const double kLonZurich_rad = 8.545594 * M_PI / 180; // rad
34 static const double kAltZurich_m = 488.0; // meters
35 static const float kEarthRadius_m = 6353000; // m
36 
38 
40  updateConnection_->~Connection();
41 }
42 
44  physics::ModelPtr _model, sdf::ElementPtr _sdf) {
45  // Store the pointer to the model.
46  model_ = _model;
47 
48  world_ = model_->GetWorld();
49 
50  const char* env_alt = std::getenv("PX4_HOME_ALT");
51  if (env_alt) {
52  gzmsg << "Home altitude is set to " << env_alt << ".\n";
53  alt_home = std::stod(env_alt);
54  }
55 
56  namespace_.clear();
57  if (_sdf->HasElement("robotNamespace")) {
58  namespace_ = _sdf->GetElement("robotNamespace")->Get<std::string>();
59  } else {
60  gzerr << "[gazebo_mavlink_interface] Please specify a robotNamespace.\n";
61  }
62 
63  if (_sdf->HasElement("protocol_version")) {
64  protocol_version_ = _sdf->GetElement("protocol_version")->Get<float>();
65  }
66 
67  node_handle_ = transport::NodePtr(new transport::Node());
68  node_handle_->Init();
69 
70  getSdfParam<std::string>(
71  _sdf, "motorSpeedCommandPubTopic", motor_velocity_reference_pub_topic_,
73  gzdbg << "motorSpeedCommandPubTopic = \""
74  << motor_velocity_reference_pub_topic_ << "\"." << std::endl;
75  getSdfParam<std::string>(_sdf, "imuSubTopic", imu_sub_topic_, imu_sub_topic_);
76  getSdfParam<std::string>(
77  _sdf, "lidarSubTopic", lidar_sub_topic_, lidar_sub_topic_);
78  getSdfParam<std::string>(
79  _sdf, "opticalFlowSubTopic", opticalFlow_sub_topic_,
81 
82  // set input_reference_ from inputs.control
83  input_reference_.resize(kNOutMax);
84  joints_.resize(kNOutMax);
85  pids_.resize(kNOutMax);
86  for (int i = 0; i < kNOutMax; ++i) {
87  pids_[i].Init(0, 0, 0, 0, 0, 0, 0);
88  input_reference_[i] = 0;
89  }
90 
91  if (_sdf->HasElement("control_channels")) {
92  sdf::ElementPtr control_channels = _sdf->GetElement("control_channels");
93  sdf::ElementPtr channel = control_channels->GetElement("channel");
94  while (channel) {
95  if (channel->HasElement("input_index")) {
96  int index = channel->Get<int>("input_index");
97  if (index < kNOutMax) {
98  input_offset_[index] = channel->Get<double>("input_offset");
99  input_scaling_[index] = channel->Get<double>("input_scaling");
100  zero_position_disarmed_[index] =
101  channel->Get<double>("zero_position_disarmed");
102  zero_position_armed_[index] =
103  channel->Get<double>("zero_position_armed");
104  if (channel->HasElement("joint_control_type")) {
105  joint_control_type_[index] =
106  channel->Get<std::string>("joint_control_type");
107  } else {
108  gzwarn << "joint_control_type[" << index
109  << "] not specified, using velocity.\n";
110  joint_control_type_[index] = "velocity";
111  }
112 
113  // start gz transport node handle
114  if (joint_control_type_[index] == "position_gztopic") {
115  // setup publisher handle to topic
116  if (channel->HasElement("gztopic"))
117  gztopic_[index] = "~/" + model_->GetName() +
118  channel->Get<std::string>("gztopic");
119  else
120  gztopic_[index] =
121  "control_position_gztopic_" + std::to_string(index);
122 
123  joint_control_pub_[index] =
124  node_handle_->Advertise<gazebo::msgs::Any>(gztopic_[index]);
125  }
126 
127  if (channel->HasElement("joint_name")) {
128  std::string joint_name = channel->Get<std::string>("joint_name");
129  joints_[index] = model_->GetJoint(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";
133  } else {
134  gzdbg << "joint [" << joint_name << "] found for channel["
135  << index << "] joint control active for this channel.\n";
136  }
137  } else {
138  gzdbg << "<joint_name> not found for channel[" << index
139  << "] no joint control will be performed for this channel.\n";
140  }
141 
142  // setup joint control pid to control joint
143  if (channel->HasElement("joint_control_pid")) {
144  sdf::ElementPtr pid = channel->GetElement("joint_control_pid");
145  double p = 0;
146  if (pid->HasElement("p"))
147  p = pid->Get<double>("p");
148  double i = 0;
149  if (pid->HasElement("i"))
150  i = pid->Get<double>("i");
151  double d = 0;
152  if (pid->HasElement("d"))
153  d = pid->Get<double>("d");
154  double iMax = 0;
155  if (pid->HasElement("iMax"))
156  iMax = pid->Get<double>("iMax");
157  double iMin = 0;
158  if (pid->HasElement("iMin"))
159  iMin = pid->Get<double>("iMin");
160  double cmdMax = 0;
161  if (pid->HasElement("cmdMax"))
162  cmdMax = pid->Get<double>("cmdMax");
163  double cmdMin = 0;
164  if (pid->HasElement("cmdMin"))
165  cmdMin = pid->Get<double>("cmdMin");
166  pids_[index].Init(p, i, d, iMax, iMin, cmdMax, cmdMin);
167  }
168  } else {
169  gzerr << "input_index[" << index << "] out of range, not parsing.\n";
170  }
171  } else {
172  gzerr << "no input_index, not parsing.\n";
173  break;
174  }
175  channel = channel->GetNextElement("channel");
176  }
177  }
178 
179  // Listen to the update event. This event is broadcast every
180  // simulation iteration.
181  updateConnection_ = event::Events::ConnectWorldUpdateBegin(
182  boost::bind(&GazeboMavlinkInterface::OnUpdate, this, _1));
183 
184  // Subscriber to IMU sensor_msgs::Imu Message and SITL message
185  imu_sub_ = node_handle_->Subscribe(
186  "~/" + model_->GetName() + imu_sub_topic_,
188  lidar_sub_ = node_handle_->Subscribe(
189  "~/" + model_->GetName() + lidar_sub_topic_,
191  opticalFlow_sub_ = node_handle_->Subscribe(
192  "~/" + model_->GetName() + opticalFlow_sub_topic_,
194 
195  // Publish gazebo's motor_speed message
197  node_handle_->Advertise<gz_mav_msgs::CommandMotorSpeed>(
198  "~/" + model_->GetName() + motor_velocity_reference_pub_topic_, 1);
199 
200  _rotor_count = 5;
201 
202  last_time_ = world_->SimTime();
203  last_imu_time_ = world_->SimTime();
204  gravity_W_ = world_->Gravity();
205 
206  if (_sdf->HasElement("imu_rate")) {
207  imu_update_interval_ = 1.0 / _sdf->GetElement("imu_rate")->Get<int>();
208  }
209 
210  // Magnetic field data for Zurich from WMM2015 (10^5xnanoTesla (N, E D)
211  // n-frame ) mag_n_ = {0.21523, 0.00771, -0.42741}; We set the world Y
212  // component to zero because we apply the declination based on the global
213  // position, and so we need to start without any offsets. The real value for
214  // Zurich would be 0.00771 frame d is the magnetic north frame
215  mag_d_.X() = 0.21523;
216  mag_d_.Y() = 0;
217  mag_d_.Z() = -0.42741;
218 
219  if (_sdf->HasElement("hil_state_level")) {
220  hil_mode_ = _sdf->GetElement("hil_mode")->Get<bool>();
221  }
222 
223  if (_sdf->HasElement("hil_state_level")) {
224  hil_state_level_ = _sdf->GetElement("hil_state_level")->Get<bool>();
225  }
226 
227  // Get serial params
228  if (_sdf->HasElement("serialEnabled")) {
229  serial_enabled_ = _sdf->GetElement("serialEnabled")->Get<bool>();
230  }
231 
232  if (serial_enabled_) {
233  // Set up serial interface
234  if (_sdf->HasElement("serialDevice")) {
235  device_ = _sdf->GetElement("serialDevice")->Get<std::string>();
236  }
237 
238  if (_sdf->HasElement("baudRate")) {
239  baudrate_ = _sdf->GetElement("baudRate")->Get<int>();
240  }
241  io_service_.post(std::bind(&GazeboMavlinkInterface::do_read, this));
242 
243  // run io_service for async io
244  io_thread_ = std::thread([this]() { io_service_.run(); });
245  open();
246  }
247 
248  // Create socket
249  // udp socket data
250  mavlink_addr_ = htonl(INADDR_ANY);
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") {
255  mavlink_addr_ = inet_addr(mavlink_addr.c_str());
256  if (mavlink_addr_ == INADDR_NONE) {
257  fprintf(stderr, "invalid mavlink_addr \"%s\"\n", mavlink_addr.c_str());
258  return;
259  }
260  }
261  }
262  if (_sdf->HasElement("mavlink_udp_port")) {
263  mavlink_udp_port_ = _sdf->GetElement("mavlink_udp_port")->Get<int>();
264  }
265 
266  auto worldName = world_->Name();
267  model_param(worldName, model_->GetName(), "mavlink_udp_port",
269 
270  qgc_addr_ = htonl(INADDR_ANY);
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());
277  return;
278  }
279  }
280  }
281  if (_sdf->HasElement("qgc_udp_port")) {
282  qgc_udp_port_ = _sdf->GetElement("qgc_udp_port")->Get<int>();
283  }
284 
285  // try to setup udp socket for communcation
286  if ((_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
287  printf("create socket failed\n");
288  return;
289  }
290 
291  memset((char*)&myaddr_, 0, sizeof(myaddr_));
292  myaddr_.sin_family = AF_INET;
293  srcaddr_.sin_family = AF_INET;
294 
295  if (serial_enabled_) {
296  // gcs link
297  myaddr_.sin_addr.s_addr = mavlink_addr_;
298  myaddr_.sin_port = htons(mavlink_udp_port_);
299  srcaddr_.sin_addr.s_addr = qgc_addr_;
300  srcaddr_.sin_port = htons(qgc_udp_port_);
301  }
302 
303  else {
304  myaddr_.sin_addr.s_addr = htonl(INADDR_ANY);
305  // Let the OS pick the port
306  myaddr_.sin_port = htons(0);
307  srcaddr_.sin_addr.s_addr = mavlink_addr_;
308  srcaddr_.sin_port = htons(mavlink_udp_port_);
309  }
310 
311  addrlen_ = sizeof(srcaddr_);
312 
313  if (bind(_fd, (struct sockaddr*)&myaddr_, sizeof(myaddr_)) < 0) {
314  printf("bind failed\n");
315  return;
316  }
317 
318  fds[0].fd = _fd;
319  fds[0].events = POLLIN;
320 
322 
323  // set the Mavlink protocol version to use on the link
324  if (protocol_version_ == 2.0) {
325  chan_state->flags &= ~(MAVLINK_STATUS_FLAG_OUT_MAVLINK1);
326  gzmsg << "Using MAVLink protocol v2.0\n";
327  } else if (protocol_version_ == 1.0) {
329  gzmsg << "Using MAVLink protocol v1.0\n";
330  } else {
331  gzerr << "Unkown protocol version! Using v" << protocol_version_
332  << "by default \n";
333  }
334 }
335 
336 // This gets called by the world update start event.
337 void GazeboMavlinkInterface::OnUpdate(const common::UpdateInfo& /*_info*/) {
338  common::Time current_time = world_->SimTime();
339  double dt = (current_time - last_time_).Double();
340 
341  pollForMAVLinkMessages(dt, 1000);
342 
343  handle_control(dt);
344 
346  gz_mav_msgs::CommandMotorSpeed turning_velocities_msg;
347 
348  for (int i = 0; i < input_reference_.size(); i++) {
349  if (last_actuator_time_ == 0 ||
350  (current_time - last_actuator_time_).Double() > 0.2) {
351  turning_velocities_msg.add_motor_speed(0);
352  } else {
353  turning_velocities_msg.add_motor_speed(input_reference_[i]);
354  }
355  }
356  // TODO Add timestamp and Header
357  // turning_velocities_msg->header.stamp.sec = current_time.sec;
358  // turning_velocities_msg->header.stamp.nsec = current_time.nsec;
359 
360  motor_velocity_reference_pub_->Publish(turning_velocities_msg);
361  }
362 
363  last_time_ = current_time;
364 }
365 
367  const mavlink_message_t* message, const int destination_port) {
368  if (serial_enabled_ && destination_port == 0) {
369  assert(message != nullptr);
370  if (!is_open()) {
371  gzerr << "Serial port closed! \n";
372  return;
373  }
374 
375  {
376  lock_guard lock(mutex_);
377 
378  if (tx_q_.size() >= MAX_TXQ_SIZE) {
379  // gzwarn << "TX queue overflow. \n";
380  }
381  tx_q_.emplace_back(message);
382  }
383  io_service_.post(std::bind(&GazeboMavlinkInterface::do_write, this, true));
384  }
385 
386  else {
387  uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
388  int packetlen = mavlink_msg_to_send_buffer(buffer, message);
389 
390  struct sockaddr_in dest_addr;
391  memcpy(&dest_addr, &srcaddr_, sizeof(srcaddr_));
392 
393  if (destination_port != 0) {
394  dest_addr.sin_port = htons(destination_port);
395  }
396 
397  ssize_t len = sendto(
398  _fd, buffer, packetlen, 0, (struct sockaddr*)&srcaddr_,
399  sizeof(srcaddr_));
400 
401  if (len <= 0) {
402  printf("Failed sending mavlink message\n");
403  }
404  }
405 }
406 
408  common::Time current_time = world_->SimTime();
409  double dt = (current_time - last_imu_time_).Double();
410 
411  ignition::math::Quaterniond q_br(0, 1, 0, 0);
412  ignition::math::Quaterniond q_ng(0, 0.70711, 0.70711, 0);
413 
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());
417 
418  ignition::math::Quaterniond q_gb = q_gr * q_br.Inverse();
419  ignition::math::Quaterniond q_nb = q_ng * q_gb;
420 
421  ignition::math::Vector3d pos_g = model_->WorldPose().Pos();
422  ignition::math::Vector3d pos_n = q_ng.RotateVector(pos_g);
423 
424  float declination = get_mag_declination(lat_rad_, lon_rad_);
425 
426  ignition::math::Quaterniond q_dn(0.0, 0.0, declination);
427  ignition::math::Vector3d mag_n = q_dn.RotateVector(mag_d_);
428 
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());
434 
435  ignition::math::Vector3d mag_noise_b(
436  0.01 * randn_(rand_), 0.01 * randn_(rand_), 0.01 * randn_(rand_));
437 
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;
447 
448  if (imu_update_interval_ != 0 && dt >= imu_update_interval_) {
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();
460 
461  // calculate abs_pressure using an ISA model for the tropsphere (valid up to
462  // 11km above MSL)
463  const float lapse_rate =
464  0.0065f; // reduction in temperature with altitude (Kelvin/m)
465  const float temperature_msl = 288.0f; // temperature at MSL (Kelvin)
466  float alt_msl = (float)alt_home - pos_n.Z();
467  float temperature_local = temperature_msl - lapse_rate * alt_msl;
468  float pressure_ratio = powf((temperature_msl / temperature_local), 5.256f);
469  const float pressure_msl = 101325.0f; // pressure at MSL
470  sensor_msg.abs_pressure = pressure_msl / pressure_ratio;
471 
472  // generate Gaussian noise sequence using polar form of Box-Muller
473  // transformation http://www.design.caltech.edu/erik/Misc/Gaussian.html
474  double x1, x2, w, y1, y2;
475  do {
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;
479  } while (w >= 1.0);
480  w = sqrt((-2.0 * log(w)) / w);
481  y1 = x1 * w;
482  y2 = x2 * w;
483 
484  // Apply 1 Pa RMS noise
485  float abs_pressure_noise = 1.0f * (float)w;
486  sensor_msg.abs_pressure += abs_pressure_noise;
487 
488  // convert to hPa
489  sensor_msg.abs_pressure *= 0.01f;
490 
491  // calculate density using an ISA model for the tropsphere (valid up to 11km
492  // above MSL)
493  const float density_ratio =
494  powf((temperature_msl / temperature_local), 4.256f);
495  float rho = 1.225f / density_ratio;
496 
497  // calculate pressure altitude including effect of pressure noise
498  sensor_msg.pressure_alt =
499  alt_msl - abs_pressure_noise / (gravity_W_.Length() * rho);
500 
501  // calculate differential pressure in hPa
502  sensor_msg.diff_pressure = 0.005f * rho * vel_b.X() * vel_b.X();
503 
504  // calculate temperature in Celsius
505  sensor_msg.temperature = temperature_local - 273.0f;
506 
507  sensor_msg.fields_updated = 4095;
508 
509  // accumulate gyro measurements that are needed for the optical flow message
510  static uint32_t last_dt_us = sensor_msg.time_usec;
511  uint32_t dt_us = sensor_msg.time_usec - last_dt_us;
512  if (dt_us > 1000) {
513  optflow_gyro_ += gyro_b * (dt_us / 1000000.0f);
514  last_dt_us = sensor_msg.time_usec;
515  }
516 
518  mavlink_msg_hil_sensor_encode_chan(
519  1, 200, MAVLINK_COMM_0, &msg, &sensor_msg);
520  if (hil_mode_) {
521  if (!hil_state_level_) {
522  send_mavlink_message(&msg);
523  }
524  }
525 
526  else {
527  send_mavlink_message(&msg);
528  }
529  last_imu_time_ = current_time;
530  }
531 
532  // ground truth
533  ignition::math::Vector3d accel_true_b =
534  q_br.RotateVector(model_->RelativeLinearAccel());
535 
536  // send ground truth
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();
543 
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();
547 
548  hil_state_quat.lat = lat_rad_ * 180 / M_PI * 1e7;
549  hil_state_quat.lon = lon_rad_ * 180 / M_PI * 1e7;
550  hil_state_quat.alt = (-pos_n.Z() + kAltZurich_m) * 1000;
551 
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;
555 
556  // assumed indicated airspeed due to flow aligned with pitot (body x)
557  hil_state_quat.ind_airspeed = vel_b.X();
558  hil_state_quat.true_airspeed =
559  model_->WorldLinearVel().Length() * 100; // no wind simulated
560 
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;
564 
566  mavlink_msg_hil_state_quaternion_encode_chan(
567  1, 200, MAVLINK_COMM_0, &msg, &hil_state_quat);
568  if (hil_mode_) {
569  if (hil_state_level_) {
570  send_mavlink_message(&msg);
571  }
572  }
573 
574  else {
575  send_mavlink_message(&msg);
576  }
577 }
578 
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;
585  sensor_msg.type = 0;
586  sensor_msg.id = 0;
587  sensor_msg.orientation = 25; // downward facing
588  sensor_msg.covariance = 0;
589 
590  // distance needed for optical flow message
591  optflow_distance_ = lidar_message->current_distance(); //[m]
592 
594  mavlink_msg_distance_sensor_encode_chan(
595  1, 200, MAVLINK_COMM_0, &msg, &sensor_msg);
596  send_mavlink_message(&msg);
597 }
598 
600  OpticalFlowPtr& opticalFlow_message) {
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 =
608  opticalFlow_message->quality() ? -optflow_gyro_.Y() : 0.0f; // xy switched
609  sensor_msg.integrated_ygyro =
610  opticalFlow_message->quality() ? optflow_gyro_.X() : 0.0f; // xy switched
611  sensor_msg.integrated_zgyro = opticalFlow_message->quality()
612  ? -optflow_gyro_.Z()
613  : 0.0f; // change direction
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();
618  sensor_msg.distance = optflow_distance_;
619 
620  // reset gyro integral
621  optflow_gyro_.Set();
622 
624  mavlink_msg_hil_optical_flow_encode_chan(
625  1, 200, MAVLINK_COMM_0, &msg, &sensor_msg);
626  send_mavlink_message(&msg);
627 }
628 
630  double _dt, uint32_t _timeoutMs) {
631  // convert timeout in ms to timeval
632  struct timeval tv;
633  tv.tv_sec = _timeoutMs / 1000;
634  tv.tv_usec = (_timeoutMs % 1000) * 1000UL;
635 
636  // poll
637  ::poll(&fds[0], (sizeof(fds[0]) / sizeof(fds[0])), 0);
638 
639  if (fds[0].revents & POLLIN) {
640  int len = recvfrom(
641  _fd, buf_, sizeof(buf_), 0, (struct sockaddr*)&srcaddr_, &addrlen_);
642  if (len > 0) {
644  mavlink_status_t status;
645  for (unsigned i = 0; i < len; ++i) {
646  if (mavlink_parse_char(MAVLINK_COMM_0, buf_[i], &msg, &status)) {
647  if (serial_enabled_) {
648  // forward message from qgc to serial
649  send_mavlink_message(&msg);
650  }
651  // have a message, handle it
652  handle_message(&msg);
653  }
654  }
655  }
656  }
657 }
658 
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);
664  bool armed = false;
665 
666  if ((controls.mode & MAV_MODE_FLAG_SAFETY_ARMED) > 0) {
667  armed = true;
668  }
669 
670  last_actuator_time_ = world_->SimTime();
671 
672  for (unsigned i = 0; i < kNOutMax; i++) {
673  input_index_[i] = i;
674  }
675 
676  // Set rotor speeds and controller targets for flagged messages.
677  if (controls.flags == kMotorSpeedFlag) {
678  input_reference_.resize(kNOutMax);
679  for (unsigned i = 0; i < kNumMotors; ++i) {
680  if (armed) {
681  input_reference_[i] =
682  (controls.controls[input_index_[i]] + input_offset_[i]) *
683  input_scaling_[i] +
685  } else {
687  }
688  }
690  } else if (controls.flags == kServoPositionFlag) {
691  for (unsigned i = kNumMotors; i < (kNumMotors + kNumServos); ++i) {
692  if (armed) {
693  input_reference_[i] =
694  (controls.controls[input_index_[i - kNumMotors]] +
695  input_offset_[i]) *
696  input_scaling_[i] +
698  } else {
700  }
701  }
702  }
703  // Set rotor speeds, controller targets for unflagged messages.
704  else {
705  input_reference_.resize(kNOutMax);
706  for (unsigned i = 0; i < kNOutMax; ++i) {
707  if (armed) {
708  input_reference_[i] =
709  (controls.controls[input_index_[i]] + input_offset_[i]) *
710  input_scaling_[i] +
712  } else {
714  }
715  }
717  }
718  break;
719  }
720 }
721 
723  // set joint positions
724  for (int i = 0; i < input_reference_.size(); i++) {
725  if (joints_[i]) {
726  double target = input_reference_[i];
727  if (joint_control_type_[i] == "velocity") {
728  double current = joints_[i]->GetVelocity(0);
729  double err = current - target;
730  double force = pids_[i].Update(err, _dt);
731  joints_[i]->SetForce(0, force);
732  } else if (joint_control_type_[i] == "position") {
733  double current = joints_[i]->Position(0);
734  double err = current - target;
735  double force = pids_[i].Update(err, _dt);
736  joints_[i]->SetForce(0, force);
737  } else if (joint_control_type_[i] == "position_gztopic") {
738  gazebo::msgs::Any m;
739  m.set_type(gazebo::msgs::Any_ValueType_DOUBLE);
740  m.set_double_value(target);
741  joint_control_pub_[i]->Publish(m);
742  } else if (joint_control_type_[i] == "position_kinematic") {
746 
747  joints_[i]->SetPosition(0, input_reference_[i]);
748 
749  } else {
750  gzerr << "joint_control_type[" << joint_control_type_[i]
751  << "] undefined.\n";
752  }
753  }
754  }
755 }
756 
758  try {
759  serial_dev_.open(device_);
760  serial_dev_.set_option(boost::asio::serial_port_base::baud_rate(baudrate_));
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";
771  }
772 }
773 
775  lock_guard lock(mutex_);
776  if (!is_open())
777  return;
778 
779  io_service_.stop();
780  serial_dev_.close();
781 
782  if (io_thread_.joinable())
783  io_thread_.join();
784 }
785 
787  serial_dev_.async_read_some(
788  boost::asio::buffer(rx_buf_),
789  boost::bind(
791  boost::asio::placeholders::error,
792  boost::asio::placeholders::bytes_transferred));
793 }
794 
795 // Based on MAVConnInterface::parse_buffer in MAVROS
797  const boost::system::error_code& err, std::size_t bytes_t) {
798  mavlink_status_t status;
799  mavlink_message_t message;
800  uint8_t* buf = this->rx_buf_.data();
801 
802  assert(rx_buf_.size() >= bytes_t);
803 
804  for (; bytes_t > 0; bytes_t--) {
805  auto c = *buf++;
806 
807  auto msg_received = static_cast<Framing>(
808  mavlink_frame_char_buffer(&m_buffer_, &m_status_, c, &message, &status));
809  if (msg_received == Framing::bad_crc ||
810  msg_received == Framing::bad_signature) {
811  _mav_parse_error(&m_status_);
814  if (c == MAVLINK_STX) {
816  m_buffer_.len = 0;
818  }
819  }
820 
821  if (msg_received != Framing::incomplete) {
822  // send to gcs
824  handle_message(&message);
825  }
826  }
827  do_read();
828 }
829 
830 void GazeboMavlinkInterface::do_write(bool check_tx_state) {
831  if (check_tx_state && tx_in_progress_)
832  return;
833 
834  lock_guard lock(mutex_);
835  if (tx_q_.empty())
836  return;
837 
838  tx_in_progress_ = true;
839  auto& buf_ref = tx_q_.front();
840 
841  serial_dev_.async_write_some(
842  boost::asio::buffer(buf_ref.dpos(), buf_ref.nbytes()),
843  [this, &buf_ref](
844  boost::system::error_code error, size_t bytes_transferred) {
845  assert(bytes_transferred <= buf_ref.len);
846  if (error) {
847  gzerr << "Serial error: " << error.message() << "\n";
848  return;
849  }
850 
851  lock_guard lock(mutex_);
852 
853  if (tx_q_.empty()) {
854  tx_in_progress_ = false;
855  return;
856  }
857 
858  buf_ref.pos += bytes_transferred;
859  if (buf_ref.nbytes() == 0) {
860  tx_q_.pop_front();
861  }
862 
863  if (!tx_q_.empty()) {
864  do_write(false);
865  } else {
866  tx_in_progress_ = false;
867  }
868  });
869 }
870 
871 } // namespace gazebo
static const float kEarthRadius_m
d
msg
transport::SubscriberPtr opticalFlow_sub_
__BEGIN_DECLS float get_mag_declination(float lat, float lon)
std::lock_guard< std::recursive_mutex > lock_guard
void send_mavlink_message(const mavlink_message_t *message, const int destination_port=0)
void parse_buffer(const boost::system::error_code &err, std::size_t bytes_t)
void pollForMAVLinkMessages(double _dt, uint32_t _timeoutMs)
static constexpr size_t MAX_TXQ_SIZE
struct sockaddr_in srcaddr_
SITL instance.
void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
static const double kLatZurich_rad
#define M_PI
ssize_t len
std::string to_string(MAV_SENSOR_ORIENTATION orientation)
void OnUpdate(const common::UpdateInfo &)
transport::PublisherPtr motor_velocity_reference_pub_
void OpticalFlowCallback(OpticalFlowPtr &opticalFlow_msg)
Framing
Rx packer framing status. (same as mavlink::mavlink_framing_t)
static const double kLonZurich_rad
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
struct sockaddr_in myaddr_
The locally bound address.
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::normal_distribution< float > randn_
transport::PublisherPtr joint_control_pub_[kNOutMax]
ignition::math::Vector3d optflow_gyro_
std::vector< physics::JointPtr > joints_
float current
void handle_message(mavlink_message_t *msg)
static const double kAltZurich_m
void model_param(const std::string &world_name, const std::string &model_name, const std::string &param, T &param_value)
Definition: common.h:86


rotors_gazebo_plugins
Author(s): Fadri Furrer, Michael Burri, Mina Kamel, Janosch Nikolic, Markus Achtelik
autogenerated on Mon Feb 28 2022 23:39:03