7#include <QtCore/QDateTime>
22 , _hasRollAxis(hasRollAxis)
23 , _hasPitchAxis(hasPitchAxis)
24 , _hasYawAxis(hasYawAxis)
25 , _hasYawFollow(hasYawFollow)
26 , _hasYawLock(hasYawLock)
27 , _hasRetract(hasRetract)
28 , _hasNeutral(hasNeutral)
38 QMutexLocker locker(&_stateMutex);
39 const qint64 nowMs = QDateTime::currentMSecsSinceEpoch();
42 if (_managerStatusIntervalUs > 0) {
43 const qint64 intervalMs = _managerStatusIntervalUs / 1000;
44 if ((nowMs - _managerStatusLastSentMs) >= intervalMs) {
45 _sendGimbalManagerStatus();
46 _managerStatusLastSentMs = nowMs;
51 if (_deviceAttitudeStatusIntervalUs > 0) {
52 const qint64 intervalMs = _deviceAttitudeStatusIntervalUs / 1000;
53 if ((nowMs - _deviceAttitudeStatusLastSentMs) >= intervalMs) {
55 if (!_manualControl) {
57 const qint64 secondsSinceEpoch = nowMs / 1000;
58 _pitch = 10.0f * qSin(secondsSinceEpoch * 0.1);
59 _yaw = 15.0f * qCos(secondsSinceEpoch * 0.15);
62 _sendGimbalDeviceAttitudeStatus();
63 _deviceAttitudeStatusLastSentMs = nowMs;
70 if (msg.msgid != MAVLINK_MSG_ID_COMMAND_LONG) {
75 mavlink_msg_command_long_decode(&msg, &request);
78 switch (request.command) {
79 case MAV_CMD_SET_MESSAGE_INTERVAL:
80 if (_handleSetMessageInterval(request)) {
81 _sendCommandAck(request.command, MAV_RESULT_ACCEPTED);
86 case MAV_CMD_REQUEST_MESSAGE:
87 if (_handleRequestMessage(request)) {
88 _sendCommandAck(request.command, MAV_RESULT_ACCEPTED);
93 case MAV_CMD_DO_GIMBAL_MANAGER_PITCHYAW:
94 if (_handleGimbalManagerPitchYaw(request)) {
95 _sendCommandAck(request.command, MAV_RESULT_ACCEPTED);
98 _sendCommandAck(request.command, MAV_RESULT_DENIED);
101 case MAV_CMD_DO_GIMBAL_MANAGER_CONFIGURE:
102 if (_handleGimbalManagerConfigure(request)) {
103 _sendCommandAck(request.command, MAV_RESULT_ACCEPTED);
106 _sendCommandAck(request.command, MAV_RESULT_DENIED);
114void MockLinkGimbal::_sendCommandAck(uint16_t command, uint8_t result)
117 qCDebug(MockLinkGimbalLog) <<
"Sending command ACK -" << QString(
"%1(%2)").arg(commandName).arg(command) <<
"result:" << (result == MAV_RESULT_ACCEPTED ?
"ACCEPTED" : result == MAV_RESULT_DENIED ?
"DENIED" : QString::number(result));
120 (void) mavlink_msg_command_ack_pack_chan(
122 MAV_COMP_ID_AUTOPILOT1,
137 const int msgId =
static_cast<int>(request.param1);
138 const int intervalUs =
static_cast<int>(request.param2);
139 const mavlink_message_info_t* info = mavlink_get_message_info_by_id(
static_cast<uint32_t
>(msgId));
140 QString msgName = info ? info->name : QString::number(msgId);
142 qCDebug(MockLinkGimbalLog) <<
"SET_MESSAGE_INTERVAL -" << QString(
"%1(%2)").arg(msgName).arg(msgId) <<
"intervalUs:" << intervalUs;
148 int effectiveInterval = intervalUs;
149 if (intervalUs == 0) {
150 effectiveInterval = kDefaultIntervalUs;
151 }
else if (intervalUs < -1) {
158 QMutexLocker locker(&_stateMutex);
159 if (msgId == MAVLINK_MSG_ID_GIMBAL_MANAGER_STATUS) {
160 _managerStatusIntervalUs = effectiveInterval;
161 qCDebug(MockLinkGimbalLog) << msgName <<
"interval set to" << effectiveInterval <<
"us";
163 }
else if (msgId == MAVLINK_MSG_ID_GIMBAL_DEVICE_ATTITUDE_STATUS) {
164 _deviceAttitudeStatusIntervalUs = effectiveInterval;
165 qCDebug(MockLinkGimbalLog) << msgName <<
"interval set to" << effectiveInterval <<
"us";
173 const int msgId =
static_cast<int>(request.param1);
174 const mavlink_message_info_t* info = mavlink_get_message_info_by_id(
static_cast<uint32_t
>(msgId));
175 QString msgName = info ? info->name : QString::number(msgId);
177 if (msgId == MAVLINK_MSG_ID_GIMBAL_MANAGER_INFORMATION) {
178 qCDebug(MockLinkGimbalLog) <<
"REQUEST_MESSAGE -" << QString(
"%1(%2)").arg(msgName).arg(msgId);
179 _sendGimbalManagerInformation();
195 const float requestedPitch = request.param1;
196 const float requestedYaw = request.param2;
197 const uint32_t flags =
static_cast<uint32_t
>(request.param5);
199 qCDebug(MockLinkGimbalLog) <<
"DO_GIMBAL_MANAGER_PITCHYAW - pitch:" << requestedPitch <<
"yaw:" << requestedYaw <<
"flags:" << flags;
202 const bool updatePitch = !qIsNaN(requestedPitch);
203 const bool updateYaw = !qIsNaN(requestedYaw);
205 if (!updatePitch && !updateYaw) {
206 qCDebug(MockLinkGimbalLog) <<
"DO_GIMBAL_MANAGER_PITCHYAW - no valid pitch/yaw requested (both NaN)";
213 QMutexLocker locker(&_stateMutex);
215 if (updatePitch && _hasPitchAxis) {
216 _pitch = qBound(-45.0f, requestedPitch, 45.0f);
217 _manualControl =
true;
220 if (updateYaw && _hasYawAxis) {
222 if (flags & GIMBAL_MANAGER_FLAGS_YAW_LOCK) {
224 _yaw = qBound(-180.0f, requestedYaw, 180.0f);
227 _yaw = qBound(-180.0f, requestedYaw, 180.0f);
229 _manualControl =
true;
232 qCDebug(MockLinkGimbalLog) <<
"Gimbal commanded to pitch:" << _pitch <<
"yaw:" << _yaw <<
"- switched to manual control";
244 const uint8_t sysidPrimary =
static_cast<uint8_t
>(request.param1);
245 const uint8_t compidPrimary =
static_cast<uint8_t
>(request.param2);
246 const uint8_t sysidSecondary =
static_cast<uint8_t
>(request.param3);
247 const uint8_t compidSecondary =
static_cast<uint8_t
>(request.param4);
249 if (sysidPrimary > 0) {
250 _gimbalManagerSysidPrimary = sysidPrimary;
252 if (compidPrimary > 0) {
253 _gimbalManagerCompidPrimary = compidPrimary;
255 if (sysidSecondary > 0) {
256 _gimbalManagerSysidSecondary = sysidSecondary;
258 if (compidSecondary > 0) {
259 _gimbalManagerCompidSecondary = compidSecondary;
262 qCDebug(MockLinkGimbalLog) <<
"Gimbal manager configured - Primary:" << _gimbalManagerSysidPrimary
263 <<
"/" << _gimbalManagerCompidPrimary
264 <<
"Secondary:" << _gimbalManagerSysidSecondary
265 <<
"/" << _gimbalManagerCompidSecondary;
269void MockLinkGimbal::_sendGimbalManagerStatus()
271 qCDebug(MockLinkGimbalLog) <<
"Sending GIMBAL_MANAGER_STATUS";
274 (void) mavlink_msg_gimbal_manager_status_pack_chan(
276 MAV_COMP_ID_AUTOPILOT1,
282 _gimbalManagerSysidPrimary,
283 _gimbalManagerCompidPrimary,
284 _gimbalManagerSysidSecondary,
285 _gimbalManagerCompidSecondary);
289void MockLinkGimbal::_sendGimbalDeviceAttitudeStatus()
291 qCDebug(MockLinkGimbalLog) <<
"Sending GIMBAL_DEVICE_ATTITUDE_STATUS - pitch:" << _pitch <<
"yaw:" << _yaw <<
"manual:" << _manualControl;
294 const float rollRad = qDegreesToRadians(_roll);
295 const float pitchRad = qDegreesToRadians(_pitch);
296 const float yawRad = qDegreesToRadians(_yaw);
298 const float cy = qCos(yawRad * 0.5f);
299 const float sy = qSin(yawRad * 0.5f);
300 const float cp = qCos(pitchRad * 0.5f);
301 const float sp = qSin(pitchRad * 0.5f);
302 const float cr = qCos(rollRad * 0.5f);
303 const float sr = qSin(rollRad * 0.5f);
306 q[0] = cr * cp * cy + sr * sp * sy;
307 q[1] = sr * cp * cy - cr * sp * sy;
308 q[2] = cr * sp * cy + sr * cp * sy;
309 q[3] = cr * cp * sy - sr * sp * cy;
312 (void) mavlink_msg_gimbal_device_attitude_status_pack_chan(
319 GIMBAL_DEVICE_FLAGS_NEUTRAL | GIMBAL_DEVICE_FLAGS_ROLL_LOCK | GIMBAL_DEVICE_FLAGS_PITCH_LOCK,
328void MockLinkGimbal::_sendGimbalManagerInformation()
331 uint32_t capFlags = 0;
332 if (_hasRollAxis) capFlags |= GIMBAL_MANAGER_CAP_FLAGS_HAS_ROLL_AXIS;
333 if (_hasPitchAxis) capFlags |= GIMBAL_MANAGER_CAP_FLAGS_HAS_PITCH_AXIS;
334 if (_hasYawAxis) capFlags |= GIMBAL_MANAGER_CAP_FLAGS_HAS_YAW_AXIS;
335 if (_hasYawFollow) capFlags |= GIMBAL_MANAGER_CAP_FLAGS_HAS_YAW_FOLLOW;
336 if (_hasYawLock) capFlags |= GIMBAL_MANAGER_CAP_FLAGS_HAS_YAW_LOCK;
337 if (_hasRetract) capFlags |= GIMBAL_MANAGER_CAP_FLAGS_HAS_RETRACT;
338 if (_hasNeutral) capFlags |= GIMBAL_MANAGER_CAP_FLAGS_HAS_NEUTRAL;
340 qCDebug(MockLinkGimbalLog) <<
"Sending GIMBAL_MANAGER_INFORMATION - capFlags:" << QString::number(capFlags, 16);
343 (void) mavlink_msg_gimbal_manager_information_pack_chan(
345 MAV_COMP_ID_AUTOPILOT1,
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
struct __mavlink_command_long_t mavlink_command_long_t
uint8_t mavlinkChannel() const
static MissionCommandTree * instance()
QString rawName(MAV_CMD command) const
Returns the raw name for the specified command.
Simulates MAVLink Gimbal Manager Protocol for MockLink.
void run1HzTasks()
Send periodic gimbal status messages (call from 1Hz tasks)
bool handleMavlinkMessage(const mavlink_message_t &msg)
void respondWithMavlinkMessage(const mavlink_message_t &msg)
Sends the specified mavlink message to QGC.