增加通讯协议
This commit is contained in:
+157
-9
@@ -1,9 +1,26 @@
|
||||
#include "appcontext.h"
|
||||
#include "udpcommunication.h"
|
||||
#include "mockvehicle.h"
|
||||
#include "car.h"
|
||||
#include <QApplication>
|
||||
#include <QDateTime>
|
||||
|
||||
namespace {
|
||||
|
||||
// 遥控器摇杆满量程 0~4096、中位 2048;取 ±10% 死区,即 1638~2458 视为中立
|
||||
const int kAxisMid = 2048;
|
||||
const int kAxisDead = 410;
|
||||
|
||||
int axisDir(int v)
|
||||
{
|
||||
if (v > kAxisMid + kAxisDead) return +1;
|
||||
if (v < kAxisMid - kAxisDead) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 六个机械臂轴,顺序与 sendArmMove 的轴名一致(见 pages/arm.cpp)
|
||||
const char* const kArmAxes[6] = {"z", "x", "y", "roll", "pitch", "yaw"};
|
||||
|
||||
} // namespace
|
||||
|
||||
AppContext* AppContext::instance()
|
||||
{
|
||||
static AppContext* s = nullptr;
|
||||
@@ -25,18 +42,31 @@ AppContext::AppContext(QObject* parent)
|
||||
if (!m_settings->contains(keyFoamPercent()))m_settings->setValue(keyFoamPercent(), 3);
|
||||
if (!m_settings->contains(keyAirFlow())) m_settings->setValue(keyAirFlow(), 100);
|
||||
if (!m_settings->contains("param/pwd")) m_settings->setValue("param/pwd", "6789");
|
||||
if (!m_settings->contains("param/admin_pwd"))m_settings->setValue("param/admin_pwd", "6789");
|
||||
|
||||
// 通信层(UDP 收包发包)
|
||||
m_comm = new UdpCommunication(&telemetry, this);
|
||||
// 通信层(19 条 CAN 报文经 /dev/ttyS7 收发,见 comm/car.h)
|
||||
m_comm = new CarCommunication(&telemetry, this);
|
||||
|
||||
// 内置模拟车载端(离线演示:回环 UDP 收发)
|
||||
m_vehicle = new MockVehicle(this);
|
||||
// 遥控器(串口 /dev/ttyS5,24 字节二进制帧,见 comm/uart.h)
|
||||
m_rc = new RcCommunication(this);
|
||||
|
||||
// 通信层故障信号 → 写入故障历史
|
||||
connect(m_comm, &UdpCommunication::faultAppended,
|
||||
connect(m_comm, &CarCommunication::faultAppended,
|
||||
this, &AppContext::appendFault);
|
||||
|
||||
// 遥控器报文 → 模式 / 急停 / 动作 / 显示
|
||||
connect(m_rc, &RcCommunication::frameReceived, this, &AppContext::onRcFrame);
|
||||
connect(m_rc, &RcCommunication::linkChanged, this, &AppContext::onRcLinkChanged);
|
||||
|
||||
#if 0
|
||||
// 行车/机械臂模式改由底盘报文的 mode 字段决定(遥控器在线时让位给遥控器报文)。
|
||||
// 停用原因:协议 sheet RC 的 12 条下行报文里没有该 mode 字段,telemetry.driveMode
|
||||
// 无处可填,此连接只会一直把模式按 0(行车)写。待协议补充该信号后恢复。
|
||||
connect(m_comm, &CarCommunication::telemetryUpdated, this, [this]() {
|
||||
if (m_rc->linkOk()) return;
|
||||
setMode(telemetry.driveMode == 0 ? Mode::Drive : Mode::Arm);
|
||||
});
|
||||
#endif
|
||||
|
||||
seedFaultHistory();
|
||||
}
|
||||
|
||||
@@ -117,9 +147,10 @@ void AppContext::setPassword(const QString& pwd)
|
||||
m_settings->sync();
|
||||
}
|
||||
|
||||
// 管理员密码为固定值,不持久化、不可修改
|
||||
QString AppContext::adminPassword() const
|
||||
{
|
||||
return m_settings->value("param/admin_pwd", "6789").toString();
|
||||
return "9527";
|
||||
}
|
||||
|
||||
void AppContext::resetEstop()
|
||||
@@ -144,4 +175,121 @@ void AppContext::setMode(Mode m)
|
||||
if (mode == m) return;
|
||||
mode = m;
|
||||
emit modeChanged(m);
|
||||
if (m_comm) m_comm->setArmMode(m == Mode::Arm); // 同步到 Arm_ControlCmd1 的 Arm_modeCmd/Arm_enable
|
||||
}
|
||||
|
||||
// ===================== 遥控器(24 字节二进制帧) =====================
|
||||
void AppContext::onRcFrame(const RcFrame& f)
|
||||
{
|
||||
// 存入遥测快照,供界面显示
|
||||
telemetry.rcBattery = f.battery;
|
||||
telemetry.rcDriveMode = f.driveMode;
|
||||
telemetry.rcArmMode = f.armMode;
|
||||
telemetry.rcArmEnabled = f.armEnabled;
|
||||
telemetry.rcChassisEnabled = f.chassisEnabled;
|
||||
telemetry.rcEstop = f.estop;
|
||||
telemetry.rcGear = f.gear;
|
||||
telemetry.rcSteer = f.steer;
|
||||
telemetry.rcPosZ = f.posZ;
|
||||
telemetry.rcPosX = f.posX;
|
||||
telemetry.rcPosY = f.posY;
|
||||
telemetry.rcRoll = f.roll;
|
||||
telemetry.rcPitch = f.pitch;
|
||||
telemetry.rcYaw = f.yaw;
|
||||
|
||||
// 模式:bit1 机械臂模式须与 bit2 机械臂使能同时为 1 才视为机械臂
|
||||
setMode((f.armMode && f.armEnabled) ? Mode::Arm : Mode::Drive);
|
||||
|
||||
// 急停与复位都由遥控器 bit4 下发:上升沿触发,下降沿复位。面板只显示横幅提示。
|
||||
if (f.estop != m_rcEstopPrev) {
|
||||
m_rcEstopPrev = f.estop;
|
||||
if (f.estop) triggerEstop();
|
||||
else resetEstop();
|
||||
}
|
||||
|
||||
// 动作:与界面按钮同一套安全联锁(模式 + 使能 + 未急停)
|
||||
applyRcChassis(f.gear, f.steer, f.chassisEnabled);
|
||||
applyRcArm(f);
|
||||
|
||||
updateRcDriving();
|
||||
}
|
||||
|
||||
void AppContext::applyRcChassis(int gear, int steer, bool enabled)
|
||||
{
|
||||
const bool allowed = enabled && !estopTriggered && (mode == Mode::Drive);
|
||||
|
||||
const int g = allowed ? axisDir(gear) : 0;
|
||||
const int s = allowed ? axisDir(steer) : 0;
|
||||
|
||||
if (g == m_rcGearDir && s == m_rcSteerDir) return; // 方向未变,不重复发包
|
||||
m_rcGearDir = g;
|
||||
m_rcSteerDir = s;
|
||||
sendChassisCommand();
|
||||
}
|
||||
|
||||
void AppContext::applyRcArm(const RcFrame& f)
|
||||
{
|
||||
const bool allowed = f.armEnabled && !estopTriggered && (mode == Mode::Arm);
|
||||
const int vals[6] = {f.posZ, f.posX, f.posY, f.roll, f.pitch, f.yaw};
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
const int d = allowed ? axisDir(vals[i]) : 0;
|
||||
if (d == m_rcAxisDir[i]) continue; // 方向未变,不重复发包
|
||||
m_rcAxisDir[i] = d;
|
||||
m_comm->sendArmMove(QString::fromLatin1(kArmAxes[i]), d);
|
||||
}
|
||||
}
|
||||
|
||||
// 档位与转向可同时下发(边前进/后退边转向);两者都回中才停车。
|
||||
// 仅转向(档位回中)时发 stop + turn,由车载端决定是否原地转向。
|
||||
void AppContext::sendChassisCommand()
|
||||
{
|
||||
QString dir = "stop";
|
||||
if (m_rcGearDir > 0) dir = "fwd";
|
||||
else if (m_rcGearDir < 0) dir = "back";
|
||||
|
||||
QString turn;
|
||||
if (m_rcSteerDir > 0) turn = "right";
|
||||
else if (m_rcSteerDir < 0) turn = "left";
|
||||
|
||||
if (dir == "stop" && turn.isEmpty()) {
|
||||
m_comm->sendChassisMove("stop", 0);
|
||||
return;
|
||||
}
|
||||
const double spd = (dir == "stop") ? 0.0 : getDouble(keySpeed(), 4.5);
|
||||
m_comm->sendChassisMove(dir, spd, turn);
|
||||
}
|
||||
|
||||
void AppContext::updateRcDriving()
|
||||
{
|
||||
// 遥控器正在操作:链路在线且任一已生效轴偏离中位
|
||||
bool driving = (m_rcGearDir != 0) || (m_rcSteerDir != 0);
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
if (m_rcAxisDir[i] != 0) { driving = true; break; }
|
||||
}
|
||||
|
||||
if (driving == m_rcDriving) return;
|
||||
m_rcDriving = driving;
|
||||
emit rcDrivingChanged(driving);
|
||||
}
|
||||
|
||||
void AppContext::onRcLinkChanged(bool ok)
|
||||
{
|
||||
telemetry.rcLinkOk = ok;
|
||||
|
||||
if (!ok) {
|
||||
// 链路中断:撤销所有遥控器动作,否则最后一条指令会被一直挂住。
|
||||
// 不动急停状态——丢包导致的 bit4 读为 0 不应被当成遥控器下发的复位。
|
||||
if (m_rcGearDir != 0 || m_rcSteerDir != 0) {
|
||||
m_rcGearDir = 0;
|
||||
m_rcSteerDir = 0;
|
||||
m_comm->sendChassisMove("stop", 0);
|
||||
}
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
if (m_rcAxisDir[i] == 0) continue;
|
||||
m_rcAxisDir[i] = 0;
|
||||
m_comm->sendArmMove(QString::fromLatin1(kArmAxes[i]), 0);
|
||||
}
|
||||
}
|
||||
updateRcDriving();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user