ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

1M CAN总线挑战超高刷新率:全掌触觉矩阵协议优化实践

1M CAN总线挑战超高刷新率:全掌触觉矩阵协议优化实践 说到“1M CAN总线挑战超高刷新率”很多人的第一反应是1Mbps不是已经不低了吗但如果把一整块手掌矩阵触觉反馈都挂在上面情况立刻变复杂了。这个项目本质上要回答一个问题在标准CAN 2.0只有1Mbps带宽的条件下要让全掌矩阵触觉设备实现看起来“超高”的刷新率到底靠什么结论很简单不靠把总线跑得更快而靠把每一帧写得更满、把协议设计得更省、把总线错误控制得更稳。下面这套拆解适合正在做触觉矩阵、分布式I/O或CAN总线项目的人参考。我会从带宽计算、硬件架构、协议设计、代码落地、实测验证到干扰排查按实际开发顺序讲一遍。最后也会给出我觉得可以复现的阶段路径。1. 先算清楚1Mbps不是1Mbps应用吞吐1.1 一帧数据到底消耗多少总线时间很多人只看到“1Mbps”这个数字以为每秒能传1M位的数据也就是125KB/s。但CAN总线不是这么算的。标准CAN数据帧除了8字节数据本身还包含SOF、仲裁段、控制段、CRC、ACK、EOF和帧间隔。一个标准帧、8字节数据、不计算位填充时总位数在111位左右。实际传输中还会因为位填充多出几个bit平均下来一帧占用120位上下。所以1Mbps总线上每秒最多能传的完整8字节数据帧大约只有8300帧左右。换算成应用层有效吞吐也就500多kbps而不是1Mbps。更进一步如果总线负载率跑到80%以上仲裁延迟和错误重传会让刷新率变得不稳定。实际可用的应用吞吐量按70%到80%负载算只剩400kbps上下甚至更低。这是个很关键的边界。协议设计如果不考虑CAN帧本身的开销很容易在计算吞吐时错得离谱。1.2 全掌矩阵的带宽账本全掌矩阵可以理解为手掌区域分布了若干个触觉单元比如8个节点每个节点16个触点总共128个点。每个点用8位表示强度值。如果目标刷新率是1kHz那么每秒需要传输的数据量是128点 × 8位 × 1000Hz 1024kbps这个数字已经超过1Mbps物理带宽还没算CAN帧头、CRC、填充位和帧间隔。所以“全掌128点、8位、全量刷新、1kHz”在标准CAN 2.0下基本不成立。哪怕把刷新率降到500Hz数据量也有512kbps。加上CAN帧开销后总线负载会突破100%。所以如果要做全量刷新就需要降低点数、降低位深或降低刷新率。一个相对可行的配置是32个触点、8位、刷新率1kHz数据量32 × 8 × 1000 256kbps每帧8字节可以放8个点的强度32个点需要4帧每秒4000帧每帧约120bit帧总开销约480kbps数据加帧开销约736kbps负载已经接近75%到80%这个负载还能跑但已经没多少余量。一旦出现CAN错误帧或者某条消息需要重传刷新率就会出现肉眼可见的抖动。所以真正可行的“超高刷新率”一定不是在每个周期把全部触点都重新发一遍。这里留给协议层的空间还很大。2. 系统架构主控、从节点和触觉单元怎么分工2.1 为什么不直接让主控控制每一个触点如果手掌矩阵只有8个或16个触点主控MCU的GPIO够用直接用引脚控制也没问题。但全掌矩阵一旦扩大到几十上百个触点直接由主控一根一根线引到每个触点线束会非常夸张驱动功率也不够集中。更麻烦的是所有触点如果由主控连续写GPIOIO翻转顺序不同触觉点之间的时间差会很明显。CAN总线的优势在这里体现得很明显总线只需要两根线所有从节点并联在总线上。每个节点负责一小块触点区域主控只需要把目标状态通过CAN帧广播出去节点收到后并行更新自己的触点。这样线束少、节点独立、扩展性好刷新率也可以做到多通道同步。2.2 一种可落地的硬件拆分主控侧推荐用带CAN外设的MCU常见选择是STM32F4系列。主控的任务不是直接驱动每个触点而是维护触觉状态表把状态转换成CAN帧发到总线上。CAN收发器用TJA1050这类常规型号就行如果节点供电分散或者周围有大功率执行器建议用隔离CAN收发器比如ISO1050避免地环路干扰。从节点侧不需要太强的主控。每个从节点负责8到16路PWM输出选一颗带CAN外设的低功耗MCU就够了。PWM输出不够时可以外接串转并驱动芯片或专用PWM驱动比如TLC5940这类芯片由从节点MCU通过SPI把强度值刷进去。触觉单元的选择也要考虑响应速度。如果目标刷新率是几百赫兹以上偏心振动马达这类机械响应偏慢的执行器会拖后腿。更适合高刷新率场景的是线性谐振器、压电式触觉单元或者电磁驱动的微型线圈。它们响应快高频下还能保持较明显的触觉反馈。2.3 同步是分布式触觉的隐形关键多个从节点各自接收CAN帧各自更新PWM输出。如果每个节点在自己的时间点提交PWM数据那么手掌不同区域会产生“滚动刷新”感严重时能感觉到左右两侧触觉不同步。解决办法是在协议层加同步帧。从节点先把收到的强度值写入缓冲区但先不提交给PWM寄存器。等到主控广播一个同步帧所有从节点在收到同步帧后同时提交。这样整掌矩阵的更新时刻基本一致触觉刷新率才有意义。同步帧的CAN ID必须设得比数据帧低因为CAN仲裁机制会让ID小的消息优先发送。同步帧是全局时钟优先级必须最高。3. 协议层优化怎么把每个8字节都塞满3.1 自定义帧格式CAN数据帧最多只能带8字节所以协议设计的第一原则是不要把地址、命令、长度这些信息浪费在数据区里太多次。能放进CAN ID里的信息就不要占用数据字节。我实际用起来比较顺手的一种格式是这样CAN标准ID高位表示帧类型0x000表示同步帧0x100表示全量刷新帧0x200表示差分更新帧。ID低8位表示目标节点编号。全量刷新帧的数据格式第0字节是起始通道号第1到第7字节是7个通道的强度值。这样一帧最多更新7个触点。差分更新帧的数据格式第0字节是通道掩码后面是按掩码排列的强度值第7字节可以留作序号或校验。这种格式有一个好处主控不需要在每帧里重复发送节点号。目标节点已经写在CAN ID里了数据区全部用来放触觉强度。8字节利用率高。如果你的触觉单元只需要6位或7位分辨率也可以把多个通道的强度压缩到更少的字节里。比如一帧8字节放12个4位强度值适合对幅值精度要求不高的场景。但要注意位深减少之后PWM输出需要做线性映射。是否值得压缩要看实际触觉效果。3.2 全量刷新、差分刷新和扇区交织全量刷新最容易理解每个刷新周期把所有触点的强度全部发一遍。优点是主从状态一致任何时刻从节点都能知道自己该输出什么。缺点太明显刷新率上限低。差分更新只有在触点状态发生变化时才发数据。如果某一帧只有2个触点变了就只发这2个触点的变化。这样带宽占用大幅降低等效刷新率可以拉得比较高。缺点是如果丢了一个差分帧主控和从节点的状态就会不一致。所以差分更新不能完全脱离全量刷新必须每隔一段时间发一次全量帧兜底还要在协议里加帧序号从节点发现序号跳变后可以主动请求同步。扇区交织是另一个思路。全掌矩阵分成几个扇区每个总线周期只更新其中一个扇区。比如把128个点分成4个扇区每个扇区32个点那么每个扇区的全量刷新率可以做到目标刷新率的四分之一。对于空间变化比较平滑的触觉纹理手指通常感觉不到哪个扇区刚刚被刷新过。这种方案很适合“扫描式”的触觉反馈比如在手掌上模拟物体移动的感觉。实际项目里全量、差分和扇区交织可以组合使用。周期用扇区交织做全量兜底空间变化集中的区域用差分帧做高频更新。这样既保证状态一致又能在有限的CAN带宽里挤出更高刷新率。3.3 让CAN ID成为协议的一部分CAN协议本身有非破坏性仲裁机制总线上多个节点同时发送时ID小的消息会优先占用总线。这个特性可以好好利用。同步帧用ID 0x000优先级最高。全量刷新帧用ID 0x100系列优先级其次。差分更新帧用ID 0x200系列优先级最低。这意味着当总线繁忙时最重要的是先保证同步帧和全量帧发出差分帧可以被仲裁等待不会破坏全局刷新。很多新手在设计CAN应用时随便给消息分配ID没有考虑仲裁优先级。这在低速场景下没问题但在接近1M极限时会影响刷新稳定性。尽量使用标准帧而不是扩展帧。扩展帧的ID段更长帧开销也更大在需要抠带宽的项目里不划算。4. 代码落地从初始化到定时刷新4.1 CAN 1Mbps初始化注意点CAN波特率配置要看具体MCU的外设时钟。以常见STM32为例1Mbps需要合理分配预分频、位段1和位段2。采样点建议设置在80%左右也就是总线位时间的前80%采样后20%用于跳变。这样对总线信号质量的要求最稳。下面这段是示例结构实际寄存器名称以你的开发环境为准/* 伪代码CAN 1Mbps 初始化 */ CAN_InitTypeDef can; can.CAN_SJW CAN_SJW_1tq; can.CAN_BS1 CAN_BS1_8tq; can.CAN_BS2 CAN_BS2_7tq; can.CAN_Prescaler 1; can.CAN_Mode CAN_Mode_Normal; can.CAN_ABOM CAN_ABOM_Enable; can.CAN_TTCM CAN_TTCM_Disable; can.CAN_AWUM CAN_AWUM_Enable; can.CAN_NART CAN_NART_Disable; CAN_Init(CANx, can);注意CAN_TTCM也就是时间触发通信模式如果芯片支持可以关闭。ABOM自动离线恢复建议开启这样总线出现短暂Bus Off后能自动恢复。NART关闭的意思是允许自动重传对于周期刷新帧来说自动重传通常有帮助但如果频繁重传反而会堵塞总线。实际测试时我会根据错误帧数量和刷新率要求动态决定。4.2 主控发送流程主控不要在while主循环里随手调用CAN发送函数。更稳的做法是用一个定时器产生刷新周期中断在中断里读取触觉状态表打包成CAN帧发送。原因很简单主循环里可能有日志输出、外部事件、界面刷新等耗时操作碰到这些操作时发送周期就会被拉长刷新率抖动。放在定时器中断里刷新周期稳定总线上的帧间隔也均匀。可以用双缓冲。主循环负责更新下一帧的强度数据写入缓冲区A定时器中断发送时读缓冲区B发送完成后交换AB。这样发送的数据始终是完整一致的不会出现读到一半被修改的情况。发送时注意CAN的发送邮箱。如果上一帧还在等待重传新的发送请求会排队。连续高负载时要检查发送状态寄存器避免邮箱溢出造成覆盖。更简单的办法是保证每帧间隔足够不给上一帧留太多延迟。4.3 从节点接收与PWM更新从节点收到CAN帧后先不要急着在接收中断里做大量运算。接收中断只做两件事把CAN帧数据复制到RAM缓冲区置一个“收到新帧”的标志。然后主循环看到标志后解析帧内容更新PWM寄存器数组。这样做的原因是接收中断优先级通常很高如果中断里做循环、乘除、甚至打印会拖慢整个MCU的其他任务。尤其在多个节点满负载接收时中断退出延迟会直接影响节点刷新率。更新PWM输出时最好不要逐个通道地改比较寄存器。可以先把所有通道的新值放到临时数组全部准备好之后一次性提交给PWM模块。很多MCU的定时器支持直接写入多个通道寄存器写入顺序并不会有太大影响。但为了保险提交前要确保数据已经完整解析。/* 伪代码从节点收到全量刷新帧 */ void handle_full_frame(uint8_t start_ch, uint8_t *data) { /* 先把数据写入影子寄存器 */ pwm_shadow[start_ch 0] data[0]; pwm_shadow[start_ch 1] data[1]; /* ... */ /* 全部更新后再提交 */ pwm_commit(pwm_shadow); }影子寄存器的思路是让所有通道的PWM值在同一时刻生效。如果MCU硬件不支持影子寄存器也可以在收到同步帧之后再往PWM寄存器里写入这样所有节点会在同步帧到来时集中更新。5. 怎么衡量刷新率真的上去了5.1 推荐工具不要靠主控里的变量值或者串口打印来判断刷新率。串口打印本身会打断发送流程测出来的数字不可信。更推荐用三类工具CAN分析仪用于统计总线负载率、每秒帧数、错误帧数量。示波器用于测量从节点实际PWM刷新频率和同步脉冲。逻辑分析仪方便观察多路PWM输出之间的相位关系。5.2 三个验证步骤第一步测总线真实负载。让主控连续发送全量刷新帧用CAN分析仪统计1秒内的总线负载率和平均帧率。这个数字应该接近理论计算如果差太远先检查波特率配置和终端电阻。第二步测节点实际刷新率。从节点在提交PWM数据时翻转一个GPIO用示波器测这个GPIO的方波频率。这个频率就是节点实际的刷新率简单直接。第三步对照设计目标。比如设计目标是16个触点、8位强度、刷新率2kHz。实际测出来如果只有1.2kHz就要看总线负载率是否超出预期以及是否有错误帧在占用总线时间。下面这个表是我测试时常用的判断标准总线负载率刷新表现处理建议低于50%很稳节点刷新率高错误帧很少可以继续加节点或提高刷新率50%到80%可用偶发仲裁延迟多测几次观察抖动是否影响触觉高于80%容易出现错误帧或不稳定降低刷新率或启用差分/扇区优化实测时最直接的感觉是当总线负载超过80%后从节点PWM刷新频率会出现明显的间歇性抖动。示波器上能看到方波周期不再均匀这是因为CAN仲裁和重传让帧到达时间变得不规整。所以无论协议怎么优化我都会在设计中预留至少20%带宽余量。5.3 负载率看着不高但刷新率还是上不去怎么办先确认CAN分析仪统计的负载率是不是只算了数据帧没有把错误帧算进去。错误帧会额外占用总线时间而且会触发重传导致有效数据帧间隔被拉长。看一眼错误计数器如果TEC或REC持续上涨问题一定在物理层或总线节点状态上。再确认从节点的接收处理是不是被阻塞了。如果从节点在中断里做了耗时操作比如长时间访问I2C或打印日志即使总线负载率不高节点内部也会丢帧或延迟提交PWM。此时CAN总线是通的但刷新率被MCU自己拖慢。最后检查帧发送频率是否均匀。如果CAN发送只在某个事件触发时才发送而不是固定周期发送那么刷新率数据没有参考意义。刷新型项目必须用定时器产生固定周期事件只负责改变状态表内容不负责改变发送节奏。6. 刷新率突然不稳先查物理层和错误帧6.1 错误帧为什么直接拖垮刷新率CAN总线的错误帧一旦出现会立刻破坏当前正在传输的帧导致发送节点自动重传。一个错误帧加上重传可能占用好几个帧的时间。如果错误频率高总线负载会虚高有效刷新率直线下降。很多人在项目里遇到“刷新率上不去”第一反应是去优化协议把帧格式改来改去。但实际排查后经常发现问题根本不是协议而是CAN_H和CAN_L差分信号质量太差。6.2 排查顺序我一般按这个顺序查效率比较高看CAN控制器错误计数器。TEC和REC是否持续增加。如果增加说明总线上有节点在持续制造错误。看错误帧类型。CAN分析仪通常会区分位错误、CRC错误、形式错误等。CRC错误多通常和信号质量或终端电阻有关位错误多可能是波特率不匹配。量波形。用示波器看CAN_H和CAN_L的差分幅值。正常时显性电平差分电压应在1.5V到3V之间如果波形畸变、斜率过缓检查线束和终端电阻。检查终端电阻。1Mbps下总线两端必须各有一个120欧姆终端电阻。分支线要短最好不超过几十厘米。没有终端电阻波形反射会非常严重。查供电和共地。如果多个从节点使用不同的电源适配器供电地电位不一致会产生共模电压。条件允许时用隔离CAN收发器或者在收发器电源端加去耦电容。6.3 触觉单元带来的干扰怎么处理全掌触觉设备里执行器如果是电磁马达或电感线圈关断瞬间会产生反电动势。这种干扰会通过电源线耦合到CAN收发器导致错误帧增多。一个有效的办法是让执行器电源和CAN收发器电源分开。执行器用功率电源收发器用独立线性电源或经过隔离的电源。如果条件受限必须共用就在执行器两端加续流二极管和RC吸收电路同时在CAN收发器电源入口加磁珠和大容量去耦电容。总线入口还可以加共模电感抑制共模干扰。至于“外壳加电容”的做法是把CAN收发器附近的信号地通过一个小容量电容接到金属外壳地。这个电容的作用是给高频共模噪声一个泄放路径避免噪声进入总线。电容值不能太大一般几纳法到几十纳法之间如果加太大会影响CAN差分信号边沿。排查时一定要看错误帧在触觉单元开始动作的瞬间是否变多。如果是那干扰源基本就在执行器驱动回路里。这时候不要急着调CAN波特率先解决功率回路的干扰。7. 1M极限下的取舍全量、差分还是扇区7.1 三种模式的适用场景对比模式优点缺点适合场景全量刷新实现简单主从状态一致刷新率上限低点数少带宽充足差分更新带宽占用低高频变化更灵活有丢帧风险需要兜底同步触点状态变化稀疏扇区交织峰值带宽低空间平滑场景感知好单点响应延迟可能增加纹理扫描、滑动反馈实际项目里我建议不要只用一种。全量刷新做低频兜底差分更新做高频区域变化扇区交织负责降低整掌更新的峰值压力。三者组合起来才能在1Mbps下达到“感知上的超高刷新率”。具体怎么组合要看触觉内容是什么。如果是类似触摸纹理扫描相邻触点变化通常不多差分更新收益最大。如果是整个手掌同时振动变化点很多扇区交织更合适。如果只是几个独立震动点用差分就够了不需要扇区。7.2 还需不需要升级到CAN FDCAN FD把数据段速率提升到5Mbps甚至更高是打破1M瓶颈最直接的方法。如果项目未来还要扩展更多触觉点CAN FD确实省心很多。但在只有普通CAN收发器的环境里把波特率强行拉到超过1M是不符合标准的错误率会大幅上升。更稳妥的做法是先把当前1Mbps总线上的协议做干净再考虑换用支持CAN FD的MCU和收发器。协议层的打包、差分、扇区逻辑在CAN FD上依然有效升级总线不会浪费之前的工作。7.3 真正算“挑战成功”的标准我认为这个项目能不能算挑战成功不取决于刷新率数字高不高而取决于能不能在有限带宽下保持触觉输出稳定、一致、低延迟。如果一个128点系统通过差分和扇区优化让主观触觉连续性达到很高水平即使某些点全量刷新率只有500Hz也比一个32点系统硬跑2kHz但抖动明显更有意义。毕竟触觉刷新率不是单纯物理指标最终还是要回到体验。8. 想复现这个项目先按这个顺序走8.1 分阶段推进不要一上来就想在8个节点上同时做全掌高刷。我建议把复现拆成四个阶段每个阶段有明确的验证标准。第一阶段单节点、单点PWM。主控通过CAN发送一帧简单的强度值从节点收到后控制一个触觉点输出PWM。这个阶段先把CAN初始化、收发、PWM输出链路跑通。第二阶段单节点、多点打包。从同一个节点扩展出多个PWM通道让主控在一帧里发送多个通道的强度值。验证点在于能否一帧更新多个通道以及PWM输出之间的同步性。第三阶段多节点同步。用同步帧让多个从节点在同一时刻提交PWM数据。验证点在于不同节点的PWM输出是否同时跳变示波器上能不能看到对齐的边沿。第四阶段协议优化。加入差分更新和扇区交织测量总线负载率和实际刷新率。验证点在于相同目标刷新率下总线负载率是否明显下降刷新过程中是否还稳定。每个阶段都要有日志输出。从节点记录收到的帧序号和本地提交时间戳主控记录发送时间和帧序号。出现问题时把主从日志放一起对比就能很快定位是发送乱序、接收丢帧还是同步丢失。8.2 几个从踩坑里得来的提醒别在CAN接收中断里做耗时处理。哪怕只是打印一行串口日志都可能打断其他节点的接收导致刷新率掉一大截。预留带宽余量。所有计算都要按“数据加CAN帧开销”来算不能用纯数据量对比1Mbps。实际负载超过75%后刷新稳定性就开始变差最好给自己留出至少20%的空间。所有节点必须共地或者使用隔离CAN。CAN总线强依赖参考地。如果节点之间地电位差过大波形会很差错误帧和重传也会增多。遇到“刷新率上不去”先查错误帧再改协议。很多时候一个简单的终端电阻问题会让整个系统看起来像协议设计不行。CAN分析仪的负载率和错误计数应该成为每次测试的固定记录项。最后不要迷信高刷新率数字。真正确认一个刷新率合不合理要看触觉感受、节点同步性和总线负载三者是否都达标。单看任何一个指标都很容易在项目后期回头返工。
返回列表