M5Stack的CAN BUS通讯-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 4983|回复: 1

M5Stack的CAN BUS通讯

[复制链接]
发表于 2020-8-14 11:31 | 显示全部楼层 |阅读模式
本帖最后由 vany5921 于 2020-8-14 11:35 编辑

      尝试使用MCP2515使用CAN BUS模块发送和接收以M5Stack Gray内置的IMU数据。CAN(控制器局域网)是一种用于汽车的具有高抗噪性的通信标准。 CAN BUS模块的布线速度最高为1 Mbps,仅需要两条电缆CANH / CANL,因此我认为它实际上很容易用于业余爱好。这次,我尝试使用内置的IMU在CAN上发送和接收带有相对大量信息的数据。
https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_333764_997dba5f-2414.jpeg
构成:
  • M5Stack Gray(IMU消息发送)
  • CAN BUS模块1CAN BUS模块2Arduino MegaPC(Processing可视化)
对于CAN BUS模块,我使用了在亚马逊上经常看到的两个模块。MCP2515用于CAN控制器,TJA1050用于CAN收发器,并且可以通过SPI与微型计算机连接。 CAN 120Ω终端电阻也可以通过跳线启用。如上所述,所购买的产品配备有8MHz的晶体振荡器。 只要此处的设置正确,就可以与其他CAN BUS模块通信。

M5Stack(发送方)和CAN BUS模块
如下所示进行SPI连接
截屏2020-08-14 上午11.33.24.png
由于M5Stack的SPI为3.3V类型,因此3.3V也提供给CAN BUS模块。 另外,这次仅从M5Stack侧进行传输,因此没有任何东西连接到INT。 顺便说一句,CS只需要一个数字引脚,但是它将被限制为一个引脚选项,可以通过使用内置LCD和IMU在不产生扬声器大声噪声的情况下使用它。顺便说一句,不要使用不可靠的杜邦线(我在这里花了一个小时)。
Arduino Mega(接收器)和CAN BUS模块
如下所示进行SPI连接
截屏2020-08-14 上午11.34.07.png
我偶然遇到了一个Arduino Mega,因此尝试使用它,但是我认为Uno没问题(尽管SPI连接发生了变化)。 发送端的M5Stack没有建立INT连接,但是在接收端,它与中断兼容引脚相连。 这是为了在PC端启用中断接收。

程序
CAN_BUS_Shield库用于CAN BUS模块控制程序,M5Stack MPU9250示例用于M5Stack侧IMU控制程序,该程序直接用于处理。

1.M5Stack侧程序
这是M5Stack示例程序(MPU9250BasicAHRS.ino)所做修改的摘录。在此程序中,将从IMU(MPU9250)获取的四元数的4个元素(浮点数)赋予不同的ID,并与时间戳一起发送到CAN。 我不确定该方法是否正确,但是暂时将其作为对向CAN高速数据传输的测试。

  1. #define CAN_OUT
  2. /*CAN settings*/
  3. #include <mcp_can.h>
  4. const int SPI_CS_PIN = 5;
  5. MCP_CAN CAN(SPI_CS_PIN);
  6. unsigned char stmp[8] = {0, 0, 0, 0, 0, 0, 0, 0};
复制代码
加载<mcp_can.h>, 不要忘记安装CAN_BUS_Shield库。使用SPI_CS_PIN配置用于SPI器件选择的数字引脚。 在M5Stack的情况下,由于许多引脚与LCD和扬声器等内置设备共享,因此,如果您选择错误,LCD将无法工作或扬声器会发出很大的噪音,这很奇怪。
在stmp [8]上准备了用于发送到CAN的消息缓冲区。* CAN规范的结构为id 11位和数据64位(8字节)。

  1. void sendCanMsgFloat(unsigned long id, unsigned long timestamp, float val){
  2.    union {
  3.              float f;
  4.              unsigned char b[4];
  5.    } ftob;
  6.   ftob.f = val;
  7.   union {
  8.             unsigned long l;
  9.             unsigned char b[4];
  10.   } ultob;
  11.   ultob.l = timestamp;

  12. stmp[0] = ultob.b[3];
  13. stmp[1] = ultob.b[2];
  14. stmp[2] = ultob.b[1];
  15. stmp[3] = ultob.b[0];   
  16. stmp[4] = ftob.b[3];
  17. stmp[5] = ftob.b[2];
  18. stmp[6] = ftob.b[1];
  19. stmp[7] = ftob.b[0];

  20. CAN.sendMsgBuf(id, 0, 8, stmp);
  21. delay(2);
  22. }
