jjzjj

嵌入式开发板CAN通信编程——伺服电机驱动

河边小乌龟爬 2024-07-08 原文

嵌入式开发板CAN通信编程——伺服电机驱动

在实际的嵌入式项目开发过程中,若不涉及上位机与开发板的通信传输数据,那最关键的无非就是两个内容,读取传感器的数据并处理,驱动硬件设备工作。传感器数据的读取内容在前面我已经讲过了,主要就是TTL、RS232、RS485协议的串口编程,我分别给了实例,读取光敏电阻传感器的状态和倾角传感器的实时角度测量信息。那就还有一个下发指令驱动硬件工作的内容,硬件设备的驱动程序一般都由设备厂家完成,集成在设备的驱动器上(关于字符设备驱动程序我之前讲了不涉及硬件操作驱动的程序实现,后面我还会给大家介绍涉及硬件操作的驱动程序实现,并给出实例),我们要做的就是根据设备的驱动通信协议,下发相应的指令即可,这就牵扯到CAN通信编程。这个专题我仍然还是会给出一个实例,供大家学习交流。

CAN通信协议

一、首先还是有必要介绍一下CAN通信协议

(1)CAN(Controller Area Network)又称为局域网控制器,汽车上基本都是采用CAN通信,CAN通信协议拥有稳定性和准确性,传输速率比RS485还高。

(2)多主控制:总线空闲时,所有单元都可以发送消息,但当两个以上的单元同时开始发送消息时,总线会根据标识符ID决定优先级。CAN协议是串行异步通信,同一时刻只能有一个发送或接收信息,由CAN_High和CAN_Low两条信号线,以差分信号的形式进行通讯,这一点和RS485是一样的。

(3)CAN通信协议通信速度快,通信距离较远,并且具有错误检测、错误通知与恢复功能。

(4)CAN总线的报文结构:CAN总线上的报文传输有4种不同的帧类型表示和控制,分别为数据帧、远程帧、错误帧、过载帧。我们这里主要介绍数据帧,数据帧携带数据从发送器至接收器。总线上传输的大多是这种帧。从标识符长度上,又可以把数据帧分为标准帧(11 位标识符)和扩展帧(29 位标识符)。数据帧由 7 个不同的位场组成:帧起始、仲裁场、控制场、数据场、CRC 场、应答场、帧结束。其中,数据场的长度为 0~8 个字节。标识符位于仲裁场中,报文接收节点通过标识符进行报文滤波。

(5)Linux系统中CAN总线配置:在Linux系统中,CAN总线接口设备作为网络设备被系统统一管理,在控制台下,CAN总线的配置和以太网的配置使用相同的命令。主要有三个命令:关闭、设置波特率、启动。

ifconfig can0 down
ip link set can0 type can bitrate 125000
ifconfig can0 up
//我的开发板中设置的命令是:
canconfig can0 stop
canconfig can0 bitrate 125000
canconfig can0 start

二、CAN通信编程中的API

由于Linux系统将CAN设备作为网络设备进行管理,因此在CAN总线应用开发方面,Linux提供了SocketCAN接口,使得CAN总线通信近似于和以太网的通信,应用程序开发接口更加通用,也更加灵活。

(1)初始化:

SocketCAN的初始化与socket网络编程类似,主要包括创建SocketCAN套接字、设置CAN接口名、指定CAN设备、设置CAN通信的地址结构体,绑定套接字和地址结构体。具体如下所示:

int socket_fd;
//定义一个socket can通信的地址结构体
struct sockaddr_can addr;
//定义一个ifreq结构体,这个结构体用来配置和获取IP地址、掩码、MTU等接口信息的
struct ifreq ifr;
//创建socketCAN套接字,设置为原始套接字,原始CAN协议
socket_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
//设置CAN接口名,对CAN接口进行初始化
strcpy(ifr.ifr_name, "can0");
//指定can0设备
ioctl(socket_fd, SIOCGIFINDEX, &ifr);
//设置CAN协议
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
//将套接字与can0绑定
bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr));

(2)数据发送与接收:

在CAN总线通信数据收发方面,CAN总线与标准套接字稍有不同,比标准套接字更规范,每一次通信都采用can_frame结构体将数据封装成帧。结构体定义如下:

struct can_frame{
	canid_t can_id;//can的标识符,帧ID
	_u8 can_dlc;//数据场长度
	_u8 data[8];//数据
};

数据发送使用write函数,数据接收使用read函数来实现。具体过程如下:

