█ 【无人机学习之QGroundControl】android端App初解4-遥控器通道
█ 系列文章目录
提示:这里是收集了无人机的相关文章
- 【无人机学习】无人机基础知识
- 【无人机学习】Mission Planner(pc端)和QGroundControl(android端)
- 【无人机学习之DroidPlanner】FlightActivity的启动过程
- 【无人机学习之DroidPlanner】msg_heartbeat心跳处理(含MAVLink协议)
- 【无人机学习之DroidPlanner】msg_sys_status系统状态
- 【无人机学习之QGroundControl】android端App初解1
- 【无人机学习之QGroundControl】android端App初解2-APMPowerComponent(含QML的介绍)
- 【无人机学习之QGroundControl】android端App初解3-ParameterEditorController
- 【无人机学习之QGroundControl】android端App初解4-遥控器通道
█ 文章目录
█ 读前说明
- 本文通过学习别人写demo,学习一些课件,参考一些博客,学习相关知识,如有涉及侵权请告知
- 本文可能只简单罗列了一些相关的代码实现过程,复制了一些大神的高论,如内容有误请自行辨别
- 涉及到的逻辑以及说明可能只做了简单的介绍,主要当做笔记,了解过程而已,如有不同看法,欢迎下方评论
- 本文源码:https://github.com/mavlink/qgroundcontrol
- 本文UI:https://github.com/mavlink/qgroundcontrol/blob/master/src/ui
- 本文的硬件测试是APM而不是PX4,因此代码走向都是走向APM方向
- QGC中UI设计的主要模式是用QML编写的UI页面,多次与用C ++编写的定制“控制器”进行通信。类似MVC的设计模式。
- QGC最新源码版本是v4.1.1(2021年1月28),使用QtCreator版本是5.12.6,语言是c++ 。
█ 界面分析
1.遥控器界面
The Radio Component is used to setup which channels on your RC Transmitter you will use for each vehicle control such as Roll, Pitch, Yaw and Throttle. ""It also allows you to assign switches and dials to the various flight modes. "
"Prior to flight you must also calibrate the extents for all of your channels."
"Before calibrating you should zero all your trims and subtrims. Click Ok to start Calibration."
2.MissionPlanner界面参考
MAVLINK_MSG_ID_RC_CHANNELS - sysid:100 compid:1 time_boot_ms:555394
chan1_raw:1500 chan2_raw:1500 chan3_raw:1500 chan4_raw:1500
chan5_raw:1050 chan6_raw:1950 chan7_raw:1050 chan8_raw:1050
chan9_raw:1050 chan10_raw:1050 chan11_raw:1950 chan12_raw:1950
chan13_raw:874 chan14_raw:874 chan15_raw:874 chan16_raw:874
chan17_raw:0 chan18_raw:0 chancount:16 rssi:0
3. 相关文件
RadioComponent.qml文件在qgroundcontrol-master\src\AutoPilotPlugins\Common\RadioComponent.qml
)
- 遥控器
- RC#通道
4. RadioComponent.qml
- Attitude Controls 姿态控制
Column {
width: parent.width
spacing: 5
QGCLabel { text: qsTr("Attitude Controls") }
Item {
width: parent.width
height: globals.defaultTextHeight * 2
QGCLabel {
id: rollLabel
width: globals.defaultTextWidth * 10
text: qsTr("Roll")
}
Loader {
id: rollLoader
anchors.left: rollLabel.right
anchors.right: parent.right
height: globals.defaultTextHeight
width: 100
sourceComponent: channelMonitorDisplayComponent
property bool mapped: controller.rollChannelMapped
property bool reversed: controller.rollChannelReversed
}
Connections {
target: controller
onRollChannelRCValueChanged: rollLoader.item.rcValue = rcValue
}
}
。。。。。。
// Command Buttons
Row {
spacing: 10
QGCButton {
id: skipButton
text: qsTr("Skip")
onClicked: controller.skipButtonClicked()
}
QGCButton {
id: cancelButton
text: qsTr("Cancel")
onClicked: controller.cancelButtonClicked()
}
QGCButton {
id: nextButton
primary: true
text: qsTr("Calibrate")
onClicked: {
if (text === qsTr("Calibrate")) {
mainWindow.showComponentDialog(zeroTrimsDialogComponent, dialogTitle, mainWindow.showDialogDefaultWidth, StandardButton.Ok | StandardButton.Cancel)
} else {
controller.nextButtonClicked()
}
}
}
} // Row - Buttons
}// Column - Attitude Control labels
- Additional Radio setup 其他遥控器设置
// Status Text
QGCLabel { text: qsTr("Additional Radio setup:") }
GridLayout {
id: switchSettingsGrid
anchors.left: parent.left
anchors.right: parent.right
columns: 2
columnSpacing: ScreenTools.defaultFontPixelWidth
Repeater {
model: QGroundControl.multiVehicleManager.activeVehicle.px4Firmware ?
(QGroundControl.multiVehicleManager.activeVehicle.multiRotor ?
[ "RC_MAP_AUX1", "RC_MAP_AUX2", "RC_MAP_PARAM1", "RC_MAP_PARAM2", "RC_MAP_PARAM3"] :
[ "RC_MAP_FLAPS", "RC_MAP_AUX1", "RC_MAP_AUX2", "RC_MAP_PARAM1", "RC_MAP_PARAM2", "RC_MAP_PARAM3"]) :
0
RowLayout {
Layout.fillWidth: true
property Fact fact: controller.getParameterFact(-1, modelData)
QGCLabel {
Layout.fillWidth: true
text: fact.shortDescription
}
FactComboBox {
width: ScreenTools.defaultFontPixelWidth * 15
fact: parent.fact
indexModel: false
}
}
}
}
RowLayout {
QGCButton {
id: bindButton
text: qsTr("Spektrum Bind")
onClicked: mainWindow.showComponentDialog(spektrumBindDialogComponent, dialogTitle, mainWindow.showDialogDefaultWidth, StandardButton.Ok | StandardButton.Cancel)
}
QGCButton {
text: qsTr("Copy Trims")
onClicked: mainWindow.showComponentDialog(copyTrimsDialogComponent, dialogTitle, mainWindow.showDialogDefaultWidth, StandardButton.Ok | StandardButton.Cancel)
}
}
- channelMonitor 通道监控bar
// Right side column
Column {
id: rightColumn
anchors.top: parent.top
anchors.right: parent.right
width: ScreenTools.defaultFontPixelWidth * 40
spacing: ScreenTools.defaultFontPixelHeight / 2
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCRadioButton {
text: qsTr("Mode 1")
checked: controller.transmitterMode == 1
onClicked: controller.transmitterMode = 1
}
QGCRadioButton {
text: qsTr("Mode 2")
checked: controller.transmitterMode == 2
onClicked: controller.transmitterMode = 2
}
}
Image {
width: parent.width
fillMode: Image.PreserveAspectFit
smooth: true
source: controller.imageHelp
}
RCChannelMonitor {
width: parent.width
twoColumn: true
}
} // Column - Right Column
5. APMRadioComponentSummary.qml
- APMRadioComponentSummary.qml 姿态控制
// 对应的配置通道
property Fact mapRollFact: controller.getParameterFact(-1, "RCMAP_ROLL")
property Fact mapPitchFact: controller.getParameterFact(-1, "RCMAP_PITCH")
property Fact mapYawFact: controller.getParameterFact(-1, "RCMAP_YAW")
property Fact mapThrottleFact: controller.getParameterFact(-1, "RCMAP_THROTTLE")
Column {
anchors.fill: parent
VehicleSummaryRow {
labelText: qsTr("Roll")
valueText: mapRollFact.value == 0 ? qsTr("Setup required") : qsTr("Channel %1").arg(mapRollFact.valueString)
}
VehicleSummaryRow {
labelText: qsTr("Pitch")
valueText: mapPitchFact.value == 0 ? qsTr("Setup required") : qsTr("Channel %1").arg(mapPitchFact.valueString)
}
......
}
- APMRadioComponent.cc:配置两个qml
First check for all attitude controls mapped
Next check RC#_MIN/MAX/TRIM all at defaults
QUrl APMRadioComponent::setupSource(void) const
{
return QUrl::fromUserInput(QStringLiteral("qrc:/qml/RadioComponent.qml"));
}
QUrl APMRadioComponent::summaryQmlSource(void) const
{
return QUrl::fromUserInput(QStringLiteral("qrc:/qml/APMRadioComponentSummary.qml"));
}
6. RCChannelMonitor.qml
- RCChannelMonitor
Item {
id: _root
height: monitorColumn.height
property bool twoColumn: false
readonly property int _pwmMin: 800
readonly property int _pwmMax: 2200
readonly property int _pwmRange: _pwmMax - _pwmMin
RCChannelMonitorController {
id: controller
}
// Live channel monitor control component
Component {
id: channelMonitorDisplayComponent
} // Component - channelMonitorDisplayComponent
GridLayout {
id: monitorColumn
width: parent.width
columns: twoColumn ? 2 : 1
QGCLabel {
Layout.columnSpan: parent.columns
text: "Channel Monitor"
}
Connections {
target: controller
onChannelRCValueChanged: {
if (channelMonitorRepeater.itemAt(channel)) {
channelMonitorRepeater.itemAt(channel).loader.item.rcValue = rcValue
}
}
}
Repeater {
id: channelMonitorRepeater
model: controller.channelCount
RowLayout {
// Need this to get to loader from Connections above
property Item loader: theLoader
QGCLabel {
id: channelLabel
text: modelData + 1
}
Loader {
id: theLoader
Layout.fillWidth: true
//height: ScreenTools.defaultFontPixelHeight
//width: parent.width - anchors.leftMargin - ScreenTools.defaultFontPixelWidth
sourceComponent: channelMonitorDisplayComponent
property bool mapped: true
readonly property bool reversed: false
}
}
}
}
}
- channelMonitor 通道监控bar
// Live channel monitor control component
Component {
id: channelMonitorDisplayComponent
Item {
property int rcValue: 1500
property int __lastRcValue: 1500
readonly property int __rcValueMaxJitter: 2
property color __barColor: qgcPal.windowShade
readonly property int _pwmMin: 800
readonly property int _pwmMax: 2200
readonly property int _pwmRange: _pwmMax - _pwmMin
// Bar
Rectangle {
id: bar
anchors.verticalCenter: parent.verticalCenter
width: parent.width
height: parent.height / 2
color: __barColor
}
// Center point
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
width: globals.defaultTextWidth / 2
height: parent.height
color: qgcPal.window
}
// Indicator
Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: parent.height * 0.75
height: width
radius: width / 2
color: qgcPal.text
visible: mapped
x: (((reversed ? _pwmMax - rcValue : rcValue - _pwmMin) / _pwmRange) * parent.width) - (width / 2)
}
QGCLabel {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: qsTr("Not Mapped")
visible: !mapped
}
ColorAnimation {
id: barAnimation
target: bar
property: "color"
from: "yellow"
to: __barColor
duration: 1500
}
}
} // Component - channelMonitorDisplayComponent
█ mavlink协议
1.消息协议格式
- RC_CHANNELS_RAW ( #35 ):接收到的 RC 通道的 RAW 值
The RAW values of the RC channels received. The standard PPM modulation is as follows: 1000 microseconds: 0%, 2000 microseconds: 100%. A value of UINT16_MAX implies the channel is unused. Individual receivers/transmitters might violate this specification.
Field Name | Type | Units | Description |
---|---|---|---|
time_boot_ms | uint32_t | ms | 时间戳(自系统启动以来的时间) |
port | uint8_t | 伺服输出端口(8 个输出组 = 1 个端口); 在 Pixhawk 上:0 = MAIN,1 = AUX。 | |
chan1_raw | uint16_t | us | RC channel 1 value. |
chan2_raw | uint16_t | us | RC channel 2 value. |
chan3_raw | uint16_t | us | RC channel 3 value. |
chan4_raw | uint16_t | us | RC channel 4 value. |
chan5_raw | uint16_t | us | RC channel 5 value. |
chan6_raw | uint16_t | us | RC channel 6 value. |
chan7_raw | uint16_t | us | RC channel 7 value. |
chan8_raw | uint16_t | us | RC channel 8 value. |
rssi | uint8_t | 接收信号强度,取值范围:[0-254],UINT8_MAX:无效/未知。 |
- SERVO_OUTPUT_RAW ( #36 ): 伺服输出的 RAW 值(来自遥控器的 RC 输入,使用 RC_CHANNELS 消息)
Superseded by ACTUATOR_OUTPUT_STATUS. The RAW values of the servo outputs (for RC input from the remote, use the RC_CHANNELS messages). The standard PPM modulation is as follows: 1000 microseconds: 0%, 2000 microseconds: 100%.
- RC_CHANNELS ( #65 ):接收到的 RC 通道的 PPM 值
The PPM values of the RC channels received. The standard PPM modulation is as follows: 1000 microseconds: 0%, 2000 microseconds: 100%. A value of UINT16_MAX implies the channel is unused. Individual receivers/transmitters might violate this specification.
Field Name | Type | Units | Description |
---|---|---|---|
time_boot_ms | uint32_t | ms | 时间戳(自系统启动以来的时间) |
chancount | uint8_t | 正在接收的 RC 通道总数。 这可以大于 18,表示有更多频道可用但未在此消息中给出 | |
chan1_raw | uint16_t | us | RC channel 1 value. |
chan2_raw | uint16_t | us | RC channel 2 value. |
chan3_raw | uint16_t | us | RC channel 3 value. |
chan4_raw | uint16_t | us | RC channel 4 value. |
chan5_raw | uint16_t | us | RC channel 5 value. |
chan6_raw | uint16_t | us | RC channel 6 value. |
chan7_raw | uint16_t | us | RC channel 7 value. |
chan8_raw | uint16_t | us | RC channel 8 value. |
chan9_raw | uint16_t | us | RC channel 9 value. |
chan10_raw | uint16_t | us | RC channel 10 value. |
chan11_raw | uint16_t | us | RC channel 11 value. |
chan12_raw | uint16_t | us | RC channel 12 value. |
chan13_raw | uint16_t | us | RC channel 13 value. |
chan14_raw | uint16_t | us | RC channel 14 value. |
chan15_raw | uint16_t | us | RC channel 15 value. |
chan16_raw | uint16_t | us | RC channel 16 value. |
chan17_raw | uint16_t | us | RC channel 17 value. |
chan18_raw | uint16_t | us | RC channel 18 value. |
rssi | uint8_t | 接收信号强度,取值范围:[0-254],UINT8_MAX:无效/未知。 |
2.生成的Mavlink
- msg_rc_channels_raw
public class msg_rc_channels_raw extends MAVLinkMessage {
public static final int MAVLINK_MSG_ID_RC_CHANNELS_RAW = 35;
public static final int MAVLINK_MSG_LENGTH = 22;
private static final long serialVersionUID = 35L;
public long time_boot_ms;
public int chan1_raw;
public int chan2_raw;
public int chan3_raw;
public int chan4_raw;
public int chan5_raw;
public int chan6_raw;
public int chan7_raw;
public int chan8_raw;
public short port;
public short rssi;
}
- msg_rc_channels
public class msg_rc_channels extends MAVLinkMessage {
public static final int MAVLINK_MSG_ID_RC_CHANNELS = 65;
public static final int MAVLINK_MSG_LENGTH = 42;
private static final long serialVersionUID = 65L;
public long time_boot_ms;
public int chan1_raw;
public int chan2_raw;
public int chan3_raw;
public int chan4_raw;
public int chan5_raw;
public int chan6_raw;
public int chan7_raw;
public int chan8_raw;
public int chan9_raw;
public int chan10_raw;
public int chan11_raw;
public int chan12_raw;
public int chan13_raw;
public int chan14_raw;
public int chan15_raw;
public int chan16_raw;
public int chan17_raw;
public int chan18_raw;
public short chancount;
public short rssi;
}
█ 代码分析
- 创建APMRadioComponent
const QVariantList& APMAutoPilotPlugin::vehicleComponents(void)
{
if (_components.count() == 0 && !_incorrectParameterVersion) {
if (_vehicle->parameterManager()->parametersReady()) {
。。。。。。
if ( _vehicle->supportsRadio() ) {
_radioComponent = new APMRadioComponent(_vehicle, this);
_radioComponent->setupTriggerSignals();
_components.append(QVariant::fromValue((VehicleComponent*)_radioComponent));
}
。。。。。。
}
}
}
- RC#通道:channel monitor( 没有将16路全部展示)
一共有16 个(RC1-RC16 )通道,每个通道有6个参数可设置:
- 姿态控制:Attitude Controls
“RCMAP_ROLL”、“RCMAP_PITCH”、“RCMAP_YAW”、RCMAP_THROTTLE"映射到上面16个通道中的四个(正常为前4个通道):
-
取值范围
| 参数 |RC#_MIN|RC#_MAX|RC#_TRIM|
|–|–|–|–|
|QGC| 800|2200|1500|
|MP| 1000|3000|1500|
其实遥控器校准就是 16个RC#_TRIM 值显示 -
mavlinkMessage:接收到消息->rcChannelsChanged
qgroundcontrol-master\src\Vehicle\Vehicle.cc
void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t message)
{
。。。。。。
// Give the plugin a change to adjust the message contents
if (!_firmwarePlugin->adjustIncomingMavlinkMessage(this, &message)) {// APMFirmwarePlugin
return;
}
。。。。。。
switch (message.msgid) {
case MAVLINK_MSG_ID_HOME_POSITION:
_handleHomePosition(message);
break;
case MAVLINK_MSG_ID_HEARTBEAT:
_handleHeartbeat(message);
break;
case MAVLINK_MSG_ID_RADIO_STATUS:
_handleRadioStatus(message);
break;
case MAVLINK_MSG_ID_RC_CHANNELS:
_handleRCChannels(message);
break;
。。。。。。
}
// This must be emitted after the vehicle processes the message. This way the vehicle state is up to date when anyone else
// does processing.
emit mavlinkMessageReceived(message);
_uas->receiveMessage(message);
}
void Vehicle::_handleRCChannels(mavlink_message_t& message)
{
mavlink_rc_channels_t channels;
mavlink_msg_rc_channels_decode(&message, &channels);
uint16_t* _rgChannelvalues[cMaxRcChannels] = {
&channels.chan1_raw,
&channels.chan2_raw,
&channels.chan3_raw,
&channels.chan4_raw,
&channels.chan5_raw,
&channels.chan6_raw,
&channels.chan7_raw,
&channels.chan8_raw,
&channels.chan9_raw,
&channels.chan10_raw,
&channels.chan11_raw,
&channels.chan12_raw,
&channels.chan13_raw,
&channels.chan14_raw,
&channels.chan15_raw,
&channels.chan16_raw,
&channels.chan17_raw,
&channels.chan18_raw,
};
int pwmValues[cMaxRcChannels];
for (int i=0; i<cMaxRcChannels; i++) {
uint16_t channelValue = *_rgChannelvalues[i];
if (i < channels.chancount) {
pwmValues[i] = channelValue == UINT16_MAX ? -1 : channelValue;
} else {
pwmValues[i] = -1;
}
}
emit remoteControlRSSIChanged(channels.rssi);
emit rcChannelsChanged(channels.chancount, pwmValues);// #########重点
}
qgroundcontrol-master\src\FirmwarePlugin\APM\APMFirmwarePlugin.cc
/// This is the base class for all stack specific APM firmware plugins
class APMFirmwarePlugin : public FirmwarePlugin{};
/*bool APMFirmwarePlugin::adjustIncomingMavlinkMessage(Vehicle* vehicle, mavlink_message_t* message)
{
if (message->msgid == MAVLINK_MSG_ID_HEARTBEAT) {
// We need to look at all heartbeats that go by from any component
_handleIncomingHeartbeat(vehicle, message);
return true;
}
// Only translate messages which come from ArduPilot code. All other components are expected to follow current mavlink spec.
if (_ardupilotComponentMap[vehicle->id()][message->compid]) {
switch (message->msgid) {
case MAVLINK_MSG_ID_PARAM_VALUE:
_handleIncomingParamValue(vehicle, message);
break;
case MAVLINK_MSG_ID_STATUSTEXT:
return _handleIncomingStatusText(vehicle, message);
case MAVLINK_MSG_ID_RC_CHANNELS:
_handleRCChannels(vehicle, message);
break;
case MAVLINK_MSG_ID_RC_CHANNELS_RAW:
_handleRCChannelsRaw(vehicle, message);
break;
}
}
return true;
}*/
/*void APMFirmwarePlugin::_handleRCChannels(Vehicle* vehicle, mavlink_message_t* message)
{
WeakLinkInterfacePtr weakLink = vehicle->vehicleLinkManager()->primaryLink();
if (!weakLink.expired()) {
mavlink_rc_channels_t channels;
SharedLinkInterfacePtr sharedLink = weakLink.lock();
mavlink_msg_rc_channels_decode(message, &channels);
//-- Ardupilot uses 0-255 to indicate 0-100% where QGC expects 0-100
if(channels.rssi) {
channels.rssi = static_cast<uint8_t>(static_cast<double>(channels.rssi) / 255.0 * 100.0);
}
MAVLinkProtocol* mavlink = qgcApp()->toolbox()->mavlinkProtocol();
mavlink_msg_rc_channels_encode_chan(
static_cast<uint8_t>(mavlink->getSystemId()),
static_cast<uint8_t>(mavlink->getComponentId()),
sharedLink->mavlinkChannel(),
message,
&channels);
}
}*/
- 更新ui: RadioComponentController
RadioComponentController::RadioComponentController(void)
: _currentStep(-1)
, _transmitterMode(2)
, _chanCount(0)
, _rcCalState(rcCalStateChannelWait)
{
。。。。。。
connect(_vehicle, &Vehicle::rcChannelsChanged, this,
&RadioComponentController::_rcChannelsChanged);// #########重点
}
/// Connected to Vehicle::rcChannelsChanged signal
void RadioComponentController::_rcChannelsChanged(int channelCount, int pwmValues[Vehicle::cMaxRcChannels])
{
for (int channel=0; channel<channelCount; channel++) {
int channelValue = pwmValues[channel];
if (channelValue != -1) {
qCDebug(RadioComponentControllerVerboseLog) << "Raw value" << channel << channelValue;
_rcRawValue[channel] = channelValue;
emit channelRCValueChanged(channel, channelValue);// #########重点
// Signal attitude rc values to Qml if mapped
if (_rgChannelInfo[channel].function != rcCalFunctionMax) {
switch (_rgChannelInfo[channel].function) {
case rcCalFunctionRoll:
emit rollChannelRCValueChanged(channelValue);// #########重点
break;
case rcCalFunctionPitch:
emit pitchChannelRCValueChanged(channelValue);// #########重点
break;
......
}
}
......
}
}
}
\qgroundcontrol-master\src\AutoPilotPlugins\Common\RadioComponent.qml
Item {
width: parent.width
height: globals.defaultTextHeight * 2
QGCLabel {
id: rollLabel
width: globals.defaultTextWidth * 10
text: qsTr("Roll")
}
Loader {
id: rollLoader
anchors.left: rollLabel.right
anchors.right: parent.right
height: globals.defaultTextHeight
width: 100
sourceComponent: channelMonitorDisplayComponent
property bool mapped: controller.rollChannelMapped
property bool reversed: controller.rollChannelReversed
}
Connections {
target: controller
onRollChannelRCValueChanged: rollLoader.item.rcValue = rcValue// #########重点
}
}
qgroundcontrol-master\src\QmlControls\RCChannelMonitor.qml
GridLayout {
id: monitorColumn
width: parent.width
columns: twoColumn ? 2 : 1
QGCLabel {
Layout.columnSpan: parent.columns
text: "Channel Monitor"
}
Connections {
target: controller
onChannelRCValueChanged: {
if (channelMonitorRepeater.itemAt(channel)) {
channelMonitorRepeater.itemAt(channel).loader.item.rcValue = rcValue// #########重点
}
}
}
Repeater {
id: channelMonitorRepeater
model: controller.channelCount
RowLayout {
// Need this to get to loader from Connections above
property Item loader: theLoader
QGCLabel {
id: channelLabel
text: modelData + 1
}
Loader {
id: theLoader
Layout.fillWidth: true
//height: ScreenTools.defaultFontPixelHeight
//width: parent.width - anchors.leftMargin - ScreenTools.defaultFontPixelWidth
sourceComponent: channelMonitorDisplayComponent
property bool mapped: true
readonly property bool reversed: false
}
}
}
}
█ 代码分析(MP版)
- UI界面:…\GCSViews\ConfigurationView\ConfigRadioInput.cs
- 绑定数据
qgroundcontrol-master\src\Vehicle\Vehicle.cc
//setup bindings
chroll = (int)(float)MainV2.comPort.MAV.param["RCMAP_ROLL"];
chpitch = (int)(float)MainV2.comPort.MAV.param["RCMAP_PITCH"];
chthro = (int)(float)MainV2.comPort.MAV.param["RCMAP_THROTTLE"];
chyaw = (int)(float)MainV2.comPort.MAV.param["RCMAP_YAW"];
BARroll.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch" + chroll + "in", true));
BARpitch.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch" + chpitch + "in", true));
BARthrottle.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch" + chthro + "in", true));
BARyaw.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch" + chyaw + "in", true));
BAR5.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch5in", true));
BAR6.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch6in", true));
BAR7.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch7in", true));
BAR8.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch8in", true));
BAR9.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch9in", true));
BAR10.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch10in", true));
BAR11.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch11in", true));
BAR12.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch12in", true));
BAR13.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch13in", true));
BAR14.DataBindings.Add(new Binding("Value", currentStateBindingSource, "ch14in", true));
- 创建定时更新
private readonly Timer _timer = new Timer();
// setup rc update
_timer.Tick += timer_Tick;
_timer.Enabled = true;
_timer.Interval = 100;
_timer.Start();
private void timer_Tick(object sender, EventArgs e) {
// update all linked controls - 10hz
try {
MainV2.comPort.MAV.cs.UpdateCurrentSettings(currentStateBindingSource.UpdateDataSource(MainV2.comPort.MAV.cs));
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}
- 数据更新:…\ExtLibs\ArduPilot\CurrentState.cs
namespace MissionPlanner
{
public class CurrentState : ICloneable, IDisposable
{
public void UpdateCurrentSettings(Action<CurrentState> bs)
{
if (DateTime.Now > lastupdate.AddMilliseconds(50) || updatenow) // 20 hz
{
lastupdate = DateTime.Now;
。。。。。。
// re-request streams
if (!(lastdata.AddSeconds(8) > DateTime.Now) && mavinterface.BaseStream != null &&
mavinterface.BaseStream.IsOpen)
{
try
{
mavinterface.requestDatastream(MAVLink.MAV_DATA_STREAM.EXTENDED_STATUS, MAV.cs.ratestatus,
MAV.sysid, MAV.compid); // mode
mavinterface.requestDatastream(MAVLink.MAV_DATA_STREAM.POSITION, MAV.cs.rateposition,
MAV.sysid, MAV.compid); // request gps
mavinterface.requestDatastream(MAVLink.MAV_DATA_STREAM.EXTRA1, MAV.cs.rateattitude,
MAV.sysid, MAV.compid); // request attitude
mavinterface.requestDatastream(MAVLink.MAV_DATA_STREAM.EXTRA2, MAV.cs.rateattitude,
MAV.sysid, MAV.compid); // request vfr
mavinterface.requestDatastream(MAVLink.MAV_DATA_STREAM.EXTRA3, MAV.cs.ratesensors,
MAV.sysid,
MAV.compid); // request extra stuff - tridge
mavinterface.requestDatastream(MAVLink.MAV_DATA_STREAM.RAW_SENSORS, MAV.cs.ratesensors,
MAV.sysid, MAV.compid); // request raw sensor
mavinterface.requestDatastream(MAVLink.MAV_DATA_STREAM.RC_CHANNELS, MAV.cs.raterc,
MAV.sysid,
MAV.compid); // request rc info
}
catch
{
log.Error("Failed to request rates");
}
lastdata = DateTime.Now.AddSeconds(30); // prevent flooding
}
}
}
}
}
MAVlink数据接收
//radio
[GroupText("RadioIn")] public float ch1in { get; set; }
[GroupText("RadioIn")] public float ch2in { get; set; }
[GroupText("RadioIn")] public float ch3in { get; set; }
[GroupText("RadioIn")] public float ch4in { get; set; }
[GroupText("RadioIn")] public float ch5in { get; set; }
[GroupText("RadioIn")] public float ch6in { get; set; }
[GroupText("RadioIn")] public float ch7in { get; set; }
[GroupText("RadioIn")] public float ch8in { get; set; }
[GroupText("RadioIn")] public float ch9in { get; set; }
[GroupText("RadioIn")] public float ch10in { get; set; }
[GroupText("RadioIn")] public float ch11in { get; set; }
[GroupText("RadioIn")] public float ch12in { get; set; }
[GroupText("RadioIn")] public float ch13in { get; set; }
[GroupText("RadioIn")] public float ch14in { get; set; }
[GroupText("RadioIn")] public float ch15in { get; set; }
[GroupText("RadioIn")] public float ch16in { get; set; }
// motors
[GroupText("RadioOut")] public float ch1out { get; set; }
[GroupText("RadioOut")] public float ch2out { get; set; }
[GroupText("RadioOut")] public float ch3out { get; set; }
[GroupText("RadioOut")] public float ch4out { get; set; }
[GroupText("RadioOut")] public float ch5out { get; set; }
[GroupText("RadioOut")] public float ch6out { get; set; }
[GroupText("RadioOut")] public float ch7out { get; set; }
[GroupText("RadioOut")] public float ch8out { get; set; }
[GroupText("RadioOut")] public float ch9out { get; set; }
[GroupText("RadioOut")] public float ch10out { get; set; }
[GroupText("RadioOut")] public float ch11out { get; set; }
[GroupText("RadioOut")] public float ch12out { get; set; }
[GroupText("RadioOut")] public float ch13out { get; set; }
[GroupText("RadioOut")] public float ch14out { get; set; }
[GroupText("RadioOut")] public float ch15out { get; set; }
[GroupText("RadioOut")] public float ch16out { get; set; }
private void Parent_OnPacketReceived(object sender, MAVLink.MAVLinkMessage mavLinkMessage)
{
if (mavLinkMessage.sysid == parent.sysid && mavLinkMessage.compid == parent.compid
|| mavLinkMessage.msgid == (uint)MAVLink.MAVLINK_MSG_ID.RADIO // propagate the RADIO/RADIO_STATUS message across all devices on this link
|| mavLinkMessage.msgid == (uint)MAVLink.MAVLINK_MSG_ID.RADIO_STATUS)
{
switch (mavLinkMessage.msgid)
{
case (uint)MAVLink.MAVLINK_MSG_ID.RC_CHANNELS_RAW:// RC_CHANNELS_RAW ( #35 )
{
var rcin = mavLinkMessage.ToStructure<MAVLink.mavlink_rc_channels_raw_t>();
ch1in = rcin.chan1_raw;
ch2in = rcin.chan2_raw;
ch3in = rcin.chan3_raw;
ch4in = rcin.chan4_raw;
ch5in = rcin.chan5_raw;
ch6in = rcin.chan6_raw;
ch7in = rcin.chan7_raw;
ch8in = rcin.chan8_raw;
//percent
rxrssi = (int)(rcin.rssi / 255.0 * 100.0);
//MAVLink.packets[(byte)MAVLink.MSG_NAMES.RC_CHANNELS_RAW);
}
break;
case (uint)MAVLink.MAVLINK_MSG_ID.RC_CHANNELS:// RC_CHANNELS ( #65 )
{
var rcin = mavLinkMessage.ToStructure<MAVLink.mavlink_rc_channels_t>();
ch1in = rcin.chan1_raw;
ch2in = rcin.chan2_raw;
ch3in = rcin.chan3_raw;
ch4in = rcin.chan4_raw;
ch5in = rcin.chan5_raw;
ch6in = rcin.chan6_raw;
ch7in = rcin.chan7_raw;
ch8in = rcin.chan8_raw;
ch9in = rcin.chan9_raw;
ch10in = rcin.chan10_raw;
ch11in = rcin.chan11_raw;
ch12in = rcin.chan12_raw;
ch13in = rcin.chan13_raw;
ch14in = rcin.chan14_raw;
ch15in = rcin.chan15_raw;
ch16in = rcin.chan16_raw;
//percent
rxrssi = (int)(rcin.rssi / 255.0 * 100.0);
//MAVLink.packets[(byte)MAVLink.MSG_NAMES.RC_CHANNELS_RAW);
}
break;
case (uint)MAVLink.MAVLINK_MSG_ID.SERVO_OUTPUT_RAW:// SERVO_OUTPUT_RAW ( #36 )
{
var servoout = mavLinkMessage.ToStructure<MAVLink.mavlink_servo_output_raw_t>();
ch1out = servoout.servo1_raw;
ch2out = servoout.servo2_raw;
ch3out = servoout.servo3_raw;
ch4out = servoout.servo4_raw;
ch5out = servoout.servo5_raw;
ch6out = servoout.servo6_raw;
ch7out = servoout.servo7_raw;
ch8out = servoout.servo8_raw;
// mavlink2 extension
ch9out = servoout.servo9_raw;
ch10out = servoout.servo10_raw;
ch11out = servoout.servo11_raw;
ch12out = servoout.servo12_raw;
ch13out = servoout.servo13_raw;
ch14out = servoout.servo14_raw;
ch15out = servoout.servo15_raw;
ch16out = servoout.servo16_raw;
}
break;
}
}
}
█ 相关资料
提示:这里是参考的相关文章
- 消息(常见) · MAVLink 开发者指南 - LOG_REQUEST_LIST ( #117 )
- 2021-11-13 QGC PlanView(任务规划功能) 界面加载顺序
- 2021-12-02 SetupView(设置功能) 界面加载顺序
- 2018-03-05 QGC SettingsView(设置功能) 界面加载顺序_Copy->Paste的博客-CSDN博客
- 2019-01-17 QGC 增加禁飞区显示功能_Copy->Paste的博客-CSDN博客_禁飞区数据
█ 免责声明
博主分享的所有文章内容,部分参考网上教程,引用大神高论,部分亲身实践,记下笔录,内容可能存在诸多不实之处,还望海涵,本内容仅供学习研究使用,切勿用于商业用途,若您是部分内容的作者,不喜欢此内容被分享出来,可联系博主说明相关情况通知删除,感谢您的理解与支持! |
---|
提示:转载请注明出处:
https://blog.csdn.net/ljb568838953/article/details/124264485