复制代码
该功能实际上是将数据发送到CAN的功能。 一种数据结构用于将float和unsigned long(假设时间戳记)转换为字节格式。 由于在Arduino上均为32位,因此发送到CAN的数据总计为64位。在字节顺序方面,我更改了顺序,因为Arduino的字节序为Little Endian,而CAN BUS的字节序为Big Endian(网络字节序)。

  1. #ifdef CAN_OUT
  2. while (CAN_OK != CAN.begin(CAN_500KBPS, MCP_8MHz)) {         // init can bus : baudrate = 500k
  3.      Serial.println("CAN BUS Shield init fail");
  4.      Serial.println(" Init CAN BUS Shield again");
  5.      delay(100);
  6. }
  7. Serial.println("CAN BUS Shield init ok!");
  8. #endif //CAN OUTPUT
复制代码
初始化CAN设备。 根据要连接的CAN模块的工作频率设置MCP_8MHz部分。 似乎可以在CAN_BUS_Shield库中选择MCP_16MHz。 此部分中的设置不正确将阻止与其他CAN设备的正常通信。 (在8MHz的情况下,我认为很难进行1Mbps的CAN通信。)CAN_500KBPS部分定义了CAN BUS通信速度。

  1. M5.Lcd.setCursor(0,  120);
  2. M5.Lcd.printf("  q0:% 5.2f qx:% 5.2f qy:% 5.2f qz:% 5.2f \r\n",(*getQ()), (*(getQ() + 1)), (*(getQ() + 2)), (*(getQ() + 3)));//print quaternion
复制代码
我试图在M5Stack的LCD上显示四元数。
  1. #ifdef CAN_OUT
  2.     sendCanMsgFloat(0x01, IMU.count, *getQ());
  3.     sendCanMsgFloat(0x02, IMU.count, *(getQ() + 1));
  4.     sendCanMsgFloat(0x03, IMU.count, *(getQ() + 2));
  5.     sendCanMsgFloat(0x04, IMU.count, *(getQ() + 3));
  6. #endif
复制代码
使用上述功能,将四元数的每个元素发送给具有不同ID和时间戳的CAN。
打开用opendiff软件,对比修改后的文件。
https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_333764_897cd12f-259f.png
https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_333764_3d0faea0-efa2.png

