1、概述
本文基于《新能源汽车零重力座椅控制策略开发要求》所述的相关需求,现将控制逻辑拆分到AUTOSAR CP 架构中的软件组件,并详细描述应用层软件的设计与实现过程。在后续的实际工作中,技术人员可直接据此创建SWC,配置RTE、操作系统任务并编写代码。
1.1设计原则
·每个SWC负责单一功能域。
·SWC间通过RTE的标准Sender/Receiver接口交互。
·10ms周期任务保证运动控制同步精度;50ms碰撞响应路径由OS中断事件实现。
·应用层代码不直接操作硬件,全部通过RTE访问BSW服务。
1.2开发环境
·AUTOSAR版本:CP 4.2.2
·OS:Scalable OS,符合 OSEK/VDX
·配置工具:EB tresos Studio/Vector DaVinci
·编译器:符合ISO C99
·微控制器:Infineon TC3xx或NXP S32K
2、软件架构与SWC划分
2.1 SWC总体设计
系统包含以下应用层SWC,部署于CDC上。
SWC名称 | 类型 | 功能描述 |
ZgSeatCtrl | Application SWC | 零重力控制逻辑:状态机、条件判断、轨迹规划、运动协调、记忆管理、迎宾逻辑。 |
ZgSeatDiag | Application SWC | 故障汇总、DTC管理、降级模式触发、防夹冗余检测。 |
ZgLinProxy | Application SWC /CDD | 1.作为SCU的LIN数据映射代理:将RTE信号转换为LIN发送帧,接收帧解析为信号。 2.内部可封装LIN调度。 3.本例按Application SWC实现,通过LIN服务接口操作。 |
ZgHmiBridge | Application SWC | 接收HMI软开关、记忆请求,反馈状态显示、警告信息。 |
说明:ZgLinProxy在项目中常作为复杂驱动直接访问LIN硬件,但在AUTOSAR标准架构下,也可将LIN信号映射到BSW的PDU中,由Com/RTE直接为应用层提供信号接口。这里采用标准映射方式,将各LIN信号定义为系统信号,ZgSeatCtrl直接通过RTE发送TargetPositions、接收ActualPositions。本例不再单独保留ZgLinProxy SWC,以降低复杂度,所有必要的LIN信号将通过BSW层配置实现透传。
2.2修改后 SWC 列表
基于上述背景对SWC进行更新,如下:
SWC | 描述 |
ZgSeatCtrl | 零重力主控逻辑 |
ZgSeatDiag | 诊断与故障处理 |
ZgHmiBridge | HMI交互适配 |
三个SWC间通过RTE接口交换数据,ZgSeatCtrl内部包含多个可运行实体。
3、接口定义
3.1部分信号定义
信号名 | 数据元素 | 类型 | 范围/分辨率 |
VehicleSpeed | VehicleSpeed | uint16 | 0..65535, 0.01 km/h |
GearPosition | GearPosition | enum | 0=Dan,1=P,2=R,3=N,4=D |
DriverDoorStatus | DoorStatus | uint8 | 0=Closed,1=Open |
CrashSignal | CrashStatus | uint8 | 0=Normal,1=Crash |
ZeroGravityRequest | ZgRequest | uint8 | 0=Idle,1=Activate,2=Deactivate |
ManualSwitchUp | ManualSwitches | uint8 bitfields | BIT0:SlideFwd, BIT1:SlideBwd |
SeatOccupied | Occupied | uint8 | 0=Empty,1=Occupied |
ActualPos_Slide | Position_mm | sint16 | 0.1mm/bit |
ActualPos_Recline | Angle_degx10 | sint16 | 0.1°/bit |
... | |||
TargetPos_Slide | Position_mm | sint16 | 0.1mm/bit |
... | |||
ControlWord | CtrlWord | uint16 | BIT0:EnableMotors, BIT1:Abort |
StatusWord | StatusWord | uint16 | BIT0:InPosition, BIT1:AntiPinchActive |
FaultCode | FaultCodeType | uint32 | DTC格式 |
DiagCommand | DiagCmd | uint8 | 清除故障等 |
3.2 接口
Sender-Receiver接口:
·I_VehicleData:包含VehicleSpeed,GearPosition,DoorStatus,CrashStatus;
·I_SeatFeedback:包含ActualPositions,StatusWord,MotorCurrents,Occupied;
·I_SeatCommands:包含TargetPositions,ControlWord;
·I_HmiControls:ZgRequest,ManualSwitches,MemoryRequest;
·I_HmiDisplay:ZgStateEnum,WarningMsgEnum,ActiveMemorySlot;
3.3 SWC与Port映射
ZgSeatCtrl:
·RPort VehicleData:I_VehicleData,接收车速、档位等;
·RPort SeatStatus:I_SeatFeedback,接收实际位置和状态;
·PPort SeatCmd:I_SeatCommands,发送目标位置和控制字;
·RPort HmiInput:I_HmiControls,接收请求和手动开关;
·PPort HmiOutput:I_HmiDisplay,发送状态给HMI;
·RPort DiagInfo:I_Diag,接收诊断状态,用于决策。
ZgSeatDiag:
·RPort SeatStatusDiag:I_SeatFeedback,接收位置/状态以检测防夹;
·RPort ZgStateDiag:从ZgSeatCtrl,接收当前运动状态;
·PPort DiagOutput:发送故障码给DEM,诊断事件;
·PPort DiagToZgCtrl:提供降级模式指示给ZgSeatCtrl。
ZgHmiBridge:
·RPort ZgDisplayIn:接收ZgStateEnum,WarningMsgEnum等;
·PPort HmiSignalOut:转换为HMI显示信号;
·RPort HardKeysIn:接收硬开关,本例中手动开关从SCU LIN来,已经包含在SeatStatus中,所以ZgSeatCtrl直接处理,ZgHmiBridge只负责屏幕显示。
注:不单独实现ZgHmiBridge,将HMI显示接口直接由ZgSeatCtrl通过RTE输出,这里不再进一步细化。
4、ZgSeatCtrl行为设计
4.1 Runnables 列表
ZgSeatCtrl作为 Application SWC,包含以下可运行实体,由不同事件触发。
可运行实体 | 触发事件 | 周期/条件 | 功能 |
ZG_Init | Init Event | ECU启动时执行一次 | 初始化状态、加载NVM记忆位置、标定参数 |
ZG_ReceiveVehicleSignals | DataReceivedEvent | 信号更新即触发 | 更新本地车速、档位等镜像,必要时触发状态转移 |
ZG_ReceiveSeatFeedback | DataReceivedEvent | LIN数据更新后触发 | 更新位置反馈缓冲,检查到位、防夹标志 |
ZG_ProcessHMI | DataReceivedEvent | 开关/请求一次 | 处理零重力请求、手动开关、记忆命令,存入内部队列 |
ZG_StateMachine | TimingEvent | 10ms | 执行状态机跃迁、条件评估、轨迹规划更新、输出目标位置与控制字 |
ZG_DiagReport | TimingEvent | 100ms | 汇总故障上报、更新DTC状态 |
4.2 内部状态变量
在SWC内部定义静态变量,不通过RTE共享。
typedef enum {
ZG_IDLE= 0,
ZG_MOVING_TO_ZG,
ZG_ZG_ACTIVE,
ZG_MOVING_TO_NORMAL,
ZG_INTERRUPTED,
ZG_FAULT,
ZG_SAFE_STOP,
ZG_WELCOME_MOVING,
ZG_MANUAL_OVERRIDE
} ZgState_t;
typedef struct {
sint16Slide;// 0.1mm
sint16Cushion;// 0.1°
sint16Recline;// 0.1°
sint16Legrest;// 0.1mm
sint16Footrest;// 0.1°
} SeatPosition_t;
// 目标位置、轨迹阶段、记忆位置数组等
static ZgState_t zgState = ZG_IDLE;
static SeatPosition_t targetPos;
static SeatPosition_t actualPos;
static uint8 trajPhase; // 0=idle,1=phase1...
static uint32 trajTimer; // ms since movement start
static uint8 conditionsMet;
4.3 RTE 数据流向
·ZG_ReceiveVehicleSignals从RTE读取RPort_VehicleData所有信号,更新vehSpd,gear,door等全局镜像。
·ZG_ReceiveSeatFeedback读取RPort_SeatStatus,更新actualPos,statusWord。
·ZG_ProcessHMI读取RPort_HmiInput,将命令暂存于环形缓冲,由状态机消费。
·ZG_StateMachine根据当前状态和缓冲命令,计算targetPos和ctrlWord,通过PPort_SeatCmd写出;同时更新PPort_HmiOutput状态。
5、Runnable设计与代码实现
5.1 ZG_StateMachine
该Runnable集成了状态机、进入条件判断、轨迹生成及运动控制。代码结构如下:
#include "Rte_ZgSeatCtrl.h"
#include "ZgSeatCtrl_Private.h"
/* 外部常量:标定配置可通过NVM加载,此处用宏 */
#define ZG_SLIDE_TARGET_MM-100// -10mm = -100 in 0.1mm
#define ZG_RECLINE_TARGET_DEG1250// 125.0°
#define ZG_CUSHION_TARGET_DEG150// 15.0°
#define ZG_LEGREST_PERCENT85// 85% 行程,预先转换为工程值
#define ZG_FOOTREST_TARGET_DEG0// 水平
/* 运动参数 */
#define MAX_SLIDE_SPEED200// 0.1mm/10ms = 20mm/s 对应每10ms 2.0mm=20 unit
#define MAX_RECLINE_SPEED50// 0.1°/10ms -> 5°/s
#define MAX_CUSHION_SPEED50
#define MAX_LEGREST_SPEED150// 15mm/s
#define PHASE1_DURATION_MS1500
#define PHASE2_DURATION_MS3000
/* 内部函数声明 */
static boolean ZG_CheckEntryConditions(void);
static void ZG_TrajectoryGenerator(void);
static void ZG_UpdateMotorCommands(void);
static void ZG_CheckMotionTimeout(void);
void ZG_StateMachine(void) {
/*读取输入信号已在其他Runnable中更新到镜像变量,这里直接使用镜像 */
booleanentryOk = ZG_CheckEntryConditions();
switch(zgState){
caseZG_IDLE:
if(pendingZgRequest == 1 && entryOk) {
zgState= ZG_MOVING_TO_ZG;
trajPhase= 1;
trajTimer= 0;
//记录起始位置用于轨迹规划
startPos= actualPos;
//设置零重力最终目标
zgTargetPos.Slide= ZG_SLIDE_TARGET_MM;
zgTargetPos.Recline= ZG_RECLINE_TARGET_DEG;
zgTargetPos.Cushion= ZG_CUSHION_TARGET_DEG;
zgTargetPos.Legrest= (ZG_LEGREST_PERCENT * maxLegrestTravel) / 100;
zgTargetPos.Footrest= ZG_FOOTREST_TARGET_DEG;
}
/*迎宾模式处理省略 */
break;
caseZG_MOVING_TO_ZG:
/*检查中断条件:手动开关操作、故障、碰撞等 */
if(crashStatus == 1) {
zgState= ZG_SAFE_STOP;
SetAbortCmd();
break;
}
if(faultHappened) {
zgState= ZG_FAULT;
SetAbortCmd();
break;
}
/*手动操作优先级最高:切换为手动,保存中断点 */
if(manualSwitchActive) {
zgState= ZG_MANUAL_OVERRIDE;
interruptedTarget= targetPos; /* 当前未完成的目标 */
SetAbortCmd();// 停止自动运动,释放电机给手动指令
break;
}
/*碰撞、开门等请参考设计;此处简化 */
//执行轨迹生成
ZG_TrajectoryGenerator();
//冗余防夹检测(在ZG_StateMachine内调用或由Diag监控)
if(ZG_RedundantAntiPinch()) {
zgState= ZG_INTERRUPTED;
DTC_Report(B1A04);
ReverseAndStop();
break;
}
//运动超时检查
if(ZG_CheckMotionTimeout()) {
zgState= ZG_FAULT;
DTC_Report(B1A05);
SetAbortCmd();
break;
}
//发出目标
ZG_UpdateMotorCommands();
//到位判断
if(AllAxisInWindow(targetPos, actualPos, tolerance)) {
zgState= ZG_ZG_ACTIVE;
trajPhase= 0;
SetMotorsDisable();// 保持位置,关闭使能以节能
}
break;
caseZG_ZG_ACTIVE:
if(pendingZgRequest == 2) { // 恢复请求
zgState= ZG_MOVING_TO_NORMAL;
//目标设置为记忆位置1或驾驶位置
targetPos= memoryPositions[memoryRecallSlot];
trajPhase= 1;
trajTimer= 0;
startPos= actualPos;
}
//行车自动退出逻辑
if(vehicleSpeed > 30 && gearPos != P) { // speed unit 0.01km/h: >0.3km/h
zgState= ZG_MOVING_TO_NORMAL;
targetPos= drivingPosition; // 预设的安全驾驶位置
trajPhase= 1; trajTimer = 0; startPos = actualPos;
}
break;
caseZG_MOVING_TO_NORMAL:
//类似MOVING_TO_ZG,轨迹调用了恢复运动算法
ZG_TrajectoryGenerator();
if(ZG_CheckMotionTimeout()) { ... }
ZG_UpdateMotorCommands();
if(AllAxisInWindow(...)) {
zgState= ZG_IDLE;
}
break;
caseZG_MANUAL_OVERRIDE:
//直接传递手动开关到目标位置(通过另一个函数处理)
//如果手动开关释放且用户再次请求继续,可恢复
if(!manualSwitchActive && continueRequest) {
zgState= ZG_MOVING_TO_ZG; // 从中断点继续?
trajPhase= determinePhase(currentActual);
startPos= actualPos;
}else if (manualSwitchActive) {
//手动目标由ManualProcessing直接输出到PPort_SeatCmd
ProcessManualMotion();
}
break;
/*其他状态类似 */
default:break;
}
/*更新HMI输出 */
Rte_Write_PPort_HmiOutput_ZgState((uint8)zgState);
Rte_Write_PPort_HmiOutput_Warning(warningMsg);
}
5.2 轨迹生成器
基于S曲线生成五个轴的目标位置,使用时间分段和二阶平滑,这里采用梯形速度加平滑。
static void ZG_TrajectoryGenerator(void) {
uint32t = trajTimer; // 当前时间,ms
trajTimer+= 10; // 增加10ms
if(zgState == ZG_MOVING_TO_ZG) {
//阶段1: 0~1500ms 滑轨+坐垫+腿托展开
if(t <= PHASE1_DURATION_MS) {
//滑轨:从初始位置到安全后位 (例-80mm)
targetPos.Slide= LinearInterp(startPos.Slide, SAFE_SLIDE_POS, t, PHASE1_DURATION_MS);
//坐垫倾角
targetPos.Cushion= LinearInterp(startPos.Cushion, ZG_CUSHION_TARGET_DEG, t, PHASE1_DURATION_MS);
//腿托展开部分
targetPos.Legrest= LinearInterp(startPos.Legrest, ZG_LEGREST_POS, t, PHASE1_DURATION_MS);
//靠背保持或者微动
targetPos.Recline= startPos.Recline;
//脚踏伺机
targetPos.Footrest= startPos.Footrest;
}
//阶段2: 1500~4500ms 靠背开始后仰,腿托继续,脚踏动作
elseif (t <= (PHASE1_DURATION_MS + PHASE2_DURATION_MS)) {
uint32t2 = t - PHASE1_DURATION_MS;
targetPos.Slide= SAFE_SLIDE_POS; // 保持
targetPos.Cushion= ZG_CUSHION_TARGET_DEG;
targetPos.Recline= LinearInterp(startPos.Recline, ZG_RECLINE_TARGET_DEG, t2, PHASE2_DURATION_MS);
targetPos.Legrest= LinearInterp(ZG_LEGREST_PARTIAL, ZG_LEGREST_POS, t2, PHASE2_DURATION_MS);
targetPos.Footrest= LinearInterp(startPos.Footrest, ZG_FOOTREST_TARGET_DEG, t2, PHASE2_DURATION_MS);
}
else{
//阶段3:精细到位,直接赋目标值
targetPos= zgTargetPos;
}
//TODO: 应用S曲线平滑速度约束,限制每周期增量
ApplySpeedLimit(&targetPos);
}
elseif (zgState == ZG_MOVING_TO_NORMAL) {
//恢复逆过程:先靠背回收,再滑轨前移
//分阶段实现
}
}
/* 辅助线性插值 */
static sint16 LinearInterp(sint16 start, sint16 end, uint32 curTime, uint32 totalTime) {
if(totalTime == 0) return end;
int32val = start + ( (int32)(end - start) * (int32)curTime ) / totalTime;
return(sint16)val;
}
5.3 运动命令输出与位置闭环
static void ZG_UpdateMotorCommands(void) {
//准备ControlWord: 使能电机,设置非回退
uint16ctrl = 0x0001; // Bit0 Enable
if(abortFlag) ctrl |= 0x0002;
Rte_Write_PPort_SeatCmd_ControlWord(ctrl);
Rte_Write_PPort_SeatCmd_TargetSlide(targetPos.Slide);
Rte_Write_PPort_SeatCmd_TargetCushion(targetPos.Cushion);
Rte_Write_PPort_SeatCmd_TargetRecline(targetPos.Recline);
Rte_Write_PPort_SeatCmd_TargetLegrest(targetPos.Legrest);
Rte_Write_PPort_SeatCmd_TargetFootrest(targetPos.Footrest);
}
5.4 进入条件评估
static boolean ZG_CheckEntryConditions(void) {
if(vehicleSpeed > 0) return FALSE;
if(gearPosition != 1) // P
returnFALSE;
if(doorStatus == 1) return FALSE;
if(crashStatus != 0) return FALSE;
if(scuFaultPresent) return FALSE;
//座椅占位等
returnTRUE;
}
5.5 冗余防夹检测
static boolean ZG_RedundantAntiPinch(void) {
//计算实际速度 = 当前位置变化 / 周期
staticSeatPosition_t lastActual;
SeatPosition_tspeed;
speed.Slide= actualPos.Slide - lastActual.Slide;
//....类似
//若指令目标速度为moveUp,但实际速度大幅低于预期则触发
if(expectedSlideSpeed > 10 && abs(speed.Slide) < (abs(expectedSlideSpeed)*0.3) ) {
if(lowSpeedCounter++ > 50) { // 500ms
lowSpeedCounter= 0;
returnTRUE;
}
}else {
lowSpeedCounter= 0;
}
lastActual= actualPos;
returnFALSE;
}
6、诊断SWC
ZgSeatDiag周期100ms执行,监控SCU上报故障、通讯超时,检测冗余防夹事件并报告DEM,可调用Dem_SetEventStatus()。
void ZgDiag_100ms(void) {
//读取SeatStatus的StatusWord
uint16status;
Rte_Read_RPort_SeatStatusDiag_StatusWord(&status);
if(status & SCU_FAULT_MASK) {
Dem_SetEventStatus(DemEventId_B1A00,DEM_EVENT_STATUS_FAILED);
}
//检查LIN超时(由BSW提供信号AliveCounter)
//防夹冗余检测如果发现在ZgSeatCtrl中触发,可通过内部接口报告,或此处独立计算。
}
7、建议
在OS中配置任务和调度:
·Task_10ms:周期10ms,调用ZG_StateMachine。
·Task_5ms:扫描LIN接收信号,触发ZG_ReceiveSeatFeedback; 也可合并到10ms。
·Task_100ms: 调用ZG_DiagReport和部分HMI刷新。
·ISR级别:碰撞信号通过CAN中断映射到ZG_CrashCallback直接置标志,保证50ms内停车。
注:虽然RTE在Data Received Event自动触发Runnable,但为了确定顺序,可将ZG_ReceiveVehicleSignals和ZG_ProcessHMI配置在ZG_StateMachine之前运行的同一任务中或由RTE保证数据一致性。
8、代码集成与配置注意事项
·信号映射:在System Description中将CAN信号映射到I_VehicleData接口数据元素;LIN信号从PDU映射到I_SeatFeedback。
·NVM配置:记忆位置和标定参数存储于NVM Block,通过NvM_ReadAll初始化时加载。
·标定参数可调:使用XCP/CCP或通过DID读取修改。
·复杂驱动:若LIN Tx直接由SCU要求,需确保ZgSeatCtrl的PPort_SeatCmd最终触发LIN发送;BSW层面配置LinIf传输请求。

夜雨聆风