3. 数据类型与信号:Simulink数据类型、总线信号、数据字典基础
做飞控代码生成,数据类型这块儿,我见过太多人栽跟头了。
你想想看,Simulink里默认都是double,仿真跑得飞起。一生成代码,好家伙,嵌入式芯片哪受得了这个?浮点运算又慢又占内存。所以这一章,咱们就把数据类型、总线信号、数据字典这几个硬骨头啃下来。
3.1 Simulink数据类型:别让double拖垮你的飞控
Simulink支持的数据类型挺多的。但做飞控,常用的就那几个:
| 数据类型 | 位宽 | 取值范围 | 飞控中典型用途 |
|---|---|---|---|
| double | 64位 | ±1.7e308 | 仿真调试、参数标定 |
| single | 32位 | ±3.4e38 | 姿态解算、控制律计算 |
| int16 | 16位 | -32768 ~ 32767 | 传感器原始数据(加速度计、陀螺仪) |
| uint16 | 16位 | 0 ~ 65535 | PWM捕获值、ADC采样值 |
| uint8 | 8位 | 0 ~ 255 | 状态机、标志位、遥控器通道 |
| boolean | 1位 | true/false | 解锁状态、故障标志 |
我个人习惯:控制律计算用single就够了。飞控的传感器精度也就16位,你用double算半天,最后输出给电机还是16位的PWM,纯属浪费。
核心原则:能用定点不用浮点,能用单精度不用双精度。代码生成后,RAM和Flash能省下一大半。
3.2 总线信号:把散乱的信号装进一个篮子里
飞控系统里信号太多了。加速度计三个轴、陀螺仪三个轴、磁力计三个轴、GPS经纬高……你如果一根一根线连,模型图能画到天上去。
总线信号就是干这个的。它把相关的信号打包成一个整体。
3.2.1 虚拟总线 vs 非虚拟总线
这里有个坑,我刚开始做的时候踩过。
- 虚拟总线:只在Simulink里存在,生成代码时会被展开。说白了就是个视觉上的分组工具。
- 非虚拟总线:生成代码时会保留为结构体。这个才是我们真正需要的。
我建议:只要涉及到代码生成,一律用非虚拟总线。怎么设置?在Bus Creator模块上右键,勾选「Output as nonvirtual bus」就行。
注意:非虚拟总线要求所有输入信号的数据类型必须一致。如果你把int16和single混在一起,Simulink会报错。解决办法是用Data Type Conversion模块统一类型。
3.2.2 总线对象的定义
用Bus Editor定义总线对象,这是标准做法。
// 生成代码后,总线会变成这样的结构体
typedef struct {
int16_T x;
int16_T y;
int16_T z;
} IMU_Accel;
typedef struct {
IMU_Accel accel;
IMU_Gyro gyro;
IMU_Mag mag;
} IMU_Data;
你看,代码里清清楚楚。以后维护起来,看结构体就知道数据怎么组织的。
3.3 数据字典:把参数和模型解耦
做飞控最怕什么?参数写死在模型里。
你今天调个PID参数,明天改个滤波系数,每次都要打开模型改常数模块。改完还得重新生成代码,烦不烦?
数据字典就是解决这个问题的。
3.3.1 什么是数据字典
说白了,就是一个中央仓库。所有参数、数据类型、总线定义都放在里面。模型通过名字去引用,而不是直接写数值。
我的经验:把数据字典和模型文件分开管理。模型里只放逻辑,字典里只放参数。这样团队协作时,一个人改参数,另一个人改逻辑,互不干扰。
3.3.2 创建数据字典的步骤
- 在MATLAB里输入
Simulink.data.dictionary.create('myDict.sldd') - 在Model Explorer里添加参数条目
- 在模型中使用
myParam这样的变量名 - 将模型关联到数据字典
举个例子。你有一个PID比例系数 Kp:
// 在数据字典中定义
Name: Kp_Roll
Value: 2.5
DataType: single
StorageClass: ExportedGlobal
// 在模型中使用
增益模块直接填 Kp_Roll
// 生成代码后
extern real32_T Kp_Roll; // 可以在外部修改
这样,你只需要修改数据字典里的数值,重新生成代码,参数就更新了。模型本身不用动一根线。
3.4 知识体系总览
这一章的内容,我用一张图给你捋清楚:
3.5 避坑指南
最后,分享几个我实际项目中踩过的坑:
- 我曾经把加速度计数据用double传给总线,结果生成的结构体里每个字段都是64位。一个IMU数据结构体就占了48字节。改成int16后,直接缩到6字节。
- 还有一次,数据字典里定义了一个参数叫Kp,模型里也用了Kp。但同事在另一个分支里把Kp改成了Kp_Roll。合并代码时,模型找不到参数,编译报错。所以命名规范一定要统一。
- 嗯,这里要注意:数据字典的StorageClass选ExportedGlobal,生成的变量才是全局可访问的。如果选Auto,编译器可能把它优化掉,你外部程序就改不了参数了。
小技巧:调试阶段,可以在数据字典里把参数都设成ExportedGlobal。等代码稳定了,再根据需要调整存储类型。这样前期调试方便,后期优化也灵活。
数据类型、总线信号、数据字典,这三样东西搞明白了,你的Simulink模型才算真正具备了工程落地的能力。别嫌麻烦,前期多花点时间定义清楚,后面代码生成和调试能省下几倍的时间。
公众号:蓝海资料掘金营,微信deep3321