【开源】CANFESTIVAL协议栈下的CANopen主站

2020-01-03 19:07发布

本帖最后由 zhenglingo 于 2015-5-24 16:26 编辑

       这个工程是CANFESTIVAL开源协议栈移植到STM32F4中的CANopen主站,在公司里做总线式控制器通信部分,主要实现DS301和DS402标准,利用周末的时间搭建出来的基本通信框架,给正在学习CANopen的朋友做一个参考,其实网络上也有很多移植到各个平台下的,前期我也看了很多,但是到运用的时候才发现还有很多东西需要自己去理解,运用和移植完全是两码事,如果你的产品中用不到CANopen,理解下它的通信模型还是很不错的,比如生产者-消费者,客户端-服务端,主-从等通信模型在CANFESTIVAL都已经实现了。CANopen其实资料也非常多,推介周立功翻译的 《现场总线CANopen设计与应用》看一遍,基本上就明白CANopen的思想了,至于CANFESTIVAL多看看官方的例程也能明白通信对象的使用方法。 移植和概念是第一步,第二步是产品的应用,说说我在这方面的体会,之前我也没有接触过CANOpen,只用过CAN做一般的通信,CAN协议其实比较完善了,有自动重传,总线仲裁,错误检测等,但是这只是物理层的优势,没有一个好的应用层,还是发挥不了它的优势,CANopen就是针对CAN之上的应用层。之前我们的控制器是脉冲式的,考虑到节约成本决定尝试用总线式通信控制伺服电机,小弟也刚接触这个行业,公司里主从CANopen都需要做,现在从站通信基本上已经完成,已经能够让伺服电机转起来,我们是使用402里的插补模式,其他模式是否需要同步我暂时没了解过。总线式的运动控制器优点很多,如果伺服选择插补模式,用CAN做物理层还是比较欠缺的,用CAN做物理层,同步周期1MS最多可以实现3个轴联动,以1Mbit/S速率计算发送一个BYTE需要8us,正常运行时,主站发送一帧PDO数据一般由:2BYTE ID+1BYTE 长度+ 4BYTE插补值+2BYTE控制字+2BYTE CRC = 11BYTE,我们以同步周期1MS来算,主站发送一帧PDO数据就占用88US,加上从站需要处理这帧数据,处理完后返回一帧编码器的值+状态字时间和发送PDO一样,这样就需要将近200多us的时间(包括从站处理主站PDO的时间),一个轴就需要200多us,所以能做到3轴已经很不错了,况且如果整个同步周期都是数据,如果任意时刻出现干扰整个系统就非常危险,这在运动控制器里是不允许的,当然如果你的运动控制不做闭环的,只发位置下去,1MS做多轴应该是可以的,但这样谁还敢用?CAN做物理层高速还是不合适,只能用在精度不高的场合中,高速还是需要用以太网。
    代码已经实现了主站PDO,SDO,插补值映射,读取从站编码器值,目前是两轴,简单更改下就可以改成4轴,我希望大家可以多多交流CANopen在产品设计中的经验和遇到的问题,如果代码中有运用不对或者分析有不对的地方欢迎拍砖!
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
100条回答
996512682
2020-01-11 07:56
楼主这个部分
  1. /* index 0x1A00 :   Transmit PDO 1 Mapping. */
  2.                     UNS8 ObjDict_highestSubIndex_obj1A00 = 3; /* number of subindex - 1*/
  3.                     UNS32 ObjDict_obj1A00[] =
  4.                     {
  5.                       0x60400110,
  6.                       0x60c10220,  
  7.                     };
  8.                     subindex ObjDict_Index1A00[] =
  9.                      {
  10.                        { RW, uint8, sizeof (UNS8), (void*)&ObjDict_highestSubIndex_obj1A00 },
  11.                        { RW, uint32, sizeof (UNS32), (void*)&ObjDict_obj1A00[0] },
  12.                                                                                          { RW, uint32, sizeof (UNS32), (void*)&ObjDict_obj1A00[1] },
  13.                                                                                          { RW, uint32, sizeof (UNS32), (void*)&ObjDict_obj1A00[2] },
  14.                      };
复制代码
为什么ObjDict_obj1A00这个数组只有两个元素,下面却用了三个呢?

一周热门 更多>