• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mavlink / MAVSDK / 6568658631

19 Oct 2023 01:31AM UTC coverage: 31.23% (+0.02%) from 31.215%
6568658631

push

github

web-flow
Merge pull request #2155 from mavlink/pr-static-fixes

Threading fixes, MAVLink sequence number cleanup

1386 of 1386 new or added lines in 46 files covered. (100.0%)

7906 of 25315 relevant lines covered (31.23%)

23.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/mavsdk/plugins/offboard/offboard_impl.cpp
1
#include <cmath>
2
#include <utility>
3
#include "mavlink_address.h"
4
#include "mavsdk_math.h"
5
#include "offboard_impl.h"
6
#include "mavsdk_impl.h"
7
#include "px4_custom_mode.h"
8

9
namespace mavsdk {
10

11
OffboardImpl::OffboardImpl(System& system) : PluginImplBase(system)
×
12
{
13
    _system_impl->register_plugin(this);
×
14
}
×
15

16
OffboardImpl::OffboardImpl(std::shared_ptr<System> system) : PluginImplBase(std::move(system))
×
17
{
18
    _system_impl->register_plugin(this);
×
19
}
×
20

21
OffboardImpl::~OffboardImpl()
×
22
{
23
    _system_impl->unregister_plugin(this);
×
24
}
×
25

26
void OffboardImpl::init()
×
27
{
28
    _system_impl->register_mavlink_message_handler(
×
29
        MAVLINK_MSG_ID_HEARTBEAT,
30
        [this](const mavlink_message_t& message) { process_heartbeat(message); },
×
31
        this);
32
}
×
33

34
void OffboardImpl::deinit()
×
35
{
36
    {
37
        std::lock_guard<std::mutex> lock(_mutex);
×
38
        stop_sending_setpoints();
×
39
    }
40
    _system_impl->unregister_all_mavlink_message_handlers(this);
×
41
}
×
42

43
void OffboardImpl::enable() {}
×
44

45
void OffboardImpl::disable() {}
×
46

47
Offboard::Result OffboardImpl::start()
×
48
{
49
    {
50
        std::lock_guard<std::mutex> lock(_mutex);
×
51
        if (_mode == Mode::NotActive) {
×
52
            return Offboard::Result::NoSetpointSet;
×
53
        }
54
        _last_started = _time.steady_time();
×
55
    }
56

57
    return offboard_result_from_command_result(_system_impl->set_flight_mode(FlightMode::Offboard));
×
58
}
59

60
Offboard::Result OffboardImpl::stop()
×
61
{
62
    {
63
        std::lock_guard<std::mutex> lock(_mutex);
×
64
        if (_mode != Mode::NotActive) {
×
65
            stop_sending_setpoints();
×
66
        }
67
    }
68

69
    return offboard_result_from_command_result(_system_impl->set_flight_mode(FlightMode::Hold));
×
70
}
71

72
void OffboardImpl::start_async(Offboard::ResultCallback callback)
×
73
{
74
    {
75
        std::lock_guard<std::mutex> lock(_mutex);
×
76

77
        if (_mode == Mode::NotActive) {
×
78
            if (callback) {
×
79
                _system_impl->call_user_callback(
×
80
                    [callback]() { callback(Offboard::Result::NoSetpointSet); });
81
            }
82
            return;
×
83
        }
84
        _last_started = _time.steady_time();
×
85
    }
86

87
    _system_impl->set_flight_mode_async(
×
88
        FlightMode::Offboard, [callback, this](MavlinkCommandSender::Result result, float) {
×
89
            receive_command_result(result, callback);
×
90
        });
×
91
}
92

93
void OffboardImpl::stop_async(Offboard::ResultCallback callback)
×
94
{
95
    {
96
        std::lock_guard<std::mutex> lock(_mutex);
×
97
        if (_mode != Mode::NotActive) {
×
98
            stop_sending_setpoints();
×
99
        }
100
    }
101

102
    _system_impl->set_flight_mode_async(
×
103
        FlightMode::Hold, [callback, this](MavlinkCommandSender::Result result, float) {
×
104
            receive_command_result(result, callback);
×
105
        });
×
106
}
×
107

108
bool OffboardImpl::is_active()
×
109
{
110
    std::lock_guard<std::mutex> lock(_mutex);
×
111
    return (_mode != Mode::NotActive);
×
112
}
113

114
void OffboardImpl::receive_command_result(
×
115
    MavlinkCommandSender::Result result, const Offboard::ResultCallback& callback)
116
{
117
    Offboard::Result offboard_result = offboard_result_from_command_result(result);
×
118
    if (callback) {
×
119
        _system_impl->call_user_callback(
×
120
            [callback, offboard_result]() { callback(offboard_result); });
121
    }
122
}
×
123

124
Offboard::Result OffboardImpl::set_position_ned(Offboard::PositionNedYaw position_ned_yaw)
×
125
{
126
    {
127
        std::lock_guard<std::mutex> lock(_mutex);
×
128
        _position_ned_yaw = position_ned_yaw;
×
129

130
        if (_mode != Mode::PositionNed) {
×
131
            if (_call_every_cookie) {
×
132
                // If we're already sending other setpoints, stop that now.
133
                _system_impl->remove_call_every(_call_every_cookie);
×
134
                _call_every_cookie = nullptr;
×
135
            }
136
            // We automatically send Ned setpoints from now on.
137
            _system_impl->add_call_every(
×
138
                [this]() { send_position_ned(); }, SEND_INTERVAL_S, &_call_every_cookie);
×
139

140
            _mode = Mode::PositionNed;
×
141
        } else {
142
            // We're already sending these kind of setpoints. Since the setpoint change, let's
143
            // reschedule the next call, so we don't send setpoints too often.
144
            _system_impl->reset_call_every(_call_every_cookie);
×
145
        }
146
    }
147

148
    // also send it right now to reduce latency
149
    return send_position_ned();
×
150
}
151

152
Offboard::Result OffboardImpl::set_position_global(Offboard::PositionGlobalYaw position_global_yaw)
×
153
{
154
    {
155
        std::lock_guard<std::mutex> lock(_mutex);
×
156
        _position_global_yaw = position_global_yaw;
×
157

158
        if (_mode != Mode::PositionGlobalAltRel) {
×
159
            if (_call_every_cookie) {
×
160
                // If we're already sending other setpoints, stop that now.
161
                _system_impl->remove_call_every(_call_every_cookie);
×
162
                _call_every_cookie = nullptr;
×
163
            }
164
            // We automatically send Global setpoints from now on.
165
            _system_impl->add_call_every(
×
166
                [this]() { send_position_global(); }, SEND_INTERVAL_S, &_call_every_cookie);
×
167

168
            _mode = Mode::PositionGlobalAltRel;
×
169
        } else {
170
            // We're already sending these kind of setpoints. Since the setpoint change, let's
171
            // reschedule the next call, so we don't send setpoints too often.
172
            _system_impl->reset_call_every(_call_every_cookie);
×
173
        }
174
    }
175

176
    // also send it right now to reduce latency
177
    return send_position_global();
×
178
}
179

180
Offboard::Result OffboardImpl::set_velocity_ned(Offboard::VelocityNedYaw velocity_ned_yaw)
×
181
{
182
    {
183
        std::lock_guard<std::mutex> lock(_mutex);
×
184
        _velocity_ned_yaw = velocity_ned_yaw;
×
185

186
        if (_mode != Mode::VelocityNed) {
×
187
            if (_call_every_cookie) {
×
188
                // If we're already sending other setpoints, stop that now.
189
                _system_impl->remove_call_every(_call_every_cookie);
×
190
                _call_every_cookie = nullptr;
×
191
            }
192
            // We automatically send Ned setpoints from now on.
193
            _system_impl->add_call_every(
×
194
                [this]() { send_velocity_ned(); }, SEND_INTERVAL_S, &_call_every_cookie);
×
195

196
            _mode = Mode::VelocityNed;
×
197
        } else {
198
            // We're already sending these kind of setpoints. Since the setpoint change, let's
199
            // reschedule the next call, so we don't send setpoints too often.
200
            _system_impl->reset_call_every(_call_every_cookie);
×
201
        }
202
    }
203
    // also send it right now to reduce latency
204
    return send_velocity_ned();
×
205
}
206

207
Offboard::Result OffboardImpl::set_position_velocity_ned(
×
208
    Offboard::PositionNedYaw position_ned_yaw, Offboard::VelocityNedYaw velocity_ned_yaw)
209
{
210
    {
211
        std::lock_guard<std::mutex> lock(_mutex);
×
212
        _position_ned_yaw = position_ned_yaw;
×
213
        _velocity_ned_yaw = velocity_ned_yaw;
×
214

215
        if (_mode != Mode::PositionVelocityNed) {
×
216
            if (_call_every_cookie) {
×
217
                // If we're already sending other setpoints, stop that now.
218
                _system_impl->remove_call_every(_call_every_cookie);
×
219
                _call_every_cookie = nullptr;
×
220
            }
221
            // We automatically send Ned setpoints from now on.
222
            _system_impl->add_call_every(
×
223
                [this]() { send_position_velocity_ned(); }, SEND_INTERVAL_S, &_call_every_cookie);
×
224

225
            _mode = Mode::PositionVelocityNed;
×
226
        } else {
227
            // We're already sending these kind of setpoints. Since the setpoint change, let's
228
            // reschedule the next call, so we don't send setpoints too often.
229
            _system_impl->reset_call_every(_call_every_cookie);
×
230
        }
231
    }
232

233
    // also send it right now to reduce latency
234
    return send_position_velocity_ned();
×
235
}
236

237
Offboard::Result OffboardImpl::set_position_velocity_acceleration_ned(
×
238
    Offboard::PositionNedYaw position_ned_yaw,
239
    Offboard::VelocityNedYaw velocity_ned_yaw,
240
    Offboard::AccelerationNed acceleration_ned)
241
{
242
    {
243
        std::lock_guard<std::mutex> lock(_mutex);
×
244
        _position_ned_yaw = position_ned_yaw;
×
245
        _velocity_ned_yaw = velocity_ned_yaw;
×
246
        _acceleration_ned = acceleration_ned;
×
247

248
        if (_mode != Mode::PositionVelocityAccelerationNed) {
×
249
            if (_call_every_cookie) {
×
250
                // If we're already sending other setpoints, stop that now.
251
                _system_impl->remove_call_every(_call_every_cookie);
×
252
                _call_every_cookie = nullptr;
×
253
            }
254
            // We automatically send Ned setpoints from now on.
255
            _system_impl->add_call_every(
×
256
                [this]() { send_position_velocity_acceleration_ned(); },
×
257
                SEND_INTERVAL_S,
×
258
                &_call_every_cookie);
259

260
            _mode = Mode::PositionVelocityAccelerationNed;
×
261
        } else {
262
            // We're already sending these kind of setpoints. Since the setpoint change, let's
263
            // reschedule the next call, so we don't send setpoints too often.
264
            _system_impl->reset_call_every(_call_every_cookie);
×
265
        }
266
    }
267

268
    // also send it right now to reduce latency
269
    return send_position_velocity_acceleration_ned();
×
270
}
271

272
Offboard::Result OffboardImpl::set_acceleration_ned(Offboard::AccelerationNed acceleration_ned)
×
273
{
274
    {
275
        std::lock_guard<std::mutex> lock(_mutex);
×
276
        _acceleration_ned = acceleration_ned;
×
277

278
        if (_mode != Mode::AccelerationNed) {
×
279
            if (_call_every_cookie) {
×
280
                // If we're already sending other setpoints, stop that now.
281
                _system_impl->remove_call_every(_call_every_cookie);
×
282
                _call_every_cookie = nullptr;
×
283
            }
284
            // We automatically send Ned setpoints from now on.
285
            _system_impl->add_call_every(
×
286
                [this]() { send_acceleration_ned(); }, SEND_INTERVAL_S, &_call_every_cookie);
×
287

288
            _mode = Mode::AccelerationNed;
×
289
        } else {
290
            // We're already sending these kind of setpoints. Since the setpoint change, let's
291
            // reschedule the next call, so we don't send setpoints too often.
292
            _system_impl->reset_call_every(_call_every_cookie);
×
293
        }
294
    }
295

296
    // also send it right now to reduce latency
297
    return send_acceleration_ned();
×
298
}
299

300
Offboard::Result
301
OffboardImpl::set_velocity_body(Offboard::VelocityBodyYawspeed velocity_body_yawspeed)
×
302
{
303
    {
304
        std::lock_guard<std::mutex> lock(_mutex);
×
305
        _velocity_body_yawspeed = velocity_body_yawspeed;
×
306

307
        if (_mode != Mode::VelocityBody) {
×
308
            if (_call_every_cookie) {
×
309
                // If we're already sending other setpoints, stop that now.
310
                _system_impl->remove_call_every(_call_every_cookie);
×
311
                _call_every_cookie = nullptr;
×
312
            }
313
            // We automatically send body setpoints from now on.
314
            _system_impl->add_call_every(
×
315
                [this]() { send_velocity_body(); }, SEND_INTERVAL_S, &_call_every_cookie);
×
316

317
            _mode = Mode::VelocityBody;
×
318
        } else {
319
            // We're already sending these kind of setpoints. Since the setpoint change, let's
320
            // reschedule the next call, so we don't send setpoints too often.
321
            _system_impl->reset_call_every(_call_every_cookie);
×
322
        }
323
    }
324

325
    // also send it right now to reduce latency
326
    return send_velocity_body();
×
327
}
328

329
Offboard::Result OffboardImpl::set_attitude(Offboard::Attitude attitude)
×
330
{
331
    {
332
        std::lock_guard<std::mutex> lock(_mutex);
×
333
        _attitude = attitude;
×
334

335
        if (_mode != Mode::Attitude) {
×
336
            if (_call_every_cookie) {
×
337
                // If we're already sending other setpoints, stop that now.
338
                _system_impl->remove_call_every(_call_every_cookie);
×
339
                _call_every_cookie = nullptr;
×
340
            }
341
            // We automatically send body setpoints from now on.
342
            _system_impl->add_call_every(
×
343
                [this]() { send_attitude(); }, SEND_INTERVAL_S, &_call_every_cookie);
×
344

345
            _mode = Mode::Attitude;
×
346
        } else {
347
            // We're already sending these kind of setpoints. Since the setpoint change, let's
348
            // reschedule the next call, so we don't send setpoints too often.
349
            _system_impl->reset_call_every(_call_every_cookie);
×
350
        }
351
    }
352

353
    // also send it right now to reduce latency
354
    return send_attitude();
×
355
}
356

357
Offboard::Result OffboardImpl::set_attitude_rate(Offboard::AttitudeRate attitude_rate)
×
358
{
359
    {
360
        std::lock_guard<std::mutex> lock(_mutex);
×
361
        _attitude_rate = attitude_rate;
×
362

363
        if (_mode != Mode::AttitudeRate) {
×
364
            if (_call_every_cookie) {
×
365
                // If we're already sending other setpoints, stop that now.
366
                _system_impl->remove_call_every(_call_every_cookie);
×
367
                _call_every_cookie = nullptr;
×
368
            }
369
            // We automatically send body setpoints from now on.
370
            _system_impl->add_call_every(
×
371
                [this]() { send_attitude_rate(); }, SEND_INTERVAL_S, &_call_every_cookie);
×
372

373
            _mode = Mode::AttitudeRate;
×
374
        } else {
375
            // We're already sending these kind of setpoints. Since the setpoint change, let's
376
            // reschedule the next call, so we don't send setpoints too often.
377
            _system_impl->reset_call_every(_call_every_cookie);
×
378
        }
379
    }
380

381
    // also send it right now to reduce latency
382
    return send_attitude_rate();
×
383
}
384

385
Offboard::Result OffboardImpl::set_actuator_control(Offboard::ActuatorControl actuator_control)
×
386
{
387
    {
388
        std::lock_guard<std::mutex> lock(_mutex);
×
389
        _actuator_control = actuator_control;
×
390

391
        if (_mode != Mode::ActuatorControl) {
×
392
            if (_call_every_cookie) {
×
393
                // If we're already sending other setpoints, stop that now.
394
                _system_impl->remove_call_every(_call_every_cookie);
×
395
                _call_every_cookie = nullptr;
×
396
            }
397
            // We automatically send motor rate values from now on.
398
            _system_impl->add_call_every(
×
399
                [this]() { send_actuator_control(); }, SEND_INTERVAL_S, &_call_every_cookie);
×
400

401
            _mode = Mode::ActuatorControl;
×
402
        } else {
403
            // We're already sending these kind of values. Since the value changes, let's
404
            // reschedule the next call, so we don't send values too often.
405
            _system_impl->reset_call_every(_call_every_cookie);
×
406
        }
407
    }
408

409
    // It gets sent immediately as part of add_call_every.
410
    return Offboard::Result::Success;
×
411
}
412

413
Offboard::Result OffboardImpl::send_position_ned()
×
414
{
415
    const static uint16_t IGNORE_VX = (1 << 3);
416
    const static uint16_t IGNORE_VY = (1 << 4);
417
    const static uint16_t IGNORE_VZ = (1 << 5);
418
    const static uint16_t IGNORE_AX = (1 << 6);
419
    const static uint16_t IGNORE_AY = (1 << 7);
420
    const static uint16_t IGNORE_AZ = (1 << 8);
421
    const static uint16_t IGNORE_YAW_RATE = (1 << 11);
422

423
    const auto position_ned_yaw = [this]() {
×
424
        std::lock_guard<std::mutex> lock(_mutex);
×
425
        return _position_ned_yaw;
×
426
    }();
×
427

428
    return _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
429
        mavlink_message_t message;
430
        mavlink_msg_set_position_target_local_ned_pack_chan(
×
431
            mavlink_address.system_id,
×
432
            mavlink_address.component_id,
×
433
            channel,
434
            &message,
435
            static_cast<uint32_t>(_system_impl->get_time().elapsed_ms()),
×
436
            _system_impl->get_system_id(),
×
437
            _system_impl->get_autopilot_id(),
×
438
            MAV_FRAME_LOCAL_NED,
439
            IGNORE_VX | IGNORE_VY | IGNORE_VZ | IGNORE_AX | IGNORE_AY | IGNORE_AZ | IGNORE_YAW_RATE,
440
            position_ned_yaw.north_m,
×
441
            position_ned_yaw.east_m,
×
442
            position_ned_yaw.down_m,
×
443
            0.0f, // vx
444
            0.0f, // vy
445
            0.0f, // vz
446
            0.0f, // afx
447
            0.0f, // afy
448
            0.0f, // afz
449
            to_rad_from_deg(position_ned_yaw.yaw_deg), // yaw
×
450
            0.0f); // yaw_rate
451
        return message;
×
452
    }) ?
