INSTINCT Code Coverage Report


Directory: src/
File: util/Vendor/MavLink/autopilot_interface.cpp
Date: 2025-02-07 16:54:41
Exec Total Coverage
Lines: 0 335 0.0%
Functions: 0 33 0.0%
Branches: 0 205 0.0%

Line Branch Exec Source
1 /****************************************************************************
2 *
3 * Copyright (c) 2014 MAVlink Development Team. All rights reserved.
4 * Author: Trent Lukaczyk, <aerialhedgehog@gmail.com>
5 * Jaycee Lock, <jaycee.lock@gmail.com>
6 * Lorenz Meier, <lm@inf.ethz.ch>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name PX4 nor the names of its contributors may be
19 * used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 ****************************************************************************/
36
37 /**
38 * @file autopilot_interface.cpp
39 *
40 * @brief Autopilot interface functions
41 *
42 * Functions for sending and recieving commands to an autopilot via MAVlink
43 *
44 * @author Trent Lukaczyk, <aerialhedgehog@gmail.com>
45 * @author Jaycee Lock, <jaycee.lock@gmail.com>
46 * @author Lorenz Meier, <lm@inf.ethz.ch>
47 *
48 */
49
50 // ------------------------------------------------------------------------------
51 // Includes
52 // ------------------------------------------------------------------------------
53
54 #if __linux__ || __APPLE__
55 #include <optional>
56
57 #include "autopilot_interface.hpp"
58 #include "util/Logger.hpp"
59
60 // ----------------------------------------------------------------------------------
61 // Time
62 // ----------------------------------------------------------------------------------
63 uint64_t get_time_usec()
64 {
65 static struct timeval _time_stamp;
66 gettimeofday(&_time_stamp, nullptr);
67 return static_cast<uint64_t>(_time_stamp.tv_sec) * 1000000UL + static_cast<uint64_t>(_time_stamp.tv_usec);
68 }
69
70 // ----------------------------------------------------------------------------------
71 // Setpoint Helper Functions
72 // ----------------------------------------------------------------------------------
73
74 // choose one of the next three
75
76 /*
77 * Set target local ned position
78 *
79 * Modifies a mavlink_set_position_target_local_ned_t struct with target XYZ locations
80 * in the Local NED frame, in meters.
81 */
82 void set_position(float x, float y, float z, mavlink_set_position_target_local_ned_t& sp)
83 {
84 sp.type_mask =
85 MAVLINK_MSG_SET_POSITION_TARGET_LOCAL_NED_POSITION;
86
87 sp.coordinate_frame = MAV_FRAME_LOCAL_NED;
88
89 sp.x = x;
90 sp.y = y;
91 sp.z = z;
92
93 LOG_INFO("autopilot_interface.cpp - POSITION SETPOINT XYZ = [ {} , {} , {} ] \n", sp.x, sp.y, sp.z);
94 }
95
96 /*
97 * Set target local ned velocity
98 *
99 * Modifies a mavlink_set_position_target_local_ned_t struct with target VX VY VZ
100 * velocities in the Local NED frame, in meters per second.
101 */
102 void set_velocity(float vx, float vy, float vz, mavlink_set_position_target_local_ned_t& sp)
103 {
104 sp.type_mask =
105 MAVLINK_MSG_SET_POSITION_TARGET_LOCAL_NED_VELOCITY;
106
107 sp.coordinate_frame = MAV_FRAME_LOCAL_NED;
108
109 sp.vx = vx;
110 sp.vy = vy;
111 sp.vz = vz;
112
113 LOG_INFO("autopilot_interface.cpp - VELOCITY SETPOINT UVW = [ {} , {} , {} ] \n", sp.vx, sp.vy, sp.vz);
114 }
115
116 /*
117 * Set target local ned acceleration
118 *
119 * Modifies a mavlink_set_position_target_local_ned_t struct with target AX AY AZ
120 * accelerations in the Local NED frame, in meters per second squared.
121 */
122 void set_acceleration(float /* ax */, float /* ay */, float /* az */, mavlink_set_position_target_local_ned_t& /* sp */)
123 {
124 // NOT IMPLEMENTED
125 LOG_ERROR("autopilot_interface.cpp - set_acceleration doesn't work yet \n");
126
127 // sp.type_mask =
128 // MAVLINK_MSG_SET_POSITION_TARGET_LOCAL_NED_ACCELERATION & MAVLINK_MSG_SET_POSITION_TARGET_LOCAL_NED_VELOCITY;
129
130 // sp.coordinate_frame = MAV_FRAME_LOCAL_NED;
131
132 // sp.afx = ax;
133 // sp.afy = ay;
134 // sp.afz = az;
135 }
136
137 // the next two need to be called after one of the above
138
139 /*
140 * Set target local ned yaw
141 *
142 * Modifies a mavlink_set_position_target_local_ned_t struct with a target yaw
143 * in the Local NED frame, in radians.
144 */
145 void set_yaw(float yaw, mavlink_set_position_target_local_ned_t& sp)
146 {
147 sp.type_mask &=
148 MAVLINK_MSG_SET_POSITION_TARGET_LOCAL_NED_YAW_ANGLE;
149
150 sp.yaw = yaw;
151
152 LOG_INFO("autopilot_interface.cpp - POSITION SETPOINT YAW = {} \n", sp.yaw);
153 }
154
155 /*
156 * Set target local ned yaw rate
157 *
158 * Modifies a mavlink_set_position_target_local_ned_t struct with a target yaw rate
159 * in the Local NED frame, in radians per second.
160 */
161 void set_yaw_rate(float yaw_rate, mavlink_set_position_target_local_ned_t& sp)
162 {
163 sp.type_mask &=
164 MAVLINK_MSG_SET_POSITION_TARGET_LOCAL_NED_YAW_RATE;
165
166 sp.yaw_rate = yaw_rate;
167 }
168
169 // ----------------------------------------------------------------------------------
170 // Autopilot Interface Class
171 // ----------------------------------------------------------------------------------
172
173 // ------------------------------------------------------------------------------
174 // Con/De structors
175 // ------------------------------------------------------------------------------
176 Autopilot_Interface::Autopilot_Interface(const std::shared_ptr<Generic_Port>& port_) : port(port_)
177 {
178 current_messages.sysid = system_id;
179 current_messages.compid = autopilot_id;
180 }
181
182 // ------------------------------------------------------------------------------
183 // Set Port
184 // ------------------------------------------------------------------------------
185 void Autopilot_Interface::setPort(const std::shared_ptr<Generic_Port>& port_new)
186 {
187 port = port_new;
188 }
189
190 // ------------------------------------------------------------------------------
191 // Update Setpoint
192 // ------------------------------------------------------------------------------
193 void Autopilot_Interface::update_setpoint(mavlink_set_position_target_local_ned_t setpoint)
194 {
195 std::lock_guard<std::mutex> lock(current_setpoint.mutex);
196 current_setpoint.data = setpoint;
197 }
198
199 // ------------------------------------------------------------------------------
200 // Read Messages
201 // ------------------------------------------------------------------------------
202 void Autopilot_Interface::read_messages()
203 {
204 bool success = false; // receive success flag
205 bool received_all = false; // receive only one message
206 Time_Stamps this_timestamps;
207
208 // Blocking wait for new data
209 while (!received_all and !time_to_exit)
210 {
211 // ----------------------------------------------------------------------
212 // READ MESSAGE
213 // ----------------------------------------------------------------------
214 mavlink_message_t message;
215 success = port->read_message(message);
216
217 // ----------------------------------------------------------------------
218 // HANDLE MESSAGE
219 // ----------------------------------------------------------------------
220 if (success)
221 {
222 // Store message sysid and compid.
223 // Note this doesn't handle multiple message sources.
224 current_messages.sysid = message.sysid;
225 current_messages.compid = message.compid;
226
227 // Handle Message ID
228 switch (message.msgid)
229 {
230 case MAVLINK_MSG_ID_HEARTBEAT:
231 {
232 // LOG_INFO("autopilot_interface.cpp - MAVLINK_MSG_ID_HEARTBEAT\n");
233 mavlink_msg_heartbeat_decode(&message, &(current_messages.heartbeat));
234 current_messages.time_stamps.heartbeat = get_time_usec();
235 this_timestamps.heartbeat = current_messages.time_stamps.heartbeat;
236 break;
237 }
238
239 case MAVLINK_MSG_ID_SYS_STATUS:
240 {
241 // LOG_INFO("autopilot_interface.cpp - MAVLINK_MSG_ID_SYS_STATUS\n");
242 mavlink_msg_sys_status_decode(&message, &(current_messages.sys_status));
243 current_messages.time_stamps.sys_status = get_time_usec();
244 this_timestamps.sys_status = current_messages.time_stamps.sys_status;
245 break;
246 }
247
248 case MAVLINK_MSG_ID_BATTERY_STATUS:
249 {
250 // LOG_INFO("autopilot_interface.cpp - MAVLINK_MSG_ID_BATTERY_STATUS\n");
251 mavlink_msg_battery_status_decode(&message, &(current_messages.battery_status));
252 current_messages.time_stamps.battery_status = get_time_usec();
253 this_timestamps.battery_status = current_messages.time_stamps.battery_status;
254 break;
255 }
256
257 case MAVLINK_MSG_ID_RADIO_STATUS:
258 {
259 // LOG_INFO("autopilot_interface.cpp - MAVLINK_MSG_ID_RADIO_STATUS\n");
260 mavlink_msg_radio_status_decode(&message, &(current_messages.radio_status));
261 current_messages.time_stamps.radio_status = get_time_usec();
262 this_timestamps.radio_status = current_messages.time_stamps.radio_status;
263 break;
264 }
265
266 case MAVLINK_MSG_ID_LOCAL_POSITION_NED:
267 {
268 // LOG_INFO("autopilot_interface.cpp - MAVLINK_MSG_ID_LOCAL_POSITION_NED\n");
269 mavlink_msg_local_position_ned_decode(&message, &(current_messages.local_position_ned));
270 current_messages.time_stamps.local_position_ned = get_time_usec();
271 this_timestamps.local_position_ned = current_messages.time_stamps.local_position_ned;
272 break;
273 }
274
275 case MAVLINK_MSG_ID_GLOBAL_POSITION_INT:
276 {
277 // LOG_INFO("autopilot_interface.cpp - MAVLINK_MSG_ID_GLOBAL_POSITION_INT\n");
278 mavlink_msg_global_position_int_decode(&message, &(current_messages.global_position_int));
279 current_messages.time_stamps.global_position_int = get_time_usec();
280 this_timestamps.global_position_int = current_messages.time_stamps.global_position_int;
281 break;
282 }
283
284 case MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED:
285 {
286 // LOG_INFO("autopilot_interface.cpp - MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED\n");
287 mavlink_msg_position_target_local_ned_decode(&message, &(current_messages.position_target_local_ned));
288 current_messages.time_stamps.position_target_local_ned = get_time_usec();
289 this_timestamps.position_target_local_ned = current_messages.time_stamps.position_target_local_ned;
290 break;
291 }
292
293 case MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT:
294 {
295 // LOG_INFO("autopilot_interface.cpp - MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT\n");
296 mavlink_msg_position_target_global_int_decode(&message, &(current_messages.position_target_global_int));
297 current_messages.time_stamps.position_target_global_int = get_time_usec();
298 this_timestamps.position_target_global_int = current_messages.time_stamps.position_target_global_int;
299 break;
300 }
301
302 case MAVLINK_MSG_ID_HIGHRES_IMU:
303 {
304 // LOG_INFO("autopilot_interface.cpp - MAVLINK_MSG_ID_HIGHRES_IMU\n");
305 mavlink_msg_highres_imu_decode(&message, &(current_messages.highres_imu));
306 current_messages.time_stamps.highres_imu = get_time_usec();
307 this_timestamps.highres_imu = current_messages.time_stamps.highres_imu;
308 break;
309 }
310
311 case MAVLINK_MSG_ID_ATTITUDE:
312 {
313 // LOG_INFO("autopilot_interface.cpp - MAVLINK_MSG_ID_ATTITUDE\n");
314 mavlink_msg_attitude_decode(&message, &(current_messages.attitude));
315 current_messages.time_stamps.attitude = get_time_usec();
316 this_timestamps.attitude = current_messages.time_stamps.attitude;
317 break;
318 }
319
320 default:
321 {
322 // LOG_WARN("Warning, did not handle message id %i\n",message.msgid);
323 break;
324 }
325
326 } // end: switch msgid
327
328 } // end: if read message
329
330 // Check for receipt of all items
331 received_all =
332 this_timestamps.heartbeat &&
333 // this_timestamps.battery_status &&
334 // this_timestamps.radio_status &&
335 // this_timestamps.local_position_ned &&
336 // this_timestamps.global_position_int &&
337 // this_timestamps.position_target_local_ned &&
338 // this_timestamps.position_target_global_int &&
339 // this_timestamps.highres_imu &&
340 // this_timestamps.attitude &&
341 this_timestamps.sys_status;
342
343 // give the write thread time to use the port
344 if (writing_status > false)
345 {
346 usleep(100); // look for components of batches at 10kHz
347 }
348
349 } // end: while not received all
350 }
351
352 // ------------------------------------------------------------------------------
353 // Write Message
354 // ------------------------------------------------------------------------------
355 int Autopilot_Interface::write_message(mavlink_message_t message)
356 {
357 // do the write
358 int len = port->write_message(message);
359
360 // book keep
361 write_count++;
362
363 // Done!
364 return len;
365 }
366
367 // ------------------------------------------------------------------------------
368 // Write Setpoint Message
369 // ------------------------------------------------------------------------------
370 void Autopilot_Interface::write_setpoint()
371 {
372 // --------------------------------------------------------------------------
373 // PACK PAYLOAD
374 // --------------------------------------------------------------------------
375
376 // pull from position target
377 mavlink_set_position_target_local_ned_t sp;
378 {
379 std::lock_guard<std::mutex> lock(current_setpoint.mutex);
380 sp = current_setpoint.data;
381 }
382
383 // double check some system parameters
384
385 if (!sp.time_boot_ms)
386 {
387 sp.time_boot_ms = static_cast<uint32_t>(get_time_usec() / 1000);
388 }
389 sp.target_system = static_cast<uint8_t>(system_id);
390 sp.target_component = static_cast<uint8_t>(autopilot_id);
391
392 // --------------------------------------------------------------------------
393 // ENCODE
394 // --------------------------------------------------------------------------
395
396 mavlink_message_t message;
397 mavlink_msg_set_position_target_local_ned_encode(static_cast<uint8_t>(system_id), static_cast<uint8_t>(companion_id), &message, &sp);
398
399 // --------------------------------------------------------------------------
400 // WRITE
401 // --------------------------------------------------------------------------
402
403 // do the write
404 int len = write_message(message);
405
406 // check the write
407 if (len <= 0)
408 {
409 LOG_WARN("autopilot_interface.cpp - could not send POSITION_TARGET_LOCAL_NED \n");
410 }
411 // else
412 // LOG_INFO("autopilot_interface.cpp - {} POSITION_TARGET = [ {} , {} , {} ] \n", write_count, position_target.x, position_target.y, position_target.z);
413 }
414
415 // ------------------------------------------------------------------------------
416 // Start Off-Board Mode
417 // ------------------------------------------------------------------------------
418 void Autopilot_Interface::enable_offboard_control()
419 {
420 // Should only send this command once
421 if (!static_cast<bool>(control_status))
422 {
423 LOG_INFO("autopilot_interface.cpp - ENABLE OFFBOARD MODE\n");
424
425 // ----------------------------------------------------------------------
426 // TOGGLE OFF-BOARD MODE
427 // ----------------------------------------------------------------------
428
429 // Sends the command to go off-board
430 int success = toggle_offboard_control(true);
431
432 // Check the command was written
433 if (success)
434 {
435 control_status = true;
436 }
437 else
438 {
439 LOG_ERROR("autopilot_interface.cpp - off-board mode not set, could not write message\n");
440 return;
441 }
442
443 } // end: if not offboard_status
444 }
445
446 // ------------------------------------------------------------------------------
447 // Stop Off-Board Mode
448 // ------------------------------------------------------------------------------
449 void Autopilot_Interface::disable_offboard_control()
450 {
451 // Should only send this command once
452 if (static_cast<bool>(control_status))
453 {
454 LOG_INFO("autopilot_interface.cpp - DISABLE OFFBOARD MODE\n");
455
456 // ----------------------------------------------------------------------
457 // TOGGLE OFF-BOARD MODE
458 // ----------------------------------------------------------------------
459
460 // Sends the command to stop off-board
461 int success = toggle_offboard_control(false);
462
463 // Check the command was written
464 if (success)
465 {
466 control_status = false;
467 }
468 else
469 {
470 LOG_ERROR("autopilot_interface.cpp - off-board mode not set, could not write message\n");
471 return;
472 }
473
474 } // end: if offboard_status
475 }
476
477 // ------------------------------------------------------------------------------
478 // Arm
479 // ------------------------------------------------------------------------------
480 int Autopilot_Interface::arm_disarm(bool flag)
481 {
482 if (flag)
483 {
484 LOG_INFO("autopilot_interface.cpp - ARM ROTORS\n");
485 }
486 else
487 {
488 LOG_INFO("autopilot_interface.cpp - DISARM ROTORS\n");
489 }
490
491 // Prepare command for off-board mode
492 mavlink_command_long_t com = { 0, NAN, NAN, NAN, NAN, NAN, NAN, 0, 0, 0, 0 }; // FIXME: init values could be wrong here, but have to be set
493 com.target_system = static_cast<uint8_t>(system_id);
494 com.target_component = static_cast<uint8_t>(autopilot_id);
495 com.command = MAV_CMD_COMPONENT_ARM_DISARM;
496 com.confirmation = true;
497 com.param1 = static_cast<float>(flag);
498 com.param2 = 21196.;
499
500 // Encode
501 mavlink_message_t message;
502 mavlink_msg_command_long_encode(static_cast<uint8_t>(system_id), static_cast<uint8_t>(companion_id), &message, &com);
503
504 // Send the message
505 int len = port->write_message(message);
506
507 // Done!
508 return len;
509 }
510
511 // ------------------------------------------------------------------------------
512 // Toggle Off-Board Mode
513 // ------------------------------------------------------------------------------
514 int Autopilot_Interface::toggle_offboard_control(bool flag)
515 {
516 // Prepare command for off-board mode
517 mavlink_command_long_t com = { 0, NAN, NAN, NAN, NAN, NAN, NAN, 0, 0, 0, 0 }; // FIXME: init values could be wrong here, but have to be set
518 com.target_system = static_cast<uint8_t>(system_id);
519 com.target_component = static_cast<uint8_t>(autopilot_id);
520 com.command = MAV_CMD_NAV_GUIDED_ENABLE;
521 com.confirmation = true;
522 com.param1 = static_cast<float>(flag); // flag >0.5 => start, <0.5 => stop
523
524 // Encode
525 mavlink_message_t message;
526 mavlink_msg_command_long_encode(static_cast<uint8_t>(system_id), static_cast<uint8_t>(companion_id), &message, &com);
527
528 // Send the message
529 int len = port->write_message(message);
530
531 // Done!
532 return len;
533 }
534
535 // ------------------------------------------------------------------------------
536 // MOCAP_Input (ATT_POS_MOCAP (#138))
537 // ------------------------------------------------------------------------------
538 int Autopilot_Interface::MOCAP_Input(float w, float x, float y, float z)
539 {
540 mavlink_att_pos_mocap_t current_MOCAP{};
541
542 current_MOCAP.time_usec = get_time_usec();
543 current_MOCAP.q[0] = w; // Attitude quaternion W
544 current_MOCAP.q[1] = x; // Attitude quaternion X
545 current_MOCAP.q[2] = y; // Attitude quaternion Y
546 current_MOCAP.q[3] = z; // Attitude quaternion Z
547 current_MOCAP.x = 0; // X position (NED) (m)
548 current_MOCAP.y = 0; // Y position (NED) (m)
549 current_MOCAP.z = 0; // Z position (NED) (m)
550
551 current_MOCAP.covariance[0] = { std::nanf("1") };
552 /*
553 current_MOCAP.covariance[1] = 0;
554 current_MOCAP.covariance[2] = 0;
555 current_MOCAP.covariance[3] = 0;
556 current_MOCAP.covariance[4] = 0;
557 current_MOCAP.covariance[5] = 0;
558
559 current_MOCAP.covariance[6] = 0;
560 current_MOCAP.covariance[7] = 0;
561 current_MOCAP.covariance[8] = 0;
562 current_MOCAP.covariance[9] = 0;
563 current_MOCAP.covariance[10] = 0;
564 current_MOCAP.covariance[11] = 0;
565 current_MOCAP.covariance[12] = 0;
566 current_MOCAP.covariance[13] = 0;
567 current_MOCAP.covariance[14] = 0;
568 current_MOCAP.covariance[15] = 0;
569 current_MOCAP.covariance[16] = 0;
570 current_MOCAP.covariance[17] = 0;
571 current_MOCAP.covariance[18] = 0;
572 current_MOCAP.covariance[19] = 0;
573 current_MOCAP.covariance[20] = 0;
574 */
575
576 // Encode
577 mavlink_message_t message;
578 mavlink_msg_att_pos_mocap_encode(static_cast<uint8_t>(system_id), static_cast<uint8_t>(companion_id), &message, &current_MOCAP); // NOLINT(clang-analyzer-core.CallAndMessage)
579
580 // Send the message
581 int len = port->write_message(message);
582
583 // Done!
584 return len;
585 }
586
587 // ------------------------------------------------------------------------------
588 // GPS_Input (GPS_INPUT (#232))
589 // ------------------------------------------------------------------------------
590
591 int Autopilot_Interface::GPS_Input(int32_t lat_d, int32_t lon_d, float alt, float vn, float ve, float vd, uint32_t time_week_ms, uint16_t time_week)
592 {
593 mavlink_gps_input_t GPS;
594 GPS.time_usec = get_time_usec();
595 GPS.gps_id = 0;
596 GPS.ignore_flags = GPS_INPUT_IGNORE_FLAG_HDOP | GPS_INPUT_IGNORE_FLAG_VDOP |
597 // GPS_INPUT_IGNORE_FLAG_VEL_HORIZ |
598 // GPS_INPUT_IGNORE_FLAG_VEL_VERT |
599 GPS_INPUT_IGNORE_FLAG_SPEED_ACCURACY | GPS_INPUT_IGNORE_FLAG_HORIZONTAL_ACCURACY | GPS_INPUT_IGNORE_FLAG_VERTICAL_ACCURACY;
600 GPS.time_week_ms = time_week_ms;
601 GPS.time_week = time_week;
602 GPS.fix_type = 3;
603 GPS.lat = lat_d; // Latitude (WGS84) (degE7)
604 GPS.lon = lon_d; // Longitude (WGS84) (degE7)
605 GPS.alt = alt; // Altitude (MSL) Positive for up (m)
606 GPS.hdop = 0.0F;
607 GPS.vdop = 0.0F;
608 GPS.vn = vn;
609 GPS.ve = ve;
610 GPS.vd = vd;
611 GPS.speed_accuracy = 0.0F;
612 GPS.horiz_accuracy = 0.0F;
613 GPS.vert_accuracy = 0.0F;
614 GPS.satellites_visible = 20;
615 GPS.yaw = 0;
616
617 // Encode
618 mavlink_message_t message;
619 mavlink_msg_gps_input_encode(static_cast<uint8_t>(system_id), static_cast<uint8_t>(companion_id), &message, &GPS);
620
621 // Send the message
622 int len = port->write_message(message);
623
624 // Done!
625 return len;
626 }
627
628 // ------------------------------------------------------------------------------
629 // setGPS
630 // ------------------------------------------------------------------------------
631 void Autopilot_Interface::setGPS(int32_t lat_d, int32_t lon_d, float alt, float vn, float ve, float vd, uint32_t time_week_ms, uint16_t time_week)
632 {
633 gps_lat_d = lat_d;
634 gps_lon_d = lon_d;
635 gps_alt = alt;
636 gps_vn = vn;
637 gps_ve = ve;
638 gps_vd = vd;
639 gps_time_week_ms = time_week_ms;
640 gps_time_week = time_week;
641 }
642
643 // ------------------------------------------------------------------------------
644 // setMOCAP
645 // ------------------------------------------------------------------------------
646 void Autopilot_Interface::setMOCAP(float w, float x, float y, float z)
647 {
648 mocap_w = w;
649 mocap_x = x;
650 mocap_y = y;
651 mocap_z = z;
652 }
653
654 // ------------------------------------------------------------------------------
655 // setGPS_Active
656 // ------------------------------------------------------------------------------
657 void Autopilot_Interface::setGPS_Active(bool _Active)
658 {
659 GPS_Active = _Active;
660 }
661
662 // ------------------------------------------------------------------------------
663 // setMOCAP_Active
664 // ------------------------------------------------------------------------------
665 void Autopilot_Interface::setMOCAP_Active(bool _Active)
666 {
667 MOCAP_Active = _Active;
668 }
669
670 // ------------------------------------------------------------------------------
671 // setMOCAP_Frequency
672 // ------------------------------------------------------------------------------
673 void Autopilot_Interface::setMOCAP_Frequency(double _Frequency)
674 {
675 MOCAP_Frequency = _Frequency;
676 }
677
678 // ------------------------------------------------------------------------------
679 // setGPS_Frequency
680 // ------------------------------------------------------------------------------
681 void Autopilot_Interface::setGPS_Frequency(double _Frequency)
682 {
683 GPS_Frequency = _Frequency;
684 }
685
686 // ------------------------------------------------------------------------------
687 // STARTUP
688 // ------------------------------------------------------------------------------
689 void Autopilot_Interface::start()
690 {
691 std::optional<int> result;
692 time_to_exit = false;
693 current_messages = {};
694 // --------------------------------------------------------------------------
695 // CHECK PORT
696 // --------------------------------------------------------------------------
697
698 if (!port->is_running()) // PORT_OPEN
699 {
700 LOG_ERROR("autopilot_interface.cpp - port not open\n");
701 time_to_exit = true;
702 throw EXIT_FAILURE;
703 }
704
705 // --------------------------------------------------------------------------
706 // READ THREAD
707 // --------------------------------------------------------------------------
708
709 LOG_INFO("autopilot_interface.cpp - START READ THREAD \n");
710
711 result = pthread_create(&read_tid, nullptr, &start_autopilot_interface_read_thread, this);
712 if (result.has_value())
713 {
714 LOG_INFO("result = {}", result);
715 }
716
717 // now we're reading messages
718
719 // --------------------------------------------------------------------------
720 // CHECK FOR MESSAGES
721 // --------------------------------------------------------------------------
722
723 LOG_INFO("autopilot_interface.cpp - CHECK FOR MESSAGES\n");
724 int i = 0;
725 while (!current_messages.sysid)
726 {
727 if (time_to_exit || i >= 20)
728 {
729 LOG_ERROR("autopilot_interface.cpp - NO MESSAGES FOUND\n");
730 time_to_exit = true;
731 throw EXIT_FAILURE;
732 }
733 usleep(500000); // check at 2Hz
734 i++; // wait only 10s
735 }
736
737 LOG_INFO("autopilot_interface.cpp - Found\n");
738
739 // now we know autopilot is sending messages
740
741 // --------------------------------------------------------------------------
742 // GET SYSTEM and COMPONENT IDs
743 // --------------------------------------------------------------------------
744
745 // This comes from the heartbeat, which in theory should only come from
746 // the autopilot we're directly connected to it. If there is more than one
747 // vehicle then we can't expect to discover id's like this.
748 // In which case set the id's manually.
749
750 // System ID
751 if (!system_id)
752 {
753 system_id = current_messages.sysid;
754 LOG_INFO("autopilot_interface.cpp - GOT VEHICLE SYSTEM ID: {}\n", system_id);
755 }
756
757 // Component ID
758 if (!autopilot_id)
759 {
760 autopilot_id = current_messages.compid;
761 LOG_INFO("autopilot_interface.cpp - GOT AUTOPILOT COMPONENT ID: {}\n", autopilot_id);
762 }
763
764 // --------------------------------------------------------------------------
765 // GET INITIAL POSITION
766 // --------------------------------------------------------------------------
767
768 // Wait for initial position ned
769 /*
770 while (not(current_messages.time_stamps.local_position_ned && current_messages.time_stamps.attitude))
771 {
772 if (time_to_exit)
773 {
774 return;
775 }
776 usleep(500000);
777 }
778 */
779 // copy initial position ned
780 Mavlink_Messages local_data = current_messages;
781 initial_position.x = local_data.local_position_ned.x;
782 initial_position.y = local_data.local_position_ned.y;
783 initial_position.z = local_data.local_position_ned.z;
784 initial_position.vx = local_data.local_position_ned.vx;
785 initial_position.vy = local_data.local_position_ned.vy;
786 initial_position.vz = local_data.local_position_ned.vz;
787 initial_position.yaw = local_data.attitude.yaw;
788 initial_position.yaw_rate = local_data.attitude.yawspeed;
789
790 LOG_INFO("autopilot_interface.cpp - INITIAL POSITION XYZ = [ {} , {} , {} ] \n", initial_position.x, initial_position.y, initial_position.z);
791 LOG_INFO("autopilot_interface.cpp - INITIAL POSITION YAW = {} \n", initial_position.yaw);
792
793 // we need this before starting the write thread
794
795 // --------------------------------------------------------------------------
796 // WRITE THREAD
797 // --------------------------------------------------------------------------
798 LOG_INFO("autopilot_interface.cpp - START WRITE THREAD \n");
799
800 result = pthread_create(&write_tid, nullptr, &start_autopilot_interface_write_thread, this);
801 if (result.has_value())
802 {
803 LOG_INFO("result = {}", result);
804 }
805
806 // wait for it to be started
807 while (!writing_status)
808 {
809 usleep(100000); // 10Hz
810 }
811
812 // now we're streaming setpoint commands
813
814 // Done!
815 }
816
817 // ------------------------------------------------------------------------------
818 // SHUTDOWN
819 // ------------------------------------------------------------------------------
820 void Autopilot_Interface::stop()
821 {
822 // --------------------------------------------------------------------------
823 // CLOSE THREADS
824 // --------------------------------------------------------------------------
825 LOG_INFO("autopilot_interface.cpp - CLOSE THREADS\n");
826
827 // signal exit
828 time_to_exit = true;
829
830 // wait for exit
831 pthread_join(read_tid, nullptr);
832 pthread_join(write_tid, nullptr);
833
834 // now the read and write threads are closed
835
836 // still need to close the port separately
837 }
838
839 // ------------------------------------------------------------------------------
840 // Read Thread
841 // ------------------------------------------------------------------------------
842 void Autopilot_Interface::start_read_thread()
843 {
844 if (reading_status != 0)
845 {
846 LOG_WARN("autopilot_interface.cpp - read thread already running\n");
847 }
848 else
849 {
850 read_thread();
851 }
852 }
853
854 // ------------------------------------------------------------------------------
855 // Write Thread
856 // ------------------------------------------------------------------------------
857 void Autopilot_Interface::start_write_thread()
858 {
859 if (static_cast<bool>(writing_status))
860 {
861 LOG_ERROR("autopilot_interface.cpp - write thread already running\n");
862 }
863 else
864 {
865 write_thread();
866 }
867 }
868
869 // ------------------------------------------------------------------------------
870 // Quit Handler
871 // ------------------------------------------------------------------------------
872 void Autopilot_Interface::handle_quit(int /* sig */)
873 {
874 disable_offboard_control();
875
876 try
877 {
878 stop();
879 }
880 catch (const std::exception& /* e */)
881 {
882 LOG_ERROR("autopilot_interface.cpp - could not stop autopilot interface\n");
883 }
884 }
885
886 // ------------------------------------------------------------------------------
887 // Read Thread
888 // ------------------------------------------------------------------------------
889 void Autopilot_Interface::read_thread()
890 {
891 reading_status = true;
892
893 while (!time_to_exit)
894 {
895 read_messages();
896 usleep(100000); // Read batches at 10Hz
897 }
898
899 reading_status = false;
900 }
901
902 // ------------------------------------------------------------------------------
903 // Write Thread
904 // ------------------------------------------------------------------------------
905 void Autopilot_Interface::write_thread()
906 {
907 // signal startup
908 writing_status = 2;
909 /*
910 // prepare an initial setpoint, just stay put
911 mavlink_set_position_target_local_ned_t sp;
912 sp.type_mask = MAVLINK_MSG_SET_POSITION_TARGET_LOCAL_NED_VELOCITY & MAVLINK_MSG_SET_POSITION_TARGET_LOCAL_NED_YAW_RATE;
913 sp.coordinate_frame = MAV_FRAME_LOCAL_NED;
914 sp.vx = 0.0;
915 sp.vy = 0.0;
916 sp.vz = 0.0;
917 sp.yaw_rate = 0.0;
918
919 // set position target
920 {
921 std::lock_guard<std::mutex> lock(current_setpoint.mutex);
922 current_setpoint.data = sp;
923 }
924 */
925 // write a message and signal writing
926 // write_setpoint();
927 writing_status = true;
928 // Pixhawk needs to see off-board commands at minimum 2Hz,
929 // otherwise it will go into fail safe
930
931 auto lastCallTimeGPS = std::chrono::system_clock::now();
932 auto lastCallTimeMOCAP = std::chrono::system_clock::now();
933 while (!time_to_exit)
934 {
935 auto currentTime = std::chrono::system_clock::now();
936 auto elapsedTimeGPS = std::chrono::duration_cast<std::chrono::duration<double>>(currentTime - lastCallTimeGPS).count();
937 auto elapsedTimeMOCAP = std::chrono::duration_cast<std::chrono::duration<double>>(currentTime - lastCallTimeMOCAP).count();
938
939 if ((GPS_Frequency > 0.0) && (elapsedTimeGPS >= 1.0 / GPS_Frequency))
940 {
941 if (GPS_Active)
942 {
943 GPS_Input(gps_lat_d, gps_lon_d, gps_alt, gps_vn, gps_ve, gps_vd, gps_time_week_ms, gps_time_week);
944 }
945 lastCallTimeGPS = currentTime;
946 }
947 if ((MOCAP_Frequency > 0.0) && (elapsedTimeMOCAP >= 1.0 / MOCAP_Frequency))
948 {
949 if (MOCAP_Active)
950 {
951 MOCAP_Input(mocap_w, mocap_x, mocap_y, mocap_z);
952 }
953 lastCallTimeMOCAP = currentTime;
954 }
955 // usleep(100);
956 }
957 // signal end
958 writing_status = false;
959 }
960
961 // End Autopilot_Interface
962
963 // ------------------------------------------------------------------------------
964 // Pthread Starter Helper Functions
965 // ------------------------------------------------------------------------------
966
967 void* start_autopilot_interface_read_thread(void* args)
968 {
969 // takes an autopilot object argument
970 auto* autopilot_interface = static_cast<Autopilot_Interface*>(args);
971
972 // run the object's read thread
973 autopilot_interface->start_read_thread();
974
975 // done!
976 return nullptr;
977 }
978
979 void* start_autopilot_interface_write_thread(void* args)
980 {
981 // takes an autopilot object argument
982 auto* autopilot_interface = static_cast<Autopilot_Interface*>(args);
983
984 // run the object's read thread
985 autopilot_interface->start_write_thread(); // NOLINT(clang-analyzer-core.CallAndMessage)
986
987 // done!
988 return nullptr;
989 }
990
991 #endif
992