2024-09-04 11:06:17 +08:00
|
|
|
|
import socket from '@ohos.net.socket'
|
|
|
|
|
|
import Queue from '@ohos.util.Queue'
|
|
|
|
|
|
import { LogHelper } from '../LogHelper'
|
|
|
|
|
|
|
|
|
|
|
|
interface ApaListener {
|
|
|
|
|
|
onApaStart(): void
|
|
|
|
|
|
|
|
|
|
|
|
onApaStop(): void
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface AutomaticListener {
|
|
|
|
|
|
onPathTrackingStart(): void
|
|
|
|
|
|
|
|
|
|
|
|
onPathTrackingStop(): void
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class ApaListener implements ApaListener {
|
|
|
|
|
|
private listener: AutomaticListener
|
|
|
|
|
|
|
|
|
|
|
|
constructor(listener: AutomaticListener) {
|
|
|
|
|
|
this.listener = listener
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onApaStart() {
|
|
|
|
|
|
if (this.listener) {
|
|
|
|
|
|
this.listener.onPathTrackingStart()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onApaStop() {
|
|
|
|
|
|
if (this.listener) {
|
|
|
|
|
|
this.listener.onPathTrackingStop()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function sleep(time: number) {
|
|
|
|
|
|
return new Promise<void>((resolve, reject) => {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
resolve()
|
|
|
|
|
|
}, time)
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TrackInfo {
|
|
|
|
|
|
public static CAR_IN_LAND = 1; //车在平地
|
|
|
|
|
|
public static CAR_IN_RAMP_UP = 2; //车在上坡
|
|
|
|
|
|
public static CAR_IN_RAMP_DOWN = 3; //车在下坡
|
|
|
|
|
|
// private static TYPE_1_LIB = 1; //库位
|
|
|
|
|
|
// private static TYPE_2_UPRAMP = 2; //上坡模式
|
|
|
|
|
|
// private static TYPE_3_DOWNRAMP = 3;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TrackMode {
|
|
|
|
|
|
public static MODE_TEACH = "teach";
|
|
|
|
|
|
public static MODE_LIB = "lib";
|
|
|
|
|
|
public static MODE_PATH = "path";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CtrlParam {
|
|
|
|
|
|
public static k = 0.1; // look forward gain
|
|
|
|
|
|
public static Lfc = 6.5; // [m] look-ahead distance
|
|
|
|
|
|
public static Kp = 1.0; // speed proportional gain
|
|
|
|
|
|
public static dt = 0.1; // [s] time tick
|
|
|
|
|
|
public static WB = 2.42; // [m] wheel base of vehicle
|
|
|
|
|
|
public static STEERING_RATIO = 16; //哪吒V型车转向比(哪吒底盘人员提供,与速度关系不大,与方向盘关系大,一般为抛物线关系,已获取到文档)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Message {
|
|
|
|
|
|
deadline: number;
|
|
|
|
|
|
angle = 0;
|
|
|
|
|
|
|
|
|
|
|
|
constructor(deadline: number, angle: number) {
|
|
|
|
|
|
this.deadline = deadline
|
|
|
|
|
|
this.angle = angle
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class WireControl {
|
|
|
|
|
|
private static FXP_GAP_TIME: number = 180;
|
|
|
|
|
|
private static FXP_GAP_DEGREE: number = 40;
|
|
|
|
|
|
private TAG: string = "automatic";
|
|
|
|
|
|
private mAutomaticListener: AutomaticListener;
|
|
|
|
|
|
private mApaListener: ApaListener;
|
|
|
|
|
|
private socket: socket.UDPSocket
|
|
|
|
|
|
private apaIp: string;
|
|
|
|
|
|
private apaPort: number;
|
|
|
|
|
|
private APA2_HEAD: number[] = [0x08, 0x00, 0x00, 0x02, 0xba]; // 8 0 0 2 186
|
|
|
|
|
|
private APA3_HEAD: number[] = [0x08, 0x00, 0x00, 0x02, 0x7b]; // 8 0 0 2
|
|
|
|
|
|
private APA4_HEAD: number[] = [0x08, 0x00, 0x00, 0x02, 0x53];
|
|
|
|
|
|
private APA_WORKING: number = 0;
|
|
|
|
|
|
private APA_BRAKE_STATUS: number = 0;
|
|
|
|
|
|
private APA_InfoDisplayReq: number = 0; // Advanced Parking Information display request
|
|
|
|
|
|
private APA_EPSAngleReq: number = 1; // APA是否请求转向
|
|
|
|
|
|
private APA_EPSAngleReqValidity: number = 1; // APA请求转向有效位
|
|
|
|
|
|
private APA_EPSAngleValueReq: number = 0; //@@@ APA请求转向角度(-540~+540)
|
|
|
|
|
|
private APA_WorkSts_CH: number = 0; // APA状态
|
|
|
|
|
|
private APA_TurnLightReq: number = 0; // APA请求左/右转向闪灯
|
|
|
|
|
|
private APA3_GearPosReq: number = 0; //@@@ 目标档位信号 0X1:P 0X2:R 0X3:N 0X4:D
|
|
|
|
|
|
private APA3_GearPosReqValidity: number = 1; // 目标档位信号的有效性
|
|
|
|
|
|
private APA3_TorqReq: number = 0; // 请求VCU目标扭矩
|
|
|
|
|
|
private APA3_TorqReqValue: number = 512; //@@@ 请求VCU目标扭矩值
|
|
|
|
|
|
private APA3_TorqReqValidity: number = 1; // 请求VCU目标扭矩状态
|
|
|
|
|
|
private APA4_ApaMod: number = 0; // APA工作状态
|
|
|
|
|
|
private APA4_ApaBrkMod: number = 0; // APA制动控制模式
|
|
|
|
|
|
private APA4_ApaStopReq: number = 0; //@@@ APA请求Stop 0是松 1是拉
|
|
|
|
|
|
private APA4_ApaEpbReq: number = 0; // APA请求EPB协助
|
|
|
|
|
|
private APA4_ApaMaxSpd: number = 0; //@@@ APA最大允许车速
|
|
|
|
|
|
private APA4_ApaTarDecel: number = 0; // APA请求目标减速度
|
|
|
|
|
|
private APA4_APASwFd: number = 0; // APA设置开关反馈信息
|
|
|
|
|
|
private APA_Fr02_MsgCounter: number = 0; // 校验位
|
|
|
|
|
|
private APA3_Fr03_MsgCounter: number = 0; // 校验位
|
|
|
|
|
|
private APA4_Fr04_MsgCounter: number = 0; // 校验位
|
|
|
|
|
|
// APA2
|
|
|
|
|
|
private APA2_APA_HornReq: number = 0; // 喇叭 0x0——关 0x1——开
|
|
|
|
|
|
//0:unInit; 1:initing; 2:init fail; 3:init success
|
|
|
|
|
|
private initStatus: number;
|
|
|
|
|
|
private apaWorking: boolean;
|
|
|
|
|
|
private isInit: boolean;
|
|
|
|
|
|
private lastAngle: number = 0;
|
|
|
|
|
|
private angleHandle: number = 0;
|
|
|
|
|
|
private lastItem: string = "";
|
|
|
|
|
|
private lastDoor: number = -1;
|
|
|
|
|
|
protected cruiseModeSwitch: boolean = true;
|
|
|
|
|
|
protected rampUpModeSwitch: boolean = true;
|
|
|
|
|
|
protected rampDownModeSwitch: boolean = true;
|
|
|
|
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
|
|
this.mApaListener = new ApaListener(this.mAutomaticListener)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public setMAutomaticListener(mAutomaticListener: AutomaticListener) {
|
|
|
|
|
|
this.mAutomaticListener = mAutomaticListener;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getMAutomaticListener() {
|
|
|
|
|
|
return this.mAutomaticListener;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public init(ip: string, port: number) {
|
|
|
|
|
|
this.apaIp = ip;
|
|
|
|
|
|
this.apaPort = port;
|
|
|
|
|
|
this.socket = socket.constructUDPSocketInstance()
|
|
|
|
|
|
this.socket.setExtraOptions({ reuseAddress: true });
|
2024-09-05 10:35:03 +08:00
|
|
|
|
return this.socket.bind({ address: "0.0.0.0", port: 31021 }).then(() => {
|
2024-09-04 11:06:17 +08:00
|
|
|
|
this.isInit = true;
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public apaStart() {
|
|
|
|
|
|
if (!this.isInit) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
this.APA_EPSAngleValueReq = 0;
|
|
|
|
|
|
this.lastAngle = 0;
|
|
|
|
|
|
if (this.apaWorking) return;
|
|
|
|
|
|
this.apaWorking = true;
|
|
|
|
|
|
setInterval(() => {
|
2024-09-05 10:35:03 +08:00
|
|
|
|
if (this.apaWorking) {
|
|
|
|
|
|
this.sendAutomaticMsg()
|
|
|
|
|
|
}
|
2024-09-04 11:06:17 +08:00
|
|
|
|
}, 20)
|
2024-09-05 10:35:03 +08:00
|
|
|
|
sleep(3000).then(() => {
|
|
|
|
|
|
this.initStatus = 1;
|
|
|
|
|
|
this.APA_EPSAngleValueReq = 0;
|
|
|
|
|
|
this.APA_WorkSts_CH = 0x2;
|
|
|
|
|
|
return sleep(2000)
|
|
|
|
|
|
}).then(() => {
|
|
|
|
|
|
this.APA_WorkSts_CH = 0x3;
|
|
|
|
|
|
this.APA3_TorqReq = 1;
|
|
|
|
|
|
this.APA4_ApaBrkMod = 1;
|
|
|
|
|
|
this.APA4_ApaMod = 1;
|
|
|
|
|
|
this.APA4_APASwFd = 1;
|
|
|
|
|
|
return sleep(60)
|
|
|
|
|
|
}).then(() => {
|
|
|
|
|
|
this.APA_WorkSts_CH = 0x4;
|
|
|
|
|
|
this.APA4_ApaBrkMod = 2;
|
|
|
|
|
|
this.APA4_ApaStopReq = 1;
|
|
|
|
|
|
this.APA4_ApaEpbReq = 1;
|
|
|
|
|
|
this.APA4_ApaTarDecel = 0xc8;
|
|
|
|
|
|
return sleep(2000)
|
|
|
|
|
|
}).then(() => {
|
|
|
|
|
|
this.APA4_ApaMaxSpd = 0x80;
|
|
|
|
|
|
this.APA4_ApaTarDecel = 0;
|
|
|
|
|
|
this.initStatus = 3;
|
|
|
|
|
|
return sleep(2000)
|
|
|
|
|
|
});
|
|
|
|
|
|
this.mApaListener.onApaStart();
|
2024-09-04 11:06:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public apaStop() {
|
|
|
|
|
|
if (!this.isInit) return;
|
|
|
|
|
|
this.mApaListener.onApaStop();
|
|
|
|
|
|
this.apaOff();
|
|
|
|
|
|
sleep(3000).then(() => {
|
|
|
|
|
|
this.apaWorking = false
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public apaOff() {
|
|
|
|
|
|
this.initStatus = 0;
|
|
|
|
|
|
this.brakeOn();
|
|
|
|
|
|
this.APA_WorkSts_CH = 0x0;
|
|
|
|
|
|
this.APA3_TorqReq = 0;
|
|
|
|
|
|
this.APA4_ApaBrkMod = 0;
|
|
|
|
|
|
this.APA4_ApaMod = 0;
|
|
|
|
|
|
this.APA4_ApaStopReq = 0;
|
|
|
|
|
|
this.APA4_ApaEpbReq = 0;
|
|
|
|
|
|
this.APA4_ApaMaxSpd = 0;
|
|
|
|
|
|
this.APA4_ApaTarDecel = 0;
|
|
|
|
|
|
this.APA4_APASwFd = 0;
|
|
|
|
|
|
this.APA_EPSAngleValueReq = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public apaInit() {
|
|
|
|
|
|
if (this.initStatus != 0) return;
|
|
|
|
|
|
this.initStatus = 1;
|
|
|
|
|
|
this.APA_EPSAngleValueReq = 0;
|
|
|
|
|
|
this.APA_WorkSts_CH = 0x2;
|
|
|
|
|
|
sleep(2000).then(() => {
|
|
|
|
|
|
this.APA_WorkSts_CH = 0x3;
|
|
|
|
|
|
this.APA3_TorqReq = 1;
|
|
|
|
|
|
this.APA4_ApaBrkMod = 1;
|
|
|
|
|
|
this.APA4_ApaMod = 1;
|
|
|
|
|
|
this.APA4_APASwFd = 1;
|
|
|
|
|
|
return sleep(60)
|
|
|
|
|
|
}).then(() => {
|
|
|
|
|
|
this.APA_WorkSts_CH = 0x4;
|
|
|
|
|
|
this.APA4_ApaBrkMod = 2;
|
|
|
|
|
|
this.APA4_ApaStopReq = 1;
|
|
|
|
|
|
this.APA4_ApaEpbReq = 1;
|
|
|
|
|
|
this.APA4_ApaTarDecel = 0xc8;
|
|
|
|
|
|
return sleep(2000)
|
|
|
|
|
|
}).then(() => {
|
|
|
|
|
|
this.APA4_ApaStopReq = 0;
|
|
|
|
|
|
this.APA4_ApaMaxSpd = 0x80; //0xc0;
|
|
|
|
|
|
this.APA4_ApaTarDecel = 0;
|
|
|
|
|
|
this.initStatus = 3;
|
|
|
|
|
|
return sleep(2000)
|
|
|
|
|
|
}).then(() => {
|
|
|
|
|
|
this.moveUp();
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设定控制模式
|
|
|
|
|
|
private setControlMode(carLocate: number, mode: string) {
|
|
|
|
|
|
switch (carLocate) {
|
|
|
|
|
|
case -1:
|
|
|
|
|
|
case TrackInfo.CAR_IN_LAND:
|
|
|
|
|
|
this.cruiseMode();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case TrackInfo.CAR_IN_RAMP_UP:
|
|
|
|
|
|
this.rampUpMode();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case TrackInfo.CAR_IN_RAMP_DOWN:
|
|
|
|
|
|
this.rampDownMode();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (mode === TrackMode.MODE_LIB) {
|
|
|
|
|
|
this.lowSpeedCruiseMode();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* apa指令接口
|
|
|
|
|
|
* @param cmd
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
public apaCmd(cmd: string, mode: string, carLocate: number, isPathTrackEnd: boolean, doorSwitch: number) {
|
|
|
|
|
|
if (doorSwitch == 1 && this.lastDoor != 1) {
|
|
|
|
|
|
this.brakeOn();
|
|
|
|
|
|
} else if (doorSwitch == 0 && this.lastDoor != 0) {
|
|
|
|
|
|
this.moveUp();
|
|
|
|
|
|
}
|
|
|
|
|
|
this.lastDoor = doorSwitch;
|
|
|
|
|
|
|
|
|
|
|
|
if (isPathTrackEnd) {
|
|
|
|
|
|
this.brakeOn();
|
|
|
|
|
|
LogHelper.I(LogHelper.RESULT_PURPERSUIT, "导航到最后点位,停车拉手刹!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (cmd === "") {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
let params = cmd.split(";");
|
|
|
|
|
|
let fxp = parseFloat(params[0]);
|
|
|
|
|
|
let move = parseInt(params[1]);
|
|
|
|
|
|
|
|
|
|
|
|
if (fxp != -1000) {
|
|
|
|
|
|
this.fxpCtrl(fxp, mode);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.setControlMode(carLocate, mode);
|
|
|
|
|
|
|
|
|
|
|
|
if (move != -1000) {
|
|
|
|
|
|
if (move == 1) {
|
|
|
|
|
|
this.moveUp();
|
|
|
|
|
|
LogHelper.I(LogHelper.RESULT_TRACKING, "前进");
|
|
|
|
|
|
} else if (move == -1) {
|
|
|
|
|
|
this.moveDown();
|
|
|
|
|
|
LogHelper.I(LogHelper.RESULT_TRACKING, "后退");
|
|
|
|
|
|
} else if (move == 0) {
|
|
|
|
|
|
this.moveStop();
|
|
|
|
|
|
LogHelper.I(LogHelper.RESULT_TRACKING, "停止");
|
|
|
|
|
|
} else if (move == 10) {
|
|
|
|
|
|
this.brakeOn();
|
|
|
|
|
|
LogHelper.I(LogHelper.RESULT_TRACKING, "刹车");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private handleAngle(di: number) {
|
|
|
|
|
|
|
|
|
|
|
|
let angle = di * 180 / Math.PI;
|
|
|
|
|
|
if (angle > 45) {
|
|
|
|
|
|
angle = 45;
|
|
|
|
|
|
} else if (angle < -45) {
|
|
|
|
|
|
angle = -45;
|
|
|
|
|
|
}
|
|
|
|
|
|
let fxp: number = angle * CtrlParam.STEERING_RATIO;
|
|
|
|
|
|
|
|
|
|
|
|
return fxp;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public fxpCtrl(angle: number, mode: string) {
|
|
|
|
|
|
let angle2 = 0;
|
|
|
|
|
|
if (mode === TrackMode.MODE_PATH) {
|
|
|
|
|
|
LogHelper.I(LogHelper.RESULT_TRACKING, "输出方向盘PATH:" + this.handleAngle(angle));
|
|
|
|
|
|
this.APA4_ApaMaxSpd = 0xFF; //0xc0;0x80 // 0x80为2码、c0为3码 0xFF-4码 0x13F-5码 0x17F_6码 0x1BF_7码 0x200_8码
|
|
|
|
|
|
// 0x300——12码 0x3c0——15码 0x500——20码 0x640——25码 0x780——30码
|
|
|
|
|
|
angle2 = this.handleAngle(angle);
|
|
|
|
|
|
} else if (mode === TrackMode.MODE_TEACH) {
|
|
|
|
|
|
LogHelper.I(LogHelper.RESULT_TRACKING, "输出方向盘:" + angle);
|
|
|
|
|
|
this.APA4_ApaMaxSpd = 0x80; //0xc0;0x80 // 0x80为2码、c0为3码 0xFF-4码 0x13F-5码 0x17F_6码 0x1BF_7码 0x200_8码
|
|
|
|
|
|
angle2 = angle;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
LogHelper.I(LogHelper.RESULT_TRACKING, "输出方向盘:" + angle);
|
|
|
|
|
|
this.APA4_ApaMaxSpd = 0x80; //0xc0;0x80 // 0x80为2码、c0为3码 0xFF-4码 0x13F-5码 0x17F_6码 0x1BF_7码 0x200_8码
|
|
|
|
|
|
angle2 = angle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (this.initStatus != 3) return;
|
|
|
|
|
|
if (angle2 > 540) {
|
|
|
|
|
|
angle2 = 540;
|
|
|
|
|
|
} else if (angle < -540) {
|
|
|
|
|
|
angle2 = -540;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (mode === TrackMode.MODE_PATH) {
|
|
|
|
|
|
this.fxp4(angle2);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.fxp4(angle2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fxp2(angle: number) {
|
|
|
|
|
|
// 要实现方向盘的逐步转向,哪吒控制协议不支持单步过大的操作,之前的转向
|
|
|
|
|
|
// 策略为:每次转30度,300毫秒完成一次转向
|
|
|
|
|
|
if (Math.abs(this.lastAngle - angle) < 10) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (Math.abs(angle - this.APA_EPSAngleValueReq) < 50) {
|
|
|
|
|
|
this.APA_EPSAngleValueReq = angle;
|
|
|
|
|
|
LogHelper.I(LogHelper.RESULT_TRACKING, "-----方向盘变化小,直接执行:" + this.APA_EPSAngleValueReq);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.angleHandle = angle - this.lastAngle;
|
|
|
|
|
|
|
|
|
|
|
|
let queue = new Queue<Message>()
|
|
|
|
|
|
let now = new Date().getUTCMilliseconds();
|
|
|
|
|
|
let angleHandleAbs = Math.abs(this.angleHandle);
|
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < 30; i++) {
|
|
|
|
|
|
if (angleHandleAbs > 0) {
|
|
|
|
|
|
if (this.angleHandle > 0) {
|
|
|
|
|
|
queue.add(new Message(now + i * WireControl.FXP_GAP_TIME, Math.min(WireControl.FXP_GAP_DEGREE, angleHandleAbs)));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
queue.add(new Message(now + i * WireControl.FXP_GAP_TIME, -Math.min(WireControl.FXP_GAP_DEGREE, angleHandleAbs)));
|
|
|
|
|
|
}
|
|
|
|
|
|
angleHandleAbs -= WireControl.FXP_GAP_DEGREE;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let temp = "";
|
|
|
|
|
|
for (let ms of queue) {
|
|
|
|
|
|
temp = temp + "&" + ms.angle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LogHelper.I(LogHelper.RESULT_TRACKING, "queue:" + temp)
|
|
|
|
|
|
|
|
|
|
|
|
setInterval(() => {
|
|
|
|
|
|
if (queue.length > 0) {
|
|
|
|
|
|
this.APA_EPSAngleValueReq += queue.pop().angle;
|
|
|
|
|
|
}
|
|
|
|
|
|
}, WireControl.FXP_GAP_TIME)
|
|
|
|
|
|
|
|
|
|
|
|
this.lastAngle = angle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fxp3(fxpAngle: number) {
|
|
|
|
|
|
let gap = Math.abs(fxpAngle - this.APA_EPSAngleValueReq);
|
|
|
|
|
|
if (gap <= 10) {
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let step = gap * 45 / 540;
|
|
|
|
|
|
step = Math.min(45, step);
|
|
|
|
|
|
step = Math.max(2, step);
|
|
|
|
|
|
LogHelper.I(this.TAG, "AAA step:" + step);
|
|
|
|
|
|
if (fxpAngle > this.APA_EPSAngleValueReq) {
|
|
|
|
|
|
this.APA_EPSAngleValueReq += step;
|
|
|
|
|
|
} else if (fxpAngle < this.APA_EPSAngleValueReq) {
|
|
|
|
|
|
this.APA_EPSAngleValueReq -= step;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public fxp4(fxpAngle: number) {
|
|
|
|
|
|
LogHelper.I("xwq22", "angle:" + fxpAngle + " APA_EPSAngleValueReq:" + this.APA_EPSAngleValueReq);
|
|
|
|
|
|
let gap = Math.abs(fxpAngle - this.APA_EPSAngleValueReq);
|
|
|
|
|
|
if (gap <= 10) {
|
|
|
|
|
|
// do nothing
|
|
|
|
|
|
} else if (gap < 40) {
|
|
|
|
|
|
this.APA_EPSAngleValueReq = fxpAngle;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (fxpAngle > this.APA_EPSAngleValueReq) {
|
|
|
|
|
|
this.APA_EPSAngleValueReq += 40;
|
|
|
|
|
|
} else if (fxpAngle < this.APA_EPSAngleValueReq) {
|
|
|
|
|
|
this.APA_EPSAngleValueReq -= 40;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fxp(angle: number) {
|
|
|
|
|
|
LogHelper.I(this.TAG, "angle:" + angle + " APA_EPSAngleValueReq:" + this.APA_EPSAngleValueReq);
|
|
|
|
|
|
let gap = Math.abs(angle - this.APA_EPSAngleValueReq);
|
|
|
|
|
|
if (gap <= 10) {
|
|
|
|
|
|
this.APA_EPSAngleValueReq = angle;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let step = gap * 45 / 540;
|
|
|
|
|
|
step = Math.min(45, step);
|
|
|
|
|
|
step = Math.max(2, step);
|
|
|
|
|
|
if (angle > this.APA_EPSAngleValueReq) {
|
|
|
|
|
|
this.APA_EPSAngleValueReq += step;
|
|
|
|
|
|
} else if (angle < this.APA_EPSAngleValueReq) {
|
|
|
|
|
|
this.APA_EPSAngleValueReq -= step;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private lowSpeedCruiseMode() {
|
|
|
|
|
|
this.APA3_TorqReqValue = 536; // 正常536 坡道610
|
|
|
|
|
|
this.APA4_ApaMaxSpd = 0x40; //0xc0;0x80 //0x40为1码、0x80为2码、c0为3码 0xFF-4码 0x13F-5码 0x17F_6码 0x1BF_7码 0x200_8码
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//正常巡航模式
|
|
|
|
|
|
private cruiseMode() {
|
|
|
|
|
|
if (this.cruiseModeSwitch) {
|
|
|
|
|
|
this.APA3_TorqReqValue = 536; // 正常536 坡道610
|
|
|
|
|
|
// APA4_ApaMaxSpd = 0xc0;//0xc0;0x80 // 0x80为2码、c0为3码 0xFF-4码 0x13F-5码 0x17F_6码 0x1BF_7码 0x200_8码
|
|
|
|
|
|
|
|
|
|
|
|
this.cruiseModeSwitch = false;
|
|
|
|
|
|
this.rampUpModeSwitch = true;
|
|
|
|
|
|
this.rampDownModeSwitch = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 坡道上坡模式
|
|
|
|
|
|
private rampUpMode() {
|
|
|
|
|
|
if (this.rampUpModeSwitch) {
|
|
|
|
|
|
this.APA3_TorqReqValue = 610; // 正常536 坡道610
|
|
|
|
|
|
// APA4_ApaMaxSpd = 0xc0;//0xc0;0x80 // 0x80为2码、c0为3码 0xFF-4码 0x13F-5码 0x200_8码
|
|
|
|
|
|
|
|
|
|
|
|
this.rampUpModeSwitch = false;
|
|
|
|
|
|
this.cruiseModeSwitch = true;
|
|
|
|
|
|
this.rampDownModeSwitch = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 坡道下坡模式
|
|
|
|
|
|
private rampDownMode() {
|
|
|
|
|
|
if (this.rampDownModeSwitch) {
|
|
|
|
|
|
this.APA3_TorqReqValue = 488; // 正常536 坡道610
|
|
|
|
|
|
this.APA4_ApaTarDecel = 0x76C; //0x12C:300 0xc8:200(当前刹车力度) 0x190:400 0x1F4:500 0x258:600 0x320:800 0x3E8:1000 0x5DC:1500 0x76C:1900
|
|
|
|
|
|
this.rampDownModeSwitch = false;
|
|
|
|
|
|
this.cruiseModeSwitch = true;
|
|
|
|
|
|
this.rampUpModeSwitch = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 起步
|
|
|
|
|
|
public moveUp() {
|
|
|
|
|
|
if (this.initStatus != 3) return;
|
|
|
|
|
|
this.brakeOff();
|
|
|
|
|
|
this.APA3_GearPosReq = 0x4;
|
|
|
|
|
|
this.APA3_TorqReqValue = 536; // 正常536 坡道610
|
|
|
|
|
|
// this.carDir = "车辆状态:前进";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 停车
|
|
|
|
|
|
public moveStop() {
|
|
|
|
|
|
if (this.initStatus != 3) return;
|
|
|
|
|
|
this.APA3_GearPosReq = 0x3;
|
|
|
|
|
|
this.APA3_TorqReqValue = 512;
|
|
|
|
|
|
// carDir = "车辆状态:停车";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 后退
|
|
|
|
|
|
public moveDown() {
|
|
|
|
|
|
if (this.initStatus != 3) return;
|
|
|
|
|
|
this.brakeOff();
|
|
|
|
|
|
this.APA3_GearPosReq = 0x2;
|
|
|
|
|
|
this.APA3_TorqReqValue = 488;
|
|
|
|
|
|
// carDir = "车辆状态:后退";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 拉手刹
|
|
|
|
|
|
public brakeOn() {
|
|
|
|
|
|
if (this.initStatus != 3) return;
|
|
|
|
|
|
this.moveStop();
|
|
|
|
|
|
this.APA4_ApaStopReq = 0x1;
|
|
|
|
|
|
this.APA4_ApaTarDecel = 0xc8;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 松手刹
|
|
|
|
|
|
public brakeOff() {
|
|
|
|
|
|
if (this.initStatus != 3) return;
|
|
|
|
|
|
this.APA4_ApaStopReq = 0;
|
|
|
|
|
|
this.APA4_ApaTarDecel = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 左转向灯
|
|
|
|
|
|
public leftLight() {
|
|
|
|
|
|
this.APA_TurnLightReq = 0x1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 右转向灯
|
|
|
|
|
|
public rightLight() {
|
|
|
|
|
|
this.APA_TurnLightReq = 0x2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 双跳灯
|
|
|
|
|
|
public doubleLight() {
|
|
|
|
|
|
this.APA_TurnLightReq = 0x3;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭转向灯
|
|
|
|
|
|
public shutLight() {
|
|
|
|
|
|
this.APA_TurnLightReq = 0x0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 开喇叭
|
|
|
|
|
|
public onHorn() {
|
|
|
|
|
|
this.APA2_APA_HornReq = 0x1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关喇叭
|
|
|
|
|
|
public offHorn() {
|
|
|
|
|
|
this.APA2_APA_HornReq = 0x0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 增加扭矩
|
|
|
|
|
|
public addTorq() {
|
|
|
|
|
|
this.APA3_TorqReqValue += 5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 减少扭矩
|
|
|
|
|
|
public redTorq() {
|
|
|
|
|
|
this.APA3_TorqReqValue -= 5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置档位
|
|
|
|
|
|
public setGear(gear: string) {
|
|
|
|
|
|
if ("N" === gear) { //空挡N
|
|
|
|
|
|
this.APA3_GearPosReq = 0x3;
|
|
|
|
|
|
} else if ("P" === gear) { //驻车档P
|
|
|
|
|
|
this.APA3_GearPosReq = 0x1;
|
|
|
|
|
|
} else if ("R" === gear) { //倒挡R
|
|
|
|
|
|
this.APA3_GearPosReq = 0x2;
|
|
|
|
|
|
} else if ("D" === gear) { //前进D
|
|
|
|
|
|
this.APA3_GearPosReq = 0x4;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private sendAutomaticMsg() {
|
|
|
|
|
|
this.sendAPA4Data();
|
|
|
|
|
|
this.sendAPA3Data();
|
|
|
|
|
|
this.sendAPA2Data();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private sendAPA2Data() {
|
|
|
|
|
|
let data = new Uint8Array(13);
|
|
|
|
|
|
data.set(this.APA2_HEAD);
|
|
|
|
|
|
let index = 5;
|
|
|
|
|
|
data[index++] = this.APA_InfoDisplayReq;
|
|
|
|
|
|
let angle = (-this.APA_EPSAngleValueReq + 780) * 10;
|
|
|
|
|
|
data[index++] = ((angle & 0xff00) >> 8);
|
|
|
|
|
|
data[index++] = (angle & 0xff);
|
|
|
|
|
|
// 20240527 添加喇叭信号
|
|
|
|
|
|
data[index++] = ((((this.APA_EPSAngleReq & 0x1) << 7) | ((this.APA_EPSAngleReqValidity & 0x1) << 6) | ((this.APA2_APA_HornReq & 0x1) << 4)) | 0x22);
|
|
|
|
|
|
data[index++] = (((this.APA_WorkSts_CH & 0x7) << 5) | (this.APA_TurnLightReq & 0x3));
|
|
|
|
|
|
data[index++] = 0;
|
|
|
|
|
|
this.APA_Fr02_MsgCounter += 1;
|
|
|
|
|
|
if (this.APA_Fr02_MsgCounter > 15) {
|
|
|
|
|
|
this.APA_Fr02_MsgCounter = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
data[index++] = this.APA_Fr02_MsgCounter & 0xf;
|
|
|
|
|
|
let checkSum = 0;
|
|
|
|
|
|
for (let i = 5; i < 12; i++) {
|
|
|
|
|
|
checkSum ^= data[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
data[index++] = checkSum & 0xff;
|
|
|
|
|
|
this.sendAutomaticData(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private sendAPA3Data() {
|
|
|
|
|
|
let data = new Uint8Array(13);
|
|
|
|
|
|
data.set(this.APA3_HEAD);
|
|
|
|
|
|
let index = 5;
|
|
|
|
|
|
data[index++] = 0;
|
|
|
|
|
|
data[index++] = 0;
|
|
|
|
|
|
data[index++] = ((this.APA3_GearPosReq & 0x7) << 5) | (this.APA3_GearPosReqValidity << 4) | (this.APA3_TorqReq << 3) | ((this.APA3_TorqReqValue & 0x380) >> 7);
|
|
|
|
|
|
data[index++] = (this.APA3_TorqReqValue & 0x7f) << 1
|
|
|
|
|
|
data[index++] = this.APA3_TorqReqValidity << 7;
|
|
|
|
|
|
data[index++] = 0;
|
|
|
|
|
|
this.APA3_Fr03_MsgCounter += 1;
|
|
|
|
|
|
if (this.APA3_Fr03_MsgCounter > 15) {
|
|
|
|
|
|
this.APA3_Fr03_MsgCounter = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
data[index++] = this.APA3_Fr03_MsgCounter & 0xf;
|
|
|
|
|
|
let checkSum = 0;
|
|
|
|
|
|
for (let i = 5; i < 12; i++) {
|
|
|
|
|
|
checkSum ^= data[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
data[index++] = checkSum & 0xff;
|
|
|
|
|
|
this.sendAutomaticData(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private sendAPA4Data() {
|
|
|
|
|
|
let data = new Uint8Array(13);
|
|
|
|
|
|
data.set(this.APA4_HEAD);
|
|
|
|
|
|
let index = 5;
|
|
|
|
|
|
data[index++] = 0x4 | (this.APA4_ApaEpbReq & 0x3) | (this.APA4_APASwFd << 3);
|
|
|
|
|
|
data[index++] = 0;
|
|
|
|
|
|
data[index++] = 0x00 | (this.APA4_ApaTarDecel & 0x700) >> 8; // 第二字节 去9 10 11 三位
|
|
|
|
|
|
data[index++] = this.APA4_ApaTarDecel & 0xff; // 第三字节 取低八位
|
|
|
|
|
|
data[index++] = (this.APA4_ApaMaxSpd & 0xff00) >> 8; // 第四字节 取 速度的高八位
|
|
|
|
|
|
data[index++] = this.APA4_ApaMaxSpd & 0xff; // 第五字节 取 速度的低八位
|
|
|
|
|
|
this.APA4_Fr04_MsgCounter += 1;
|
|
|
|
|
|
if (this.APA4_Fr04_MsgCounter > 15) {
|
|
|
|
|
|
this.APA4_Fr04_MsgCounter = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
data[index++] = (this.APA4_Fr04_MsgCounter & 0xf) | (this.APA4_ApaStopReq << 7) | (this.APA4_ApaMod << 6) | (this.APA4_ApaBrkMod << 4);
|
|
|
|
|
|
let checkSum = 0;
|
|
|
|
|
|
for (let i = 5; i < 12; i++) {
|
|
|
|
|
|
checkSum ^= data[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
data[index++] = checkSum & 0xff;
|
|
|
|
|
|
this.sendAutomaticData(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private sendAutomaticData(data: Uint8Array) {
|
|
|
|
|
|
this.socket.send({
|
|
|
|
|
|
address: {
|
|
|
|
|
|
address: this.apaIp,
|
|
|
|
|
|
port: this.apaPort,
|
|
|
|
|
|
},
|
|
|
|
|
|
data: data.buffer
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|