×
453
               Offboard::Result::Success :
454
               Offboard::Result::ConnectionError;
×
455
}
456

457
Offboard::Result OffboardImpl::send_position_global()
×
458
{
459
    const static uint16_t IGNORE_VX = (1 << 3);
460
    const static uint16_t IGNORE_VY = (1 << 4);
461
    const static uint16_t IGNORE_VZ = (1 << 5);
462
    const static uint16_t IGNORE_AX = (1 << 6);
463
    const static uint16_t IGNORE_AY = (1 << 7);
464
    const static uint16_t IGNORE_AZ = (1 << 8);
465
    const static uint16_t IGNORE_YAW_RATE = (1 << 11);
466

467
    const auto position_global_yaw = [this]() {
×
468
        std::lock_guard<std::mutex> lock(_mutex);
×
469
        return _position_global_yaw;
×
470
    }();
×
471

472
    MAV_FRAME frame;
×
473
    switch (position_global_yaw.altitude_type) {
×
474
        case Offboard::PositionGlobalYaw::AltitudeType::Amsl:
×
475
            frame = MAV_FRAME_GLOBAL_INT;
×
476
            break;
×
477
        case Offboard::PositionGlobalYaw::AltitudeType::Agl:
×
478
            frame = MAV_FRAME_GLOBAL_TERRAIN_ALT_INT;
×
479
            break;
×
480
        case Offboard::PositionGlobalYaw::AltitudeType::RelHome:
×
481
            frame = MAV_FRAME_GLOBAL_RELATIVE_ALT_INT;
×
482
            break;
×
483
        default:
×
484
            return Offboard::Result::CommandDenied;
×
485
            break;
486
    }
487
    return _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
488
        mavlink_message_t message;
489
        mavlink_msg_set_position_target_global_int_pack_chan(
×
490
            mavlink_address.system_id,
×
491
            mavlink_address.component_id,
×
492
            channel,
493
            &message,
494
            static_cast<uint32_t>(_system_impl->get_time().elapsed_ms()),
×
495
            _system_impl->get_system_id(),
×
496
            _system_impl->get_autopilot_id(),
×
497
            frame,
×
498
            IGNORE_VX | IGNORE_VY | IGNORE_VZ | IGNORE_AX | IGNORE_AY | IGNORE_AZ | IGNORE_YAW_RATE,
499
            (int32_t)(position_global_yaw.lat_deg * 1.0e7),
×
500
            (int32_t)(position_global_yaw.lon_deg * 1.0e7),
×
501
            position_global_yaw.alt_m,
×
502
            0.0f, // vx
503
            0.0f, // vy
504
            0.0f, // vz
505
            0.0f, // afx
506
            0.0f, // afy
507
            0.0f, // afz
508
            to_rad_from_deg(position_global_yaw.yaw_deg), // yaw
×
509
            0.0f); // yaw_rate
510
        return message;
×
511
    }) ?