//存放发送和接收报文的can_frame结构体
struct can_frame frame[2] = {{0}};
//发送报文的内容
frame[0].can_id =0x141;
frame[0].can_dlc = 1;
frame[0].data[0] = 0x11;
int nbytes = write(socket_fd, &frame[0], sizeof(frame[0]));
//判断是否发送成功
if(nbytes != sizeof(frame[0])){
	printf("error\n");
}
//接收报文放在frame[1]结构体中
nbytes = read(socket_fd, &frame[1], sizeof(frame[1]));

(3)CAN通信API中还包括错误处理和过滤规则设置,这里我们就不赘述了。

CAN总线通信的伺服电机

我用的是一款脉塔的伺服电机RMD-X,具体介绍见它的使用说明书。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NXJKURGb-1651991854538)(https://cdn.jsdelivr.net/gh/zhangmeng19960901/blog-img/ECFF5AF1-2A64-451e-9322-FB30E49FC39F.png)]

它的CAN总线参数及单电机命令手法报文格式为:

我现在想要伺服电机运行并工作在速度环,通过使用说明书,我找到了电机运动命令:

电机运行命令为1帧,所以它的can_id也就是标识符为0x141,发送启动的报文如下:

frame[0].can_id = 0x141;
frame[0].can_dlc = 8;
frame[0].data[0] = 0x88;
frame[0].data[1] = 0x00;
frame[0].data[2] = 0x00;
frame[0].data[3] = 0x00;
frame[0].data[4] = 0x00;
frame[0].data[5] = 0x00;
frame[0].data[6] = 0x00;
frame[0].data[7] = 0x00;

伺服电机启动之后想要工作在速度环,就需要发送速度闭环控制指令:

它的单位0.01dps/LSB,我这里让其运行在360dps/LSB的速度上,标识符和上面一样,那报文数据就是:

frame[0].data[0] = 0xA2;
frame[0].data[1] = 0x00;
frame[0].data[2] = 0x00;
frame[0].data[3] = 0x00;
frame[0].data[4] = 0xA0;
frame[0].data[5] = 0x8C;
frame[0].data[6] = 0x00;
frame[0].data[7] = 0x00;

有了CAN总线通信的API和伺服电机的CAN总线参数与报文,我们就可以开始写程序了。

CAN总线通信编程

其实上面我已经把程序中的内容基本上都讲到了。具体程序不知道你通过上面的内容能不能完整的实现,我相信你是可以的,这里我只把程序流程说一下,具体的实现留给你们,完整代码我会贴在公众号中,要是没能实现再去下载下来看一下。

程序流程:初始化CAN通信套接字——>先发送启动报文——>在while循环中发送速度闭环控制报文——>接收伺服电机反馈回来的数据——>关闭CAN通信套接字。

用到的头文件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <stdint.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <linux/can.h>
#include <linux/can/raw.h>

在打开开发板时,要先配置CAN通信接口:

canconfig can0 stop
canconfig can0 bitrate 125000
canconfig can0 start

之后就可以将编译好的程序在开发板上运行了:启动——>运动。

到这里伺服电机就按照你想要的速度运行啦!!

完整代码我会贴在公众号中,需要完整代码的关注公众号回复CAN通信编程获取。有什么问题也可以在下方留言,我看到之后会回复你。

我是河边小乌龟爬,学习嵌入式软件开发路上的一名小学生,欢迎大家相互交流哇。公众号:河边小乌龟爬。


(群名称:嵌入式软件开发交流群;群 号:1004953094)

有关嵌入式开发板CAN通信编程——伺服电机驱动的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  3. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  4. ruby CSV : How can I read a tab-delimited file? - 2

    CSV.open(name,"r").eachdo|row|putsrowend我得到以下错误:CSV::MalformedCSVErrorUnquotedfieldsdonotallow\ror\n文件名是一个.txt制表符分隔文件。我是专门做的。我有一个.csv文件,我转到excel,并将文件保存为.txt制表符分隔的文件。所以它是制表符分隔的。CSV.open不应该能够读取制表符分隔的文件吗? 最佳答案 尝试像这样指定字段分隔符:CSV.open("name","r",{:col_sep=>"\t"}).eachdo|row|

  5. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  6. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  7. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  8. ruby-on-rails - 如何在 Ruby on Rails 中实现由 JSF 2.0 (Primefaces) 驱动的 UI 魔法 - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道ruby​​onrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim

  9. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  10. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

随机推荐