PX4 Firmware
PX4 Autopilot Software http://px4.io
simulator_mavlink.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2015 Mark Charlebois. All rights reserved.
4  * Copyright (c) 2016 Anton Matosov. All rights reserved.
5  * Copyright (c) 2018 PX4 Development Team. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  * 3. Neither the name PX4 nor the names of its contributors may be
18  * used to endorse or promote products derived from this software
19  * without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  ****************************************************************************/
35 
36 #include <termios.h>
37 #include <px4_platform_common/log.h>
38 #include <px4_platform_common/time.h>
39 #include <px4_platform_common/tasks.h>
40 #include "simulator.h"
41 #include <simulator_config.h>
42 #include "errno.h"
43 #include <lib/ecl/geo/geo.h>
44 #include <drivers/drv_pwm_output.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <netinet/tcp.h>
48 #include <pthread.h>
49 #include <conversion/rotation.h>
50 #include <mathlib/mathlib.h>
51 
52 #include <limits>
53 
54 #ifdef ENABLE_UART_RC_INPUT
55 #ifndef B460800
56 #define B460800 460800
57 #endif
58 
59 #ifndef B921600
60 #define B921600 921600
61 #endif
62 
63 static int openUart(const char *uart_name, int baud);
64 #endif
65 
66 static int _fd;
67 static unsigned char _buf[2048];
68 static sockaddr_in _srcaddr;
69 static unsigned _addrlen = sizeof(_srcaddr);
70 
71 const unsigned mode_flag_armed = 128;
72 const unsigned mode_flag_custom = 1;
73 
74 using namespace simulator;
75 using namespace time_literals;
76 
77 mavlink_hil_actuator_controls_t Simulator::actuator_controls_from_outputs(const actuator_outputs_s &actuators)
78 {
79  mavlink_hil_actuator_controls_t msg{};
80 
81  msg.time_usec = hrt_absolute_time() + hrt_absolute_time_offset();
82 
83  bool armed = (_vehicle_status.arming_state == vehicle_status_s::ARMING_STATE_ARMED);
84 
85  const float pwm_center = (PWM_DEFAULT_MAX + PWM_DEFAULT_MIN) / 2;
86 
87  int _system_type = _param_mav_type.get();
88 
89  /* scale outputs depending on system type */
90  if (_system_type == MAV_TYPE_QUADROTOR ||
91  _system_type == MAV_TYPE_HEXAROTOR ||
92  _system_type == MAV_TYPE_OCTOROTOR ||
93  _system_type == MAV_TYPE_VTOL_DUOROTOR ||
94  _system_type == MAV_TYPE_VTOL_QUADROTOR ||
95  _system_type == MAV_TYPE_VTOL_TILTROTOR ||
96  _system_type == MAV_TYPE_VTOL_RESERVED2) {
97 
98  /* multirotors: set number of rotor outputs depending on type */
99 
100  unsigned n;
101 
102  switch (_system_type) {
103  case MAV_TYPE_VTOL_DUOROTOR:
104  n = 2;
105  break;
106 
107  case MAV_TYPE_QUADROTOR:
108  case MAV_TYPE_VTOL_QUADROTOR:
109  case MAV_TYPE_VTOL_TILTROTOR:
110  n = 4;
111  break;
112 
113  case MAV_TYPE_VTOL_RESERVED2:
114  // this is the standard VTOL / quad plane with 5 propellers
115  n = 5;
116  break;
117 
118  case MAV_TYPE_HEXAROTOR:
119  n = 6;
120  break;
121 
122  default:
123  n = 8;
124  break;
125  }
126 
127  for (unsigned i = 0; i < 16; i++) {
128  if (actuators.output[i] > PWM_DEFAULT_MIN / 2) {
129  if (i < n) {
130  /* scale PWM out PWM_DEFAULT_MIN..PWM_DEFAULT_MAX us to 0..1 for rotors */
131  msg.controls[i] = (actuators.output[i] - PWM_DEFAULT_MIN) / (PWM_DEFAULT_MAX - PWM_DEFAULT_MIN);
132 
133  } else {
134  /* scale PWM out PWM_DEFAULT_MIN..PWM_DEFAULT_MAX us to -1..1 for other channels */
135  msg.controls[i] = (actuators.output[i] - pwm_center) / ((PWM_DEFAULT_MAX - PWM_DEFAULT_MIN) / 2);
136  }
137 
138  } else {
139  /* send 0 when disarmed and for disabled channels */
140  msg.controls[i] = 0.0f;
141  }
142  }
143 
144  } else {
145  /* fixed wing: scale throttle to 0..1 and other channels to -1..1 */
146 
147  for (unsigned i = 0; i < 16; i++) {
148  if (actuators.output[i] > PWM_DEFAULT_MIN / 2) {
149  if (i != 4) {
150  /* scale PWM out PWM_DEFAULT_MIN..PWM_DEFAULT_MAX us to -1..1 for normal channels */
151  msg.controls[i] = (actuators.output[i] - pwm_center) / ((PWM_DEFAULT_MAX - PWM_DEFAULT_MIN) / 2);
152 
153  } else {
154  /* scale PWM out PWM_DEFAULT_MIN..PWM_DEFAULT_MAX us to 0..1 for throttle */
155  msg.controls[i] = (actuators.output[i] - PWM_DEFAULT_MIN) / (PWM_DEFAULT_MAX - PWM_DEFAULT_MIN);
156  }
157 
158  } else {
159  /* set 0 for disabled channels */
160  msg.controls[i] = 0.0f;
161  }
162  }
163  }
164 
165  msg.mode = mode_flag_custom;
166  msg.mode |= (armed) ? mode_flag_armed : 0;
167  msg.flags = 0;
168 
169  return msg;
170 }
171 
173 {
174  // copy new actuator data if available
175  bool updated = false;
176  orb_check(_actuator_outputs_sub, &updated);
177 
178  if (updated) {
179  actuator_outputs_s actuators{};
180  orb_copy(ORB_ID(actuator_outputs), _actuator_outputs_sub, &actuators);
181 
182  if (actuators.timestamp > 0) {
183  const mavlink_hil_actuator_controls_t hil_act_control = actuator_controls_from_outputs(actuators);
184 
185  mavlink_message_t message{};
186  mavlink_msg_hil_actuator_controls_encode(_param_mav_sys_id.get(), _param_mav_comp_id.get(), &message, &hil_act_control);
187 
188  PX4_DEBUG("sending controls t=%ld (%ld)", actuators.timestamp, hil_act_control.time_usec);
189 
190  send_mavlink_message(message);
191  }
192  }
193 }
194 
195 static void fill_rc_input_msg(input_rc_s *rc, mavlink_rc_channels_t *rc_channels)
196 {
199  rc->channel_count = rc_channels->chancount;
200  rc->rssi = rc_channels->rssi;
201 
202  rc->values[0] = rc_channels->chan1_raw;
203  rc->values[1] = rc_channels->chan2_raw;
204  rc->values[2] = rc_channels->chan3_raw;
205  rc->values[3] = rc_channels->chan4_raw;
206  rc->values[4] = rc_channels->chan5_raw;
207  rc->values[5] = rc_channels->chan6_raw;
208  rc->values[6] = rc_channels->chan7_raw;
209  rc->values[7] = rc_channels->chan8_raw;
210  rc->values[8] = rc_channels->chan9_raw;
211  rc->values[9] = rc_channels->chan10_raw;
212  rc->values[10] = rc_channels->chan11_raw;
213  rc->values[11] = rc_channels->chan12_raw;
214  rc->values[12] = rc_channels->chan13_raw;
215  rc->values[13] = rc_channels->chan14_raw;
216  rc->values[14] = rc_channels->chan15_raw;
217  rc->values[15] = rc_channels->chan16_raw;
218  rc->values[16] = rc_channels->chan17_raw;
219  rc->values[17] = rc_channels->chan18_raw;
220 }
221 
222 void Simulator::update_sensors(const hrt_abstime &time, const mavlink_hil_sensor_t &imu)
223 {
224  if ((imu.fields_updated & 0x1FFF) != 0x1FFF) {
225  PX4_DEBUG("All sensor fields in mavlink HIL_SENSOR packet not updated. Got %08x", imu.fields_updated);
226  }
227 
228  // gyro
229  {
230  static constexpr float scaling = 1000.0f;
231  _px4_gyro.set_scale(1 / scaling);
232  _px4_gyro.set_temperature(imu.temperature);
233  _px4_gyro.update(time, imu.xgyro * scaling, imu.ygyro * scaling, imu.zgyro * scaling);
234  }
235 
236  // accel
237  {
238  static constexpr float scaling = 1000.0f;
239  _px4_accel.set_scale(1 / scaling);
240  _px4_accel.set_temperature(imu.temperature);
241  _px4_accel.update(time, imu.xacc * scaling, imu.yacc * scaling, imu.zacc * scaling);
242  }
243 
244  // magnetometer
245  {
246  static constexpr float scaling = 1000.0f;
247  _px4_mag.set_scale(1 / scaling);
248  _px4_mag.set_temperature(imu.temperature);
249  _px4_mag.update(time, imu.xmag * scaling, imu.ymag * scaling, imu.zmag * scaling);
250  }
251 
252  // baro
253  {
254  _px4_baro.set_temperature(imu.temperature);
255  _px4_baro.update(time, imu.abs_pressure);
256  }
257 
258  // differential pressure
259  {
260  differential_pressure_s report{};
261  report.timestamp = time;
262  report.temperature = imu.temperature;
263  report.differential_pressure_filtered_pa = imu.diff_pressure * 100.0f; // convert from millibar to bar;
264  report.differential_pressure_raw_pa = imu.diff_pressure * 100.0f; // convert from millibar to bar;
265 
266  int instance;
267  orb_publish_auto(ORB_ID(differential_pressure), &_differential_pressure_pub, &report, &instance, ORB_PRIO_DEFAULT);
268  }
269 }
270 
271 void Simulator::update_gps(const mavlink_hil_gps_t *gps_sim)
272 {
273  RawGPSData gps = {};
275  gps.lat = gps_sim->lat;
276  gps.lon = gps_sim->lon;
277  gps.alt = gps_sim->alt;
278  gps.eph = gps_sim->eph;
279  gps.epv = gps_sim->epv;
280  gps.vel = gps_sim->vel;
281  gps.vn = gps_sim->vn;
282  gps.ve = gps_sim->ve;
283  gps.vd = gps_sim->vd;
284  gps.cog = gps_sim->cog;
285  gps.fix_type = gps_sim->fix_type;
286  gps.satellites_visible = gps_sim->satellites_visible;
287 
288  write_gps_data((void *)&gps);
289 }
290 
291 void Simulator::handle_message(const mavlink_message_t *msg)
292 {
293  switch (msg->msgid) {
294  case MAVLINK_MSG_ID_HIL_SENSOR:
295  handle_message_hil_sensor(msg);
296  break;
297 
298  case MAVLINK_MSG_ID_HIL_OPTICAL_FLOW:
299  handle_message_optical_flow(msg);
300  break;
301 
302  case MAVLINK_MSG_ID_ODOMETRY:
303  handle_message_odometry(msg);
304  break;
305 
306  case MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE:
307  handle_message_vision_position_estimate(msg);
308  break;
309 
310  case MAVLINK_MSG_ID_DISTANCE_SENSOR:
311  handle_message_distance_sensor(msg);
312  break;
313 
314  case MAVLINK_MSG_ID_HIL_GPS:
315  handle_message_hil_gps(msg);
316  break;
317 
318  case MAVLINK_MSG_ID_RC_CHANNELS:
319  handle_message_rc_channels(msg);
320  break;
321 
322  case MAVLINK_MSG_ID_LANDING_TARGET:
323  handle_message_landing_target(msg);
324  break;
325 
326  case MAVLINK_MSG_ID_HIL_STATE_QUATERNION:
327  handle_message_hil_state_quaternion(msg);
328  break;
329  }
330 }
331 
332 void Simulator::handle_message_distance_sensor(const mavlink_message_t *msg)
333 {
334  mavlink_distance_sensor_t dist;
335  mavlink_msg_distance_sensor_decode(msg, &dist);
336  publish_distance_topic(&dist);
337 }
338 
339 void Simulator::handle_message_hil_gps(const mavlink_message_t *msg)
340 {
341  mavlink_hil_gps_t gps_sim;
342  mavlink_msg_hil_gps_decode(msg, &gps_sim);
343 
344  update_gps(&gps_sim);
345 }
346 
347 void Simulator::handle_message_hil_sensor(const mavlink_message_t *msg)
348 {
349  mavlink_hil_sensor_t imu;
350  mavlink_msg_hil_sensor_decode(msg, &imu);
351 
352  struct timespec ts;
353  abstime_to_ts(&ts, imu.time_usec);
354  px4_clock_settime(CLOCK_MONOTONIC, &ts);
355 
356  hrt_abstime now_us = hrt_absolute_time();
357 
358 #if 0
359  // This is just for to debug missing HIL_SENSOR messages.
360  static hrt_abstime last_time = 0;
361  hrt_abstime diff = now_us - last_time;
362  float step = diff / 4000.0f;
363 
364  if (step > 1.1f || step < 0.9f) {
365  PX4_INFO("HIL_SENSOR: imu time_usec: %lu, time_usec: %lu, diff: %lu, step: %.2f", imu.time_usec, now_us, diff, step);
366  }
367 
368  last_time = now_us;
369 #endif
370 
371  update_sensors(now_us, imu);
372 
373  static float battery_percentage = 1.0f;
374  static uint64_t last_integration_us = 0;
375 
376  // battery simulation (limit update to 100Hz)
377  if (hrt_elapsed_time(&_battery_status.timestamp) >= 10_ms) {
378 
379  const float discharge_interval_us = _param_sim_bat_drain.get() * 1000 * 1000;
380 
381  bool armed = (_vehicle_status.arming_state == vehicle_status_s::ARMING_STATE_ARMED);
382 
383  if (armed) {
384  if (last_integration_us != 0) {
385  battery_percentage -= (now_us - last_integration_us) / discharge_interval_us;
386  }
387 
388  last_integration_us = now_us;
389 
390  } else {
391  last_integration_us = 0;
392  }
393 
394  float ibatt = -1.0f; // no current sensor in simulation
395 
396  battery_percentage = math::max(battery_percentage, _battery_min_percentage.get() / 100.f);
397  float vbatt = math::gradual(battery_percentage, 0.f, 1.f, _battery.empty_cell_voltage(), _battery.full_cell_voltage());
398  vbatt *= _battery.cell_count();
399 
400  const float throttle = 0.0f; // simulate no throttle compensation to make the estimate predictable
401  _battery.updateBatteryStatus(now_us, vbatt, ibatt, true, true, 0, throttle, armed, &_battery_status);
402 
403 
404  // publish the battery voltage
405  int batt_multi;
406  orb_publish_auto(ORB_ID(battery_status), &_battery_pub, &_battery_status, &batt_multi, ORB_PRIO_HIGH);
407  }
408 }
409 
411 {
412  mavlink_hil_state_quaternion_t hil_state;
413  mavlink_msg_hil_state_quaternion_decode(msg, &hil_state);
414 
415  uint64_t timestamp = hrt_absolute_time();
416 
417  /* angular velocity */
418  vehicle_angular_velocity_s hil_angular_velocity{};
419  {
420  hil_angular_velocity.timestamp = timestamp;
421 
422  hil_angular_velocity.xyz[0] = hil_state.rollspeed;
423  hil_angular_velocity.xyz[1] = hil_state.pitchspeed;
424  hil_angular_velocity.xyz[2] = hil_state.yawspeed;
425 
426  // always publish ground truth attitude message
427  int hilstate_multi;
428  orb_publish_auto(ORB_ID(vehicle_angular_velocity_groundtruth), &_vehicle_angular_velocity_pub, &hil_angular_velocity,
429  &hilstate_multi, ORB_PRIO_HIGH);
430  }
431 
432  /* attitude */
433  vehicle_attitude_s hil_attitude{};
434  {
435  hil_attitude.timestamp = timestamp;
436 
437  matrix::Quatf q(hil_state.attitude_quaternion);
438  q.copyTo(hil_attitude.q);
439 
440  // always publish ground truth attitude message
441  int hilstate_multi;
442  orb_publish_auto(ORB_ID(vehicle_attitude_groundtruth), &_attitude_pub, &hil_attitude, &hilstate_multi, ORB_PRIO_HIGH);
443  }
444 
445  /* global position */
446  vehicle_global_position_s hil_gpos{};
447  {
448  hil_gpos.timestamp = timestamp;
449 
450  hil_gpos.lat = hil_state.lat / 1E7;//1E7
451  hil_gpos.lon = hil_state.lon / 1E7;//1E7
452  hil_gpos.alt = hil_state.alt / 1E3;//1E3
453 
454  hil_gpos.vel_n = hil_state.vx / 100.0f;
455  hil_gpos.vel_e = hil_state.vy / 100.0f;
456  hil_gpos.vel_d = hil_state.vz / 100.0f;
457 
458  // always publish ground truth attitude message
459  int hil_gpos_multi;
460  orb_publish_auto(ORB_ID(vehicle_global_position_groundtruth), &_gpos_pub, &hil_gpos, &hil_gpos_multi, ORB_PRIO_HIGH);
461  }
462 
463  /* local position */
464  struct vehicle_local_position_s hil_lpos = {};
465  {
466  hil_lpos.timestamp = timestamp;
467 
468  double lat = hil_state.lat * 1e-7;
469  double lon = hil_state.lon * 1e-7;
470 
471  if (!_hil_local_proj_inited) {
472  _hil_local_proj_inited = true;
474  _hil_ref_timestamp = timestamp;
475  _hil_ref_lat = lat;
476  _hil_ref_lon = lon;
477  _hil_ref_alt = hil_state.alt / 1000.0f;
478  }
479 
480  float x;
481  float y;
482  map_projection_project(&_hil_local_proj_ref, lat, lon, &x, &y);
483  hil_lpos.timestamp = timestamp;
484  hil_lpos.xy_valid = true;
485  hil_lpos.z_valid = true;
486  hil_lpos.v_xy_valid = true;
487  hil_lpos.v_z_valid = true;
488  hil_lpos.x = x;
489  hil_lpos.y = y;
490  hil_lpos.z = _hil_ref_alt - hil_state.alt / 1000.0f;
491  hil_lpos.vx = hil_state.vx / 100.0f;
492  hil_lpos.vy = hil_state.vy / 100.0f;
493  hil_lpos.vz = hil_state.vz / 100.0f;
494  matrix::Eulerf euler = matrix::Quatf(hil_attitude.q);
495  hil_lpos.yaw = euler.psi();
496  hil_lpos.xy_global = true;
497  hil_lpos.z_global = true;
498  hil_lpos.ref_lat = _hil_ref_lat;
499  hil_lpos.ref_lon = _hil_ref_lon;
500  hil_lpos.ref_alt = _hil_ref_alt;
501  hil_lpos.ref_timestamp = _hil_ref_timestamp;
502  hil_lpos.vxy_max = std::numeric_limits<float>::infinity();
503  hil_lpos.vz_max = std::numeric_limits<float>::infinity();
504  hil_lpos.hagl_min = std::numeric_limits<float>::infinity();
505  hil_lpos.hagl_max = std::numeric_limits<float>::infinity();
506 
507  // always publish ground truth attitude message
508  int hil_lpos_multi;
509  orb_publish_auto(ORB_ID(vehicle_local_position_groundtruth), &_lpos_pub, &hil_lpos, &hil_lpos_multi, ORB_PRIO_HIGH);
510  }
511 }
512 
513 void Simulator::handle_message_landing_target(const mavlink_message_t *msg)
514 {
515  mavlink_landing_target_t landing_target_mavlink;
516  mavlink_msg_landing_target_decode(msg, &landing_target_mavlink);
517 
518  struct irlock_report_s report = {};
519 
520  report.timestamp = hrt_absolute_time();
521  report.signature = landing_target_mavlink.target_num;
522  report.pos_x = landing_target_mavlink.angle_x;
523  report.pos_y = landing_target_mavlink.angle_y;
524  report.size_x = landing_target_mavlink.size_x;
525  report.size_y = landing_target_mavlink.size_y;
526 
527  int irlock_multi;
528  orb_publish_auto(ORB_ID(irlock_report), &_irlock_report_pub, &report, &irlock_multi, ORB_PRIO_HIGH);
529 }
530 
531 void Simulator::handle_message_odometry(const mavlink_message_t *msg)
532 {
533  publish_odometry_topic(msg);
534 }
535 
536 void Simulator::handle_message_optical_flow(const mavlink_message_t *msg)
537 {
538  mavlink_hil_optical_flow_t flow;
539  mavlink_msg_hil_optical_flow_decode(msg, &flow);
540  publish_flow_topic(&flow);
541 }
542 
543 void Simulator::handle_message_rc_channels(const mavlink_message_t *msg)
544 {
545  mavlink_rc_channels_t rc_channels;
546  mavlink_msg_rc_channels_decode(msg, &rc_channels);
547  fill_rc_input_msg(&_rc_input, &rc_channels);
548 
549  // publish message
550  int rc_multi;
551  orb_publish_auto(ORB_ID(input_rc), &_rc_channels_pub, &_rc_input, &rc_multi, ORB_PRIO_HIGH);
552 }
553 
555 {
556  publish_odometry_topic(msg);
557 }
558 
559 void Simulator::send_mavlink_message(const mavlink_message_t &aMsg)
560 {
561  uint8_t buf[MAVLINK_MAX_PACKET_LEN];
562  uint16_t bufLen = 0;
563 
564  bufLen = mavlink_msg_to_send_buffer(buf, &aMsg);
565 
566  ssize_t len;
567 
568  if (_ip == InternetProtocol::UDP) {
569  len = ::sendto(_fd, buf, bufLen, 0, (struct sockaddr *)&_srcaddr, sizeof(_srcaddr));
570 
571  } else {
572  len = ::send(_fd, buf, bufLen, 0);
573  }
574 
575  if (len <= 0) {
576  PX4_WARN("Failed sending mavlink message: %s", strerror(errno));
577  }
578 }
579 
581 {
582  // copy new actuator data if available
583  bool updated = false;
584 
585  orb_check(_vehicle_status_sub, &updated);
586 
587  if (updated) {
588  orb_copy(ORB_ID(vehicle_status), _vehicle_status_sub, &_vehicle_status);
589  }
590 }
591 
592 void *Simulator::sending_trampoline(void * /*unused*/)
593 {
594  _instance->send();
595  return nullptr;
596 }
597 
599 {
600 #ifdef __PX4_DARWIN
601  pthread_setname_np("sim_send");
602 #else
603  pthread_setname_np(pthread_self(), "sim_send");
604 #endif
605 
606  // Before starting, we ought to send a heartbeat to initiate the SITL
607  // simulator to start sending sensor data which will set the time and
608  // get everything rolling.
609  // Without this, we get stuck at px4_poll which waits for a time update.
610  send_heartbeat();
611 
612  px4_pollfd_struct_t fds[1] = {};
613  fds[0].fd = _actuator_outputs_sub;
614  fds[0].events = POLLIN;
615 
616  while (true) {
617  // Wait for up to 100ms for data.
618  int pret = px4_poll(&fds[0], (sizeof(fds) / sizeof(fds[0])), 100);
619 
620  if (pret == 0) {
621  // Timed out, try again.
622  continue;
623  }
624 
625  if (pret < 0) {
626  PX4_ERR("poll error %s", strerror(errno));
627  continue;
628  }
629 
630  if (fds[0].revents & POLLIN) {
631  // Got new data to read, update all topics.
632  parameters_update(false);
633  poll_topics();
634  send_controls();
635  }
636  }
637 }
638 
640 {
641  mavlink_command_long_t cmd_long = {};
642  mavlink_message_t message = {};
643  cmd_long.command = MAV_CMD_SET_MESSAGE_INTERVAL;
644  cmd_long.param1 = MAVLINK_MSG_ID_HIL_STATE_QUATERNION;
645  cmd_long.param2 = 5e3;
646  mavlink_msg_command_long_encode(_param_mav_sys_id.get(), _param_mav_comp_id.get(), &message, &cmd_long);
647  send_mavlink_message(message);
648 }
649 
651 {
652  mavlink_heartbeat_t hb = {};
653  mavlink_message_t message = {};
654  hb.autopilot = 12;
655  hb.base_mode |= (_vehicle_status.arming_state == vehicle_status_s::ARMING_STATE_ARMED) ? 128 : 0;
656  mavlink_msg_heartbeat_encode(_param_mav_sys_id.get(), _param_mav_comp_id.get(), &message, &hb);
657  send_mavlink_message(message);
658 }
659 
661 {
662 #ifdef __PX4_DARWIN
663  pthread_setname_np("sim_rcv");
664 #else
665  pthread_setname_np(pthread_self(), "sim_rcv");
666 #endif
667 
668  struct sockaddr_in _myaddr {};
669  _myaddr.sin_family = AF_INET;
670  _myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
671  _myaddr.sin_port = htons(_port);
672 
673  if (_ip == InternetProtocol::UDP) {
674 
675  if ((_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
676  PX4_ERR("Creating UDP socket failed: %s", strerror(errno));
677  return;
678  }
679 
680  if (bind(_fd, (struct sockaddr *)&_myaddr, sizeof(_myaddr)) < 0) {
681  PX4_ERR("bind for UDP port %i failed (%i)", _port, errno);
682  ::close(_fd);
683  return;
684  }
685 
686  PX4_INFO("Waiting for simulator to connect on UDP port %u", _port);
687 
688  while (true) {
689  // Once we receive something, we're most probably good and can carry on.
690  int len = ::recvfrom(_fd, _buf, sizeof(_buf), 0,
691  (struct sockaddr *)&_srcaddr, (socklen_t *)&_addrlen);
692 
693  if (len > 0) {
694  break;
695 
696  } else {
697  system_sleep(1);
698  }
699  }
700 
701  PX4_INFO("Simulator connected on UDP port %u.", _port);
702 
703  } else {
704 
705  PX4_INFO("Waiting for simulator to connect on TCP port %u", _port);
706 
707  while (true) {
708  if ((_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
709  PX4_ERR("Creating TCP socket failed: %s", strerror(errno));
710  return;
711  }
712 
713  int yes = 1;
714  int ret = setsockopt(_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &yes, sizeof(int));
715 
716  if (ret != 0) {
717  PX4_ERR("setsockopt failed: %s", strerror(errno));
718  }
719 
720  socklen_t myaddr_len = sizeof(_myaddr);
721  ret = connect(_fd, (struct sockaddr *)&_myaddr, myaddr_len);
722 
723  if (ret == 0) {
724  break;
725 
726  } else {
727  ::close(_fd);
728  system_sleep(1);
729  }
730  }
731 
732  PX4_INFO("Simulator connected on TCP port %u.", _port);
733 
734  }
735 
736  // Create a thread for sending data to the simulator.
737  pthread_t sender_thread;
738 
739  pthread_attr_t sender_thread_attr;
740  pthread_attr_init(&sender_thread_attr);
741  pthread_attr_setstacksize(&sender_thread_attr, PX4_STACK_ADJUSTED(4000));
742 
743  struct sched_param param;
744  (void)pthread_attr_getschedparam(&sender_thread_attr, &param);
745 
746  // sender thread should run immediately after new outputs are available
747  // to send the lockstep update to the simulation
748  param.sched_priority = SCHED_PRIORITY_ACTUATOR_OUTPUTS + 1;
749  (void)pthread_attr_setschedparam(&sender_thread_attr, &param);
750 
751  struct pollfd fds[2] = {};
752  unsigned fd_count = 1;
753  fds[0].fd = _fd;
754  fds[0].events = POLLIN;
755 
756 #ifdef ENABLE_UART_RC_INPUT
757  // setup serial connection to autopilot (used to get manual controls)
758  int serial_fd = openUart(PIXHAWK_DEVICE, PIXHAWK_DEVICE_BAUD);
759 
760  char serial_buf[1024];
761 
762  if (serial_fd >= 0) {
763  fds[1].fd = serial_fd;
764  fds[1].events = POLLIN;
765  fd_count++;
766 
767  PX4_INFO("Start using %s for radio control input.", PIXHAWK_DEVICE);
768 
769  } else {
770  PX4_INFO("Not using %s for radio control input. Assuming joystick input via MAVLink.", PIXHAWK_DEVICE);
771  }
772 
773 #endif
774 
775  // Subscribe to topics.
776  // Only subscribe to the first actuator_outputs to fill a single HIL_ACTUATOR_CONTROLS.
777  _actuator_outputs_sub = orb_subscribe_multi(ORB_ID(actuator_outputs), 0);
778  _vehicle_status_sub = orb_subscribe(ORB_ID(vehicle_status));
779 
780  // got data from simulator, now activate the sending thread
781  pthread_create(&sender_thread, &sender_thread_attr, Simulator::sending_trampoline, nullptr);
782  pthread_attr_destroy(&sender_thread_attr);
783 
784  mavlink_status_t mavlink_status = {};
785 
786  // Request HIL_STATE_QUATERNION for ground truth.
787  request_hil_state_quaternion();
788 
789  while (true) {
790 
791  // wait for new mavlink messages to arrive
792  int pret = ::poll(&fds[0], fd_count, 1000);
793 
794  if (pret == 0) {
795  // Timed out.
796  continue;
797  }
798 
799  if (pret < 0) {
800  PX4_ERR("poll error %d, %d", pret, errno);
801  continue;
802  }
803 
804  if (fds[0].revents & POLLIN) {
805 
806  int len = ::recvfrom(_fd, _buf, sizeof(_buf), 0, (struct sockaddr *)&_srcaddr, (socklen_t *)&_addrlen);
807 
808  if (len > 0) {
809  mavlink_message_t msg;
810 
811  for (int i = 0; i < len; i++) {
812  if (mavlink_parse_char(MAVLINK_COMM_0, _buf[i], &msg, &mavlink_status)) {
813  handle_message(&msg);
814  }
815  }
816  }
817  }
818 
819 #ifdef ENABLE_UART_RC_INPUT
820 
821  // got data from PIXHAWK
822  if (fd_count > 1 && fds[1].revents & POLLIN) {
823  int len = ::read(serial_fd, serial_buf, sizeof(serial_buf));
824 
825  if (len > 0) {
826  mavlink_message_t msg;
827 
828  mavlink_status_t serial_status = {};
829 
830  for (int i = 0; i < len; ++i) {
831  if (mavlink_parse_char(MAVLINK_COMM_1, serial_buf[i], &msg, &serial_status)) {
832  handle_message(&msg);
833  }
834  }
835  }
836  }
837 
838 #endif
839  }
840 
841  orb_unsubscribe(_actuator_outputs_sub);
842  orb_unsubscribe(_vehicle_status_sub);
843 }
844 
845 
846 #ifdef ENABLE_UART_RC_INPUT
847 int openUart(const char *uart_name, int baud)
848 {
849  /* process baud rate */
850  int speed;
851 
852  switch (baud) {
853  case 0: speed = B0; break;
854 
855  case 50: speed = B50; break;
856 
857  case 75: speed = B75; break;
858 
859  case 110: speed = B110; break;
860 
861  case 134: speed = B134; break;
862 
863  case 150: speed = B150; break;
864 
865  case 200: speed = B200; break;
866 
867  case 300: speed = B300; break;
868 
869  case 600: speed = B600; break;
870 
871  case 1200: speed = B1200; break;
872 
873  case 1800: speed = B1800; break;
874 
875  case 2400: speed = B2400; break;
876 
877  case 4800: speed = B4800; break;
878 
879  case 9600: speed = B9600; break;
880 
881  case 19200: speed = B19200; break;
882 
883  case 38400: speed = B38400; break;
884 
885  case 57600: speed = B57600; break;
886 
887  case 115200: speed = B115200; break;
888 
889  case 230400: speed = B230400; break;
890 
891  case 460800: speed = B460800; break;
892 
893  case 921600: speed = B921600; break;
894 
895  default:
896  PX4_ERR("Unsupported baudrate: %d", baud);
897  return -EINVAL;
898  }
899 
900  /* open uart */
901  int uart_fd = ::open(uart_name, O_RDWR | O_NOCTTY);
902 
903  if (uart_fd < 0) {
904  return uart_fd;
905  }
906 
907 
908  /* Try to set baud rate */
909  struct termios uart_config = {};
910 
911  int termios_state;
912 
913  /* Back up the original uart configuration to restore it after exit */
914  if ((termios_state = tcgetattr(uart_fd, &uart_config)) < 0) {
915  PX4_ERR("tcgetattr failed for %s: %s\n", uart_name, strerror(errno));
916  ::close(uart_fd);
917  return -1;
918  }
919 
920  /* Set baud rate */
921  if (cfsetispeed(&uart_config, speed) < 0 || cfsetospeed(&uart_config, speed) < 0) {
922  PX4_ERR("cfsetispeed or cfsetospeed failed for %s: %s\n", uart_name, strerror(errno));
923  ::close(uart_fd);
924  return -1;
925  }
926 
927  // Make raw
928  cfmakeraw(&uart_config);
929 
930  if ((termios_state = tcsetattr(uart_fd, TCSANOW, &uart_config)) < 0) {
931  PX4_ERR("tcsetattr failed for %s: %s\n", uart_name, strerror(errno));
932  ::close(uart_fd);
933  return -1;
934  }
935 
936  return uart_fd;
937 }
938 #endif
939 
940 int Simulator::publish_flow_topic(const mavlink_hil_optical_flow_t *flow_mavlink)
941 {
942  uint64_t timestamp = hrt_absolute_time();
943 
944  struct optical_flow_s flow = {};
945 
946  flow.sensor_id = flow_mavlink->sensor_id;
947  flow.timestamp = timestamp;
949  flow.frame_count_since_last_readout = 0; // ?
950  flow.integration_timespan = flow_mavlink->integration_time_us;
951 
952  flow.ground_distance_m = flow_mavlink->distance;
953  flow.gyro_temperature = flow_mavlink->temperature;
954  flow.gyro_x_rate_integral = flow_mavlink->integrated_xgyro;
955  flow.gyro_y_rate_integral = flow_mavlink->integrated_ygyro;
956  flow.gyro_z_rate_integral = flow_mavlink->integrated_zgyro;
957  flow.pixel_flow_x_integral = flow_mavlink->integrated_x;
958  flow.pixel_flow_y_integral = flow_mavlink->integrated_y;
959  flow.quality = flow_mavlink->quality;
960 
961  /* fill in sensor limits */
962  float flow_rate_max;
963  param_get(param_find("SENS_FLOW_MAXR"), &flow_rate_max);
964  float flow_min_hgt;
965  param_get(param_find("SENS_FLOW_MINHGT"), &flow_min_hgt);
966  float flow_max_hgt;
967  param_get(param_find("SENS_FLOW_MAXHGT"), &flow_max_hgt);
968 
969  flow.max_flow_rate = flow_rate_max;
970  flow.min_ground_distance = flow_min_hgt;
971  flow.max_ground_distance = flow_max_hgt;
972 
973  /* rotate measurements according to parameter */
974  int32_t flow_rot_int;
975  param_get(param_find("SENS_FLOW_ROT"), &flow_rot_int);
976  const enum Rotation flow_rot = (Rotation)flow_rot_int;
977 
978  float zeroval = 0.0f;
979  rotate_3f(flow_rot, flow.pixel_flow_x_integral, flow.pixel_flow_y_integral, zeroval);
981 
982  int flow_multi;
983  orb_publish_auto(ORB_ID(optical_flow), &_flow_pub, &flow, &flow_multi, ORB_PRIO_HIGH);
984 
985  return OK;
986 }
987 
988 int Simulator::publish_odometry_topic(const mavlink_message_t *odom_mavlink)
989 {
990  uint64_t timestamp = hrt_absolute_time();
991 
992  struct vehicle_odometry_s odom;
993 
994  odom.timestamp = timestamp;
995 
996  const size_t POS_URT_SIZE = sizeof(odom.pose_covariance) / sizeof(odom.pose_covariance[0]);
997 
998  if (odom_mavlink->msgid == MAVLINK_MSG_ID_ODOMETRY) {
999  mavlink_odometry_t odom_msg;
1000  mavlink_msg_odometry_decode(odom_mavlink, &odom_msg);
1001 
1002  /* Dcm rotation matrix from body frame to local NED frame */
1003  matrix::Dcm<float> Rbl;
1004 
1005  /* since odom.child_frame_id == MAV_FRAME_BODY_FRD, WRT to estimated vehicle body-fixed frame */
1006  /* get quaternion from the msg quaternion itself and build DCM matrix from it */
1007  /* No need to transform the covariance matrices since the non-diagonal values are all zero */
1008  Rbl = matrix::Dcm<float>(matrix::Quatf(odom_msg.q)).I();
1009 
1010  /* the linear velocities needs to be transformed to the local NED frame */
1011  matrix::Vector3<float> linvel_local(Rbl * matrix::Vector3<float>(odom_msg.vx, odom_msg.vy, odom_msg.vz));
1012 
1013  /* The position in the local NED frame */
1014  odom.x = odom_msg.x;
1015  odom.y = odom_msg.y;
1016  odom.z = odom_msg.z;
1017  /* The quaternion of the ODOMETRY msg represents a rotation from
1018  * NED earth/local frame to XYZ body frame */
1019  matrix::Quatf q(odom_msg.q[0], odom_msg.q[1], odom_msg.q[2], odom_msg.q[3]);
1020  q.copyTo(odom.q);
1021 
1022  odom.local_frame = odom.LOCAL_FRAME_NED;
1023 
1024  static_assert(POS_URT_SIZE == (sizeof(odom_msg.pose_covariance) / sizeof(odom_msg.pose_covariance[0])),
1025  "Odometry Pose Covariance matrix URT array size mismatch");
1026 
1027  /* The pose covariance URT */
1028  for (size_t i = 0; i < POS_URT_SIZE; i++) {
1029  odom.pose_covariance[i] = odom_msg.pose_covariance[i];
1030  }
1031 
1032  /* The velocity in the local NED frame */
1033  odom.vx = linvel_local(0);
1034  odom.vy = linvel_local(1);
1035  odom.vz = linvel_local(2);
1036  /* The angular velocity in the body-fixed frame */
1037  odom.rollspeed = odom_msg.rollspeed;
1038  odom.pitchspeed = odom_msg.pitchspeed;
1039  odom.yawspeed = odom_msg.yawspeed;
1040 
1041  // velocity_covariance
1042  static constexpr size_t VEL_URT_SIZE = sizeof(odom.velocity_covariance) / sizeof(odom.velocity_covariance[0]);
1043  static_assert(VEL_URT_SIZE == (sizeof(odom_msg.velocity_covariance) / sizeof(odom_msg.velocity_covariance[0])),
1044  "Odometry Velocity Covariance matrix URT array size mismatch");
1045 
1046  /* The velocity covariance URT */
1047  for (size_t i = 0; i < VEL_URT_SIZE; i++) {
1048  odom.velocity_covariance[i] = odom_msg.velocity_covariance[i];
1049  }
1050 
1051  } else if (odom_mavlink->msgid == MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE) {
1052  mavlink_vision_position_estimate_t ev;
1053  mavlink_msg_vision_position_estimate_decode(odom_mavlink, &ev);
1054  /* The position in the local NED frame */
1055  odom.x = ev.x;
1056  odom.y = ev.y;
1057  odom.z = ev.z;
1058  /* The euler angles of the VISUAL_POSITION_ESTIMATE msg represent a
1059  * rotation from NED earth/local frame to XYZ body frame */
1060  matrix::Quatf q(matrix::Eulerf(ev.roll, ev.pitch, ev.yaw));
1061  q.copyTo(odom.q);
1062 
1063  odom.local_frame = odom.LOCAL_FRAME_NED;
1064 
1065  static_assert(POS_URT_SIZE == (sizeof(ev.covariance) / sizeof(ev.covariance[0])),
1066  "Vision Position Estimate Pose Covariance matrix URT array size mismatch");
1067 
1068  /* The pose covariance URT */
1069  for (size_t i = 0; i < POS_URT_SIZE; i++) {
1070  odom.pose_covariance[i] = ev.covariance[i];
1071  }
1072 
1073  /* The velocity in the local NED frame - unknown */
1074  odom.vx = NAN;
1075  odom.vy = NAN;
1076  odom.vz = NAN;
1077  /* The angular velocity in body-fixed frame - unknown */
1078  odom.rollspeed = NAN;
1079  odom.pitchspeed = NAN;
1080  odom.yawspeed = NAN;
1081 
1082  /* The velocity covariance URT - unknown */
1083  odom.velocity_covariance[0] = NAN;
1084 
1085  }
1086 
1087  int instance_id = 0;
1088 
1089  /** @note: frame_id == MAV_FRAME_VISION_NED) */
1090  orb_publish_auto(ORB_ID(vehicle_visual_odometry), &_visual_odometry_pub, &odom, &instance_id, ORB_PRIO_HIGH);
1091 
1092  return OK;
1093 }
1094 
1095 int Simulator::publish_distance_topic(const mavlink_distance_sensor_t *dist_mavlink)
1096 {
1097  uint64_t timestamp = hrt_absolute_time();
1098 
1099  struct distance_sensor_s dist = {};
1100 
1101  dist.timestamp = timestamp;
1102  dist.min_distance = dist_mavlink->min_distance / 100.0f;
1103  dist.max_distance = dist_mavlink->max_distance / 100.0f;
1104  dist.current_distance = dist_mavlink->current_distance / 100.0f;
1105  dist.type = dist_mavlink->type;
1106  dist.id = dist_mavlink->id;
1107  dist.orientation = dist_mavlink->orientation;
1108  dist.variance = dist_mavlink->covariance * 1e-4f; // cm^2 to m^2
1109  dist.signal_quality = -1;
1110 
1111  dist.h_fov = dist_mavlink->horizontal_fov;
1112  dist.v_fov = dist_mavlink->vertical_fov;
1113  dist.q[0] = dist_mavlink->quaternion[0];
1114  dist.q[1] = dist_mavlink->quaternion[1];
1115  dist.q[2] = dist_mavlink->quaternion[2];
1116  dist.q[3] = dist_mavlink->quaternion[3];
1117 
1118  int dist_multi;
1119  orb_publish_auto(ORB_ID(distance_sensor), &_dist_pub, &dist, &dist_multi, ORB_PRIO_HIGH);
1120 
1121  return OK;
1122 }
#define PWM_DEFAULT_MAX
Default maximum PWM in us.
void handle_message_distance_sensor(const mavlink_message_t *msg)
void handle_message_rc_channels(const mavlink_message_t *msg)
int16_t gyro_temperature
Definition: optical_flow.h:66
int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
Definition: uORB.cpp:90
void handle_message_landing_target(const mavlink_message_t *msg)
float gyro_x_rate_integral
Definition: optical_flow.h:56
int32_t rssi
Definition: input_rc.h:72
__EXPORT int param_get(param_t param, void *val)
Copy the value of a parameter.
Definition: parameters.cpp:589
Definition of geo / math functions to perform geodesic calculations.
uint64_t timestamp
Definition: optical_flow.h:53
void handle_message_optical_flow(const mavlink_message_t *msg)
void handle_message(const mavlink_message_t *msg)
float pixel_flow_y_integral
Definition: optical_flow.h:55
void handle_message_hil_gps(const mavlink_message_t *msg)
void send_mavlink_message(const mavlink_message_t &aMsg)
float max_flow_rate
Definition: optical_flow.h:62
__EXPORT void rotate_3f(enum Rotation rot, float &x, float &y, float &z)
rotate a 3 element float vector in-place
Definition: rotation.cpp:63
#define system_sleep
Definition: visibility.h:109
void * send(void *data)
void handle_message_hil_sensor(const mavlink_message_t *msg)
This module interfaces via MAVLink to a software in the loop simulator (SITL) such as jMAVSim or Gaze...
int px4_poll(px4_pollfd_struct_t *fds, nfds_t nfds, int timeout)
uint16_t frame_count_since_last_readout
Definition: optical_flow.h:65
float min_ground_distance
Definition: optical_flow.h:63
float pixel_flow_x_integral
Definition: optical_flow.h:54
void handle_message_hil_state_quaternion(const mavlink_message_t *msg)
uint64_t timestamp
Definition: input_rc.h:69
LidarLite * instance
Definition: ll40ls.cpp:65
float ground_distance_m
Definition: optical_flow.h:59
void copyTo(Type dst[M *N]) const
Definition: Matrix.hpp:115
uint32_t time_since_last_sonar_update
Definition: optical_flow.h:61
Vector rotation library.
Quaternion class.
Definition: Dcm.hpp:24
float velocity_covariance[21]
Type psi() const
Definition: Euler.hpp:136
void handle_message_vision_position_estimate(const mavlink_message_t *msg)
const T gradual(const T &value, const T &x_low, const T &x_high, const T &y_low, const T &y_high)
Definition: Functions.hpp:139
uint8_t satellites_visible
Definition: simulator.h:93
static char msg[NUM_MSG][CONFIG_USART1_TXBUFSIZE]
Definition: px4io.c:89
float max_ground_distance
Definition: optical_flow.h:64
static void read(bootloader_app_shared_t *pshared)
int orb_subscribe(const struct orb_metadata *meta)
Definition: uORB.cpp:75
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
void request_hil_state_quaternion()
uint16_t signature
Definition: irlock_report.h:58
static void parameters_update()
update all parameters
uint16_t values[18]
Definition: input_rc.h:76
Rotation
Enum for board and external compass rotations.
Definition: rotation.h:51
uint32_t channel_count
Definition: input_rc.h:71
int orb_unsubscribe(int handle)
Definition: uORB.cpp:85
static struct actuator_armed_s armed
Definition: Commander.cpp:139
int publish_distance_topic(const mavlink_distance_sensor_t *dist)
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
static hrt_abstime hrt_elapsed_time(const hrt_abstime *then)
Compute the delta between a timestamp taken in the past and now.
Definition: drv_hrt.h:102
void handle_message_odometry(const mavlink_message_t *msg)
Euler angles class.
Definition: AxisAngle.hpp:18
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
uint64_t timestamp
Definition: irlock_report.h:53
void poll_for_MAVLink_messages()
__EXPORT param_t param_find(const char *name)
Look up a parameter by name.
Definition: parameters.cpp:370
constexpr _Tp max(_Tp a, _Tp b)
Definition: Limits.hpp:60
void update_gps(const mavlink_hil_gps_t *gps_sim)
Quaternion< float > Quatf
Definition: Quaternion.hpp:544
int map_projection_project(const struct map_projection_reference_s *ref, double lat, double lon, float *x, float *y)
Definition: geo.cpp:132
int orb_check(int handle, bool *updated)
Definition: uORB.cpp:95
int orb_subscribe_multi(const struct orb_metadata *meta, unsigned instance)
Definition: uORB.cpp:80
uint32_t integration_timespan
Definition: optical_flow.h:60
mavlink_hil_actuator_controls_t actuator_controls_from_outputs(const actuator_outputs_s &actuators)
__EXPORT void abstime_to_ts(struct timespec *ts, hrt_abstime abstime)
Convert absolute time to a timespec.
#define OK
Definition: uavcan_main.cpp:71
uint8_t sensor_id
Definition: optical_flow.h:67
int publish_odometry_topic(const mavlink_message_t *odom_mavlink)
float gyro_z_rate_integral
Definition: optical_flow.h:58
float gyro_y_rate_integral
Definition: optical_flow.h:57
int map_projection_init(struct map_projection_reference_s *ref, double lat_0, double lon_0)
Initializes the map transformation given by the argument and sets the timestamp to now...
Definition: geo.cpp:105
#define PWM_DEFAULT_MIN
Default minimum PWM in us.
int publish_flow_topic(const mavlink_hil_optical_flow_t *flow)
11 bits per channel * 16 channels = 22 bytes.
uint64_t timestamp_last_signal
Definition: input_rc.h:70
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
static int orb_publish_auto(const struct orb_metadata *meta, orb_advert_t *handle, const void *data, int *instance, int priority)
Advertise as the publisher of a topic.
Definition: uORB.h:177
static void * sending_trampoline(void *)
void update_sensors(const hrt_abstime &time, const mavlink_hil_sensor_t &imu)
uint8_t quality
Definition: optical_flow.h:68