×
512
               Offboard::Result::Success :
513
               Offboard::Result::ConnectionError;
×
514
}
515

516
Offboard::Result OffboardImpl::send_velocity_ned()
×
517
{
518
    const static uint16_t IGNORE_X = (1 << 0);
519
    const static uint16_t IGNORE_Y = (1 << 1);
520
    const static uint16_t IGNORE_Z = (1 << 2);
521
    const static uint16_t IGNORE_AX = (1 << 6);
522
    const static uint16_t IGNORE_AY = (1 << 7);
523
    const static uint16_t IGNORE_AZ = (1 << 8);
524
    const static uint16_t IGNORE_YAW_RATE = (1 << 11);
525

526
    const auto velocity_ned_yaw = [this]() {
×
527
        std::lock_guard<std::mutex> lock(_mutex);
×
528
        return _velocity_ned_yaw;
×
529
    }();
×
530

531
    return _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
532
        mavlink_message_t message;
533
        mavlink_msg_set_position_target_local_ned_pack_chan(
×
534
            mavlink_address.system_id,
×
535
            mavlink_address.component_id,
×
536
            channel,
537
            &message,
538
            static_cast<uint32_t>(_system_impl->get_time().elapsed_ms()),
×
539
            _system_impl->get_system_id(),
×
540
            _system_impl->get_autopilot_id(),
×
541
            MAV_FRAME_LOCAL_NED,
542
            IGNORE_X | IGNORE_Y | IGNORE_Z | IGNORE_AX | IGNORE_AY | IGNORE_AZ | IGNORE_YAW_RATE,
543
            0.0f, // x,
544
            0.0f, // y,
545
            0.0f, // z,
546
            velocity_ned_yaw.north_m_s,
×
547
            velocity_ned_yaw.east_m_s,
×
548
            velocity_ned_yaw.down_m_s,
×
549
            0.0f, // afx
550
            0.0f, // afy
551
            0.0f, // afz
552
            to_rad_from_deg(velocity_ned_yaw.yaw_deg), // yaw
×
553
            0.0f); // yaw_rate
554
        return message;
×
555
    }) ?
×
556
               Offboard::Result::Success :
557
               Offboard::Result::ConnectionError;
×
558
}
559

560
Offboard::Result OffboardImpl::send_position_velocity_ned()
×
561
{
562
    const static uint16_t IGNORE_AX = (1 << 6);
563
    const static uint16_t IGNORE_AY = (1 << 7);
564
    const static uint16_t IGNORE_AZ = (1 << 8);
565
    const static uint16_t IGNORE_YAW_RATE = (1 << 11);
566

567
    const auto position_and_velocity = [this]() {
×
568
        std::lock_guard<std::mutex> lock(_mutex);
×
569
        return std::make_pair<>(_position_ned_yaw, _velocity_ned_yaw);
×
570
    }();
×
571

572
    return _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
573
        mavlink_message_t message;
574
        mavlink_msg_set_position_target_local_ned_pack_chan(
×
575
            mavlink_address.system_id,
×
576
            mavlink_address.component_id,
×
577
            channel,
578
            &message,
579
            static_cast<uint32_t>(_system_impl->get_time().elapsed_ms()),
×
580
            _system_impl->get_system_id(),
×
581
            _system_impl->get_autopilot_id(),
×
582
            MAV_FRAME_LOCAL_NED,
583
            IGNORE_AX | IGNORE_AY | IGNORE_AZ | IGNORE_YAW_RATE,
584
            position_and_velocity.first.north_m,
×
585
            position_and_velocity.first.east_m,
×
586
            position_and_velocity.first.down_m,
×
587
            position_and_velocity.second.north_m_s,
×
588
            position_and_velocity.second.east_m_s,
×
589
            position_and_velocity.second.down_m_s,
×
590
            0.0f, // afx
591
            0.0f, // afy
592
            0.0f, // afz
593
            to_rad_from_deg(position_and_velocity.first.yaw_deg), // yaw
×
594
            0.0f); // yaw_rate
595
        return message;
×
596
    }) ?