Arduino Mega程序
Arduino Mega端对从CAN BUS获取的M5Stack IMU数据进行解码,并通过串行通信将其中继到正在处理的查看器。 CAN_BUS_Shield库示例程序receive_check.ino用于CAN的接收部分。

  1. /*for processing*/
  2. uint8_t teapotPacket[14] = { '此功能将解码的IMU四元数信息转换为处理程序可以使用的格式。 我已经在本文中使用过一个。
  3. [code] //SERIAL.println("-----------------------------");
  4. //SERIAL.print("Get data from ID: 0x");
  5. //SERIAL.println(canId, HEX);

  6. //for (int i = 0; i < len; i++) { // print the data
  7. //    SERIAL.print(buf[i], HEX);
  8. //    SERIAL.print("\t");
  9. //}
  10. union {
  11.      float f;
  12.      unsigned char b[4];
  13. } ftob;
  14. if(canId == 1){
  15.      ftob.b[0] = b  uf[7];
  16.      ftob.b[1] = buf[6];
  17.      ftob.b[2] = buf[5];
  18.      ftob.b[3] = buf[4];
  19.      q0 = ftob.f;
  20. }else if(canId == 2){
  21.      ftob.b[0] = buf[7];
  22.      ftob.b[1] = buf[6];
  23.      ftob.b[2] = buf[5];
  24.      ftob.b[3] = buf[4];
  25.      q1 = ftob.f;
  26. }else if(canId == 3){
  27.      ftob.b[0] = buf[7];
  28.      ftob.b[1] = buf[6];
  29.      ftob.b[2] = buf[5];
  30.      ftob.b[3] = buf[4];
  31.      q2 = ftob.f;
  32. }else if(canId == 4){
  33.      ftob.b[0] = buf[7];
  34.      ftob.b[1] = buf[6];
  35.      ftob.b[2] = buf[5];
  36.      ftob.b[3] = buf[4];
  37.      q3 = ftob.f;
复制代码
从CAN设备接收到的数据被解码并变成四元数的四个元素。再次,用opendiff复制代码进行对比。

https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_333764_ba5e9030-9d20.png

https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_333764_f3859e12-d84c.png
PC端程序
在处理中按原样照搬MPUTeapot.pde 不要指定串行端口。
您会看到M5Stack的物理运动与“Processing”中显示的飞机一起运动。
截屏2020-08-14 上午11.31.14.png

, 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
int qw, qx, qy, qz;
float q0, q1, q2, q3;

void printProcessing(){
     qw =int(q0 * 16384.0f);
     qx =int(q1 * 16384.0f);
     qy =int(q2 * 16384.0f);
     qz =int(q3 * 16384.0f);

     teapotPacket[2] = highByte(qw);
     teapotPacket[3] = lowByte(qw);
     teapotPacket[4] = highByte(qx);
     teapotPacket[5] = lowByte(qx);
     teapotPacket[6] = highByte(qy);
     teapotPacket[7] = lowByte(qy);
     teapotPacket[8] = highByte(qz);
     teapotPacket[9] = lowByte(qz);
     SERIAL.write(teapotPacket, 14);
     teapotPacket[11]++; // packetCount, loops at 0xFF on purpose
}[/code]此功能将解码的IMU四元数信息转换为处理程序可以使用的格式。 我已经在本文中使用过一个。
  1. &nbsp;//SERIAL.println("-----------------------------");
  2. &nbsp;//SERIAL.print("Get data from ID: 0x");
  3. &nbsp;//SERIAL.println(canId, HEX);

  4. &nbsp;//for (int i = 0; i &lt; len; i++) { // print the data
  5. &nbsp;//    SERIAL.print(buf[i], HEX);
  6. &nbsp;//    SERIAL.print("\t");
  7. &nbsp;//}
  8. &nbsp;union {
  9. &nbsp; &nbsp; &nbsp;float f;
  10. &nbsp; &nbsp; &nbsp;unsigned char b[4];
  11. &nbsp;} ftob;
  12. &nbsp;if(canId == 1){
  13. &nbsp; &nbsp; &nbsp;ftob.b[0] = b &nbsp;uf[7];
  14. &nbsp; &nbsp; &nbsp;ftob.b[1] = buf[6];
  15. &nbsp; &nbsp; &nbsp;ftob.b[2] = buf[5];
  16. &nbsp; &nbsp; &nbsp;ftob.b[3] = buf[4];
  17. &nbsp; &nbsp; &nbsp;q0 = ftob.f;
  18. &nbsp;}else if(canId == 2){
  19. &nbsp; &nbsp; &nbsp;ftob.b[0] = buf[7];
  20. &nbsp; &nbsp; &nbsp;ftob.b[1] = buf[6];
  21. &nbsp; &nbsp; &nbsp;ftob.b[2] = buf[5];
  22. &nbsp; &nbsp; &nbsp;ftob.b[3] = buf[4];
  23. &nbsp; &nbsp; &nbsp;q1 = ftob.f;
  24. &nbsp;}else if(canId == 3){
  25. &nbsp; &nbsp; &nbsp;ftob.b[0] = buf[7];
  26. &nbsp; &nbsp; &nbsp;ftob.b[1] = buf[6];
  27. &nbsp; &nbsp; &nbsp;ftob.b[2] = buf[5];
  28. &nbsp; &nbsp; &nbsp;ftob.b[3] = buf[4];
  29. &nbsp; &nbsp; &nbsp;q2 = ftob.f;
  30. &nbsp;}else if(canId == 4){
  31. &nbsp; &nbsp; &nbsp;ftob.b[0] = buf[7];
  32. &nbsp; &nbsp; &nbsp;ftob.b[1] = buf[6];
  33. &nbsp; &nbsp; &nbsp;ftob.b[2] = buf[5];
  34. &nbsp; &nbsp; &nbsp;ftob.b[3] = buf[4];
  35. &nbsp; &nbsp; &nbsp;q3 = ftob.f;
复制代码
从CAN设备接收到的数据被解码并变成四元数的四个元素。再次,用opendiff复制代码进行对比。




PC端程序
在处理中按原样照搬MPUTeapot.pde 不要指定串行端口。
您会看到M5Stack的物理运动与“Processing”中显示的飞机一起运动。


发表于 2020-12-25 17:51 | 显示全部楼层
感谢分享,做的不错!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-12-1 01:47 , Processed in 0.180647 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表