×
597
               Offboard::Result::Success :
598
               Offboard::Result::ConnectionError;
×
599
}
600

601
Offboard::Result OffboardImpl::send_position_velocity_acceleration_ned()
×
602
{
603
    const static uint16_t IGNORE_YAW_RATE = (1 << 11);
604

605
    std::lock_guard<std::mutex> lock(_mutex);
×
606
    return _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
607
        mavlink_message_t message;
608
        mavlink_msg_set_position_target_local_ned_pack_chan(
×
609
            mavlink_address.system_id,
×
610
            mavlink_address.component_id,
×
611
            channel,
612
            &message,
613
            static_cast<uint32_t>(_system_impl->get_time().elapsed_ms()),
×
614
            _system_impl->get_system_id(),
×
615
            _system_impl->get_autopilot_id(),
×
616
            MAV_FRAME_LOCAL_NED,
617
            IGNORE_YAW_RATE,
618
            _position_ned_yaw.north_m,
619
            _position_ned_yaw.east_m,
620
            _position_ned_yaw.down_m,
621
            _velocity_ned_yaw.north_m_s,
622
            _velocity_ned_yaw.east_m_s,
623
            _velocity_ned_yaw.down_m_s,
624
            _acceleration_ned.north_m_s2,
625
            _acceleration_ned.east_m_s2,
626
            _acceleration_ned.down_m_s2,
627
            to_rad_from_deg(_position_ned_yaw.yaw_deg), // yaw
628
            0.0f); // yaw_rate
629
        return message;
×
630
    }) ?
×
631
               Offboard::Result::Success :
632
               Offboard::Result::ConnectionError;
×
633
}
634

635
Offboard::Result OffboardImpl::send_acceleration_ned()
×
636
{
637
    const static uint16_t IGNORE_X = (1 << 0);
638
    const static uint16_t IGNORE_Y = (1 << 1);
639
    const static uint16_t IGNORE_Z = (1 << 2);
640
    const static uint16_t IGNORE_VX = (1 << 3);
641
    const static uint16_t IGNORE_VY = (1 << 4);
642
    const static uint16_t IGNORE_VZ = (1 << 5);
643
    const static uint16_t IGNORE_YAW = (1 << 10);
644
    const static uint16_t IGNORE_YAW_RATE = (1 << 11);
645

646
    const auto acceleration_ned = [this]() {
×
647
        std::lock_guard<std::mutex> lock(_mutex);
×
648
        return _acceleration_ned;
×
649
    }();
×
650

651
    return _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
652
        mavlink_message_t message;
653
        mavlink_msg_set_position_target_local_ned_pack_chan(
×
654
            mavlink_address.system_id,
×
655
            mavlink_address.component_id,
×
656
            channel,
657
            &message,
658
            static_cast<uint32_t>(_system_impl->get_time().elapsed_ms()),
×
659
            _system_impl->get_system_id(),
×
660
            _system_impl->get_autopilot_id(),
×
661
            MAV_FRAME_LOCAL_NED,
662
            IGNORE_X | IGNORE_Y | IGNORE_Z | IGNORE_VX | IGNORE_VY | IGNORE_VZ | IGNORE_YAW |
663
                IGNORE_YAW_RATE,
664
            0.0f, // x,
665
            0.0f, // y,
666
            0.0f, // z,
667
            0.0f, // vfx
668
            0.0f, // vfy
669
            0.0f, // vfz
670
            acceleration_ned.north_m_s2,
×
671
            acceleration_ned.east_m_s2,
×
672
            acceleration_ned.down_m_s2,
×
673
            0.0f, // yaw
674
            0.0f); // yaw_rate
675
        return message;
×
676
    }) ?
×
677
               Offboard::Result::Success :
678
               Offboard::Result::ConnectionError;
×
679
}
680

681
Offboard::Result OffboardImpl::send_velocity_body()
×
682
{
683
    const static uint16_t IGNORE_X = (1 << 0);
684
    const static uint16_t IGNORE_Y = (1 << 1);
685
    const static uint16_t IGNORE_Z = (1 << 2);
686
    const static uint16_t IGNORE_AX = (1 << 6);
687
    const static uint16_t IGNORE_AY = (1 << 7);
688
    const static uint16_t IGNORE_AZ = (1 << 8);
689
    const static uint16_t IGNORE_YAW = (1 << 10);
690

691
    const auto velocity_body_yawspeed = [this]() {
×
692
        std::lock_guard<std::mutex> lock(_mutex);
×
693
        return _velocity_body_yawspeed;
×
694
    }();
×
695

696
    return _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
697
        mavlink_message_t message;
698
        mavlink_msg_set_position_target_local_ned_pack_chan(
×
699
            mavlink_address.system_id,
×
700
            mavlink_address.component_id,
×
701
            channel,
702
            &message,
703
            static_cast<uint32_t>(_system_impl->get_time().elapsed_ms()),
×
704
            _system_impl->get_system_id(),
×
705
            _system_impl->get_autopilot_id(),
×
706
            MAV_FRAME_BODY_NED,
707
            IGNORE_X | IGNORE_Y | IGNORE_Z | IGNORE_AX | IGNORE_AY | IGNORE_AZ | IGNORE_YAW,
708
            0.0f, // x
709
            0.0f, // y
710
            0.0f, // z
711
            velocity_body_yawspeed.forward_m_s,
×
712
            velocity_body_yawspeed.right_m_s,
×
713
            velocity_body_yawspeed.down_m_s,
×
714
            0.0f, // afx
715
            0.0f, // afy
716
            0.0f, // afz
717
            0.0f, // yaw
718
            to_rad_from_deg(velocity_body_yawspeed.yawspeed_deg_s));
×
719
        return message;
×
720
    }) ?
×
721
               Offboard::Result::Success :
722
               Offboard::Result::ConnectionError;
×
723
}
724

725
Offboard::Result OffboardImpl::send_attitude()
×
726
{
727
    const static uint8_t IGNORE_BODY_ROLL_RATE = (1 << 0);
728
    const static uint8_t IGNORE_BODY_PITCH_RATE = (1 << 1);
729
    const static uint8_t IGNORE_BODY_YAW_RATE = (1 << 2);
730

731
    const auto attitude = [this]() {
×
732
        std::lock_guard<std::mutex> lock(_mutex);
×
733
        return _attitude;
×
734
    }();
×
735

736
    const float thrust = _attitude.thrust_value;
×
737
    const float roll = to_rad_from_deg(attitude.roll_deg);
×
738
    const float pitch = to_rad_from_deg(attitude.pitch_deg);
×
739
    const float yaw = to_rad_from_deg(attitude.yaw_deg);
×
740

741
    const double cos_phi_2 = cos(double(roll) / 2.0);
×
742
    const double sin_phi_2 = sin(double(roll) / 2.0);
×
743
    const double cos_theta_2 = cos(double(pitch) / 2.0);
×
744
    const double sin_theta_2 = sin(double(pitch) / 2.0);
×
745
    const double cos_psi_2 = cos(double(yaw) / 2.0);
×
746
    const double sin_psi_2 = sin(double(yaw) / 2.0);
×
747

748
    float q[4];
×
749

750
    q[0] = float(cos_phi_2 * cos_theta_2 * cos_psi_2 + sin_phi_2 * sin_theta_2 * sin_psi_2);
×
751
    q[1] = float(sin_phi_2 * cos_theta_2 * cos_psi_2 - cos_phi_2 * sin_theta_2 * sin_psi_2);
×
752
    q[2] = float(cos_phi_2 * sin_theta_2 * cos_psi_2 + sin_phi_2 * cos_theta_2 * sin_psi_2);
×
753
    q[3] = float(cos_phi_2 * cos_theta_2 * sin_psi_2 - sin_phi_2 * sin_theta_2 * cos_psi_2);
×
754

755
    const float thrust_body[3] = {0.0f, 0.0f, 0.0f};
×
756

757
    return _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
758
        mavlink_message_t message;
759
        mavlink_msg_set_attitude_target_pack_chan(
×
760
            mavlink_address.system_id,
×
761
            mavlink_address.component_id,
×
762
            channel,
763
            &message,
764
            static_cast<uint32_t>(_system_impl->get_time().elapsed_ms()),
×
765
            _system_impl->get_system_id(),
×
766
            _system_impl->get_autopilot_id(),
×
767
            IGNORE_BODY_ROLL_RATE | IGNORE_BODY_PITCH_RATE | IGNORE_BODY_YAW_RATE,
768
            q,
×
769
            0,
770
            0,
771
            0,
772
            thrust,
×
773
            thrust_body);
×
774
        return message;
×
775
    }) ?
×
776
               Offboard::Result::Success :
777
               Offboard::Result::ConnectionError;
×
778
}
779

780
Offboard::Result OffboardImpl::send_attitude_rate()
×
781
{
782
    const static uint8_t IGNORE_ATTITUDE = (1 << 7);
783

784
    const auto attitude_rate = [this]() {
×
785
        std::lock_guard<std::mutex> lock(_mutex);
×
786
        return _attitude_rate;
×
787
    }();
×
788

789
    const float thrust_body[3] = {0.0f, 0.0f, 0.0f};
×
790

791
    return _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
792
        mavlink_message_t message;
793
        mavlink_msg_set_attitude_target_pack_chan(
×
794
            mavlink_address.system_id,
×
795
            mavlink_address.component_id,
×
796
            channel,
797
            &message,
798
            static_cast<uint32_t>(_system_impl->get_time().elapsed_ms()),
×
799
            _system_impl->get_system_id(),
×
800
            _system_impl->get_autopilot_id(),
×
801
            IGNORE_ATTITUDE,
802
            0,
803
            to_rad_from_deg(attitude_rate.roll_deg_s),
×
804
            to_rad_from_deg(attitude_rate.pitch_deg_s),
×
805
            to_rad_from_deg(attitude_rate.yaw_deg_s),
×
806
            _attitude_rate.thrust_value,
807
            thrust_body);
×
808
        return message;
×
809
    }) ?
×
810
               Offboard::Result::Success :
811
               Offboard::Result::ConnectionError;
×
812
}
813

814
Offboard::Result
815
OffboardImpl::send_actuator_control_message(const float* controls, uint8_t group_number)
×
816
{
817
    return _system_impl->queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
×
818
        mavlink_message_t message;
819
        mavlink_msg_set_actuator_control_target_pack_chan(
×
820
            mavlink_address.system_id,
×
821
            mavlink_address.component_id,
×
822
            channel,
823
            &message,
824
            static_cast<uint32_t>(_system_impl->get_time().elapsed_ms()),
×
825
            group_number,
×
826
            _system_impl->get_system_id(),
×
827
            _system_impl->get_autopilot_id(),
×
828
            controls);
×
829
        return message;
×
830
    }) ?
×
831
               Offboard::Result::Success :
832
               Offboard::Result::ConnectionError;
×
833
}
834

835
Offboard::Result OffboardImpl::send_actuator_control()
×
836
{
837
    std::lock_guard<std::mutex> lock(_mutex);
×
838

839
    for (unsigned i = 0; i < 4 && i < _actuator_control.groups.size(); ++i) {
×
840
        _actuator_control.groups[i].controls.resize(8, NAN);
×
841

842
        for (unsigned j = 0; j < 8; ++j) {
×
843
            if (std::isnan(_actuator_control.groups[i].controls[j])) {
×
844
                _actuator_control.groups[i].controls[j] = 0.0f;
×
845
            }
846
        }
847
        auto result = send_actuator_control_message(&_actuator_control.groups[i].controls[0], i);
×
848

849
        if (result != Offboard::Result::Success) {
×
850
            return result;
×
851
        }
852
    }
853

854
    return Offboard::Result::Success;
×
855
}
856

857
void OffboardImpl::process_heartbeat(const mavlink_message_t& message)
×
858
{
859
    // Process only Heartbeat coming from the autopilot
860
    if (message.compid != MAV_COMP_ID_AUTOPILOT1) {
×
861
        return;
×
862
    }
863

864
    mavlink_heartbeat_t heartbeat;
×
865
    mavlink_msg_heartbeat_decode(&message, &heartbeat);
×
866

867
    bool offboard_mode_active = false;
×
868
    if (heartbeat.base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) {
×
869
        FlightMode flight_mode = to_flight_mode_from_custom_mode(
×
870
            _system_impl->autopilot(), _system_impl->get_vehicle_type(), heartbeat.custom_mode);
×
871

872
        if (flight_mode == FlightMode::Offboard) {
×
873
            offboard_mode_active = true;
×
874
        }
875
    }
876

877
    {
878
        // Right after we started offboard we might still be getting heartbeats
879
        // from earlier which don't indicate offboard mode yet.
880
        // Therefore, we make sure we don't stop too eagerly and ignore
881
        // possibly stale heartbeats for some time.
882
        std::lock_guard<std::mutex> lock(_mutex);
×
883
        if (!offboard_mode_active && _mode != Mode::NotActive &&
×
884
            _time.elapsed_since_s(_last_started) > 3.0) {
×
885
            // It seems that we are no longer in offboard mode but still trying to send
886
            // setpoints. Let's stop for now.
887
            stop_sending_setpoints();
×
888
        }
889
    }
890
}
891

892
void OffboardImpl::stop_sending_setpoints()
×
893
{
894
    // We assume that we already acquired the mutex in this function.
895

896
    if (_call_every_cookie != nullptr) {
×
897
        _system_impl->remove_call_every(_call_every_cookie);
×
898
        _call_every_cookie = nullptr;
×
899
    }
900
    _mode = Mode::NotActive;
×
901
}
×
902

903
Offboard::Result
904
OffboardImpl::offboard_result_from_command_result(MavlinkCommandSender::Result result)
×
905
{
906
    switch (result) {
×
907
        case MavlinkCommandSender::Result::Success:
×
908
            return Offboard::Result::Success;
×
909
        case MavlinkCommandSender::Result::NoSystem:
×
910
            return Offboard::Result::NoSystem;
×
911
        case MavlinkCommandSender::Result::ConnectionError:
×
912
            return Offboard::Result::ConnectionError;
×
913
        case MavlinkCommandSender::Result::Busy:
×
914
            return Offboard::Result::Busy;
×
915
        case MavlinkCommandSender::Result::Denied:
×
916
            // FALLTHROUGH
917
        case MavlinkCommandSender::Result::TemporarilyRejected:
918
            return Offboard::Result::CommandDenied;
×
919
        case MavlinkCommandSender::Result::Timeout:
×
920
            return Offboard::Result::Timeout;
×
921
        case MavlinkCommandSender::Result::Failed:
×
922
            return Offboard::Result::Failed;
×
923
        default:
×
924
            return Offboard::Result::Unknown;
×
925
    }
926
}
927

928
} // namespace mavsdk
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc