演示CAN协议转换器读写DroneCAN协议数据的例程,读取dronecan设备节点信息,写入key-value数据和RGB三原色数据

关键词:CAN协议转换/转换模块/转换器,Lua编程,DroneCAN/UAVCAN/CAN转换器,Ardupilot,Px4,Pixhawk,UartAssist,读写DroneCAN协议数据,DroneCAN协议与原生CAN协议数据转换,DroneCAN协议与自定义CAN协议数据转换

Keywords:Demonstrates a case of reading and writing DroneCAN protocol data, reading dronecan device node information, writing key-value data and RGB three primary color data, CAN protocol conversion/converter/conversion module, Lua programming, DroneCAN/UAVCAN/CAN converter, Ardupilot, Px4, Pixhawk, UartAssist, Read and write DroneCAN protocol data, convert DroneCAN protocol and native CAN protocol data, convert DroneCAN protocol and custom CAN protocol data

Ключевые слова:Демонстрируется случай чтения и записи данных протокола DroneCAN, чтения информации об узле устройства Dronecan, записи данных «ключ-значение» и данных трех основных цветов RGB, Модуль преобразования/конвертера/преобразования протокола CAN, программирование Lua, преобразователь DroneCAN/UAVCAN/CAN, Ardupilot, Px4, Pixhawk, UartAssis, Чтение и запись данных протокола DroneCAN, преобразование протокола DroneCAN и данных протокола CAN, преобразование протокола DroneCAN и данных пользовательского протокола CAN

哈喽大家好,我是Mokel。这是Pogo-CAN协议转换器/转换模块(can-convertor转换器)系列视频的第二期。can-convertor转换器默认支持在DroneCAN协议和原生CAN协议之间进行数据转换,同时也支持我们根据厂商提供的技术资料和测试数据自行开发针对厂商自定义CAN协议的拆包/封包Lua函数库,然后再编写数据转换的主逻辑,从而实现DroneCAN协议和自定义CAN协议之间的数据转换功能。这期视频中我将演示在can-convertor转换器中如何通过Lua代码读写DroneCAN协议数据。

在视频中我将用到Pogo-CAN协议转换器/转换模块(can-convertor转换器)、Pogo-DroneCAN调试器(canv2调试器)、GH1.25-4P双头反向端子线以及两根typeC转USB线。

你可以在淘宝搜索“CAN协议转换 px4”找到Pogo-CAN转换器商品或者直接点击评论区置顶链接(https://item.taobao.com/item.htm?spm=a21n57.1.0.0.7e56523cjhl6Oc&id=750897861626&ns=1&abbucket=17#detail)跳转到商品。

该商品也上架了俄罗斯电商平台OZON,你可以通过搜索关键词“Модуль преобразования cоглашение CAN”找到商品或者直接点击评论区置顶链接(https://www.ozon.ru/product/modul-preobrazovaniya-coglashenie-can-podderzhka-px4-pixhawk-ardupilot-podderzhka-programmirovaniya-1346610729/?asb=a7D3xKAAFCBoCKqQPIHhDhA7YESO2M9%252BDg4SWOxhKmk%253D&asb2=dtTUZykkKGWFh2Dos3wDcpH9qvmxF3jrRLoQjbqXhHyDWLPydKdYk1CiwF1q9MHCZ98QmDvbtyMlFo8dsqXSiw0iL-tFl3ZFWsg5n72DgGiT61hWqEPZ_fN-hOpkPNTi&avtc=1&avte=2&avts=1703401190&keywords=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F+c%D0%BE%D0%B3%D0%BB%D0%B0%D1%88%D0%B5%D0%BD%D0%B8%D0%B5+CAN)跳转到商品。

同时,你可以在淘宝搜索“DroneCAN调试器”找到Pogo-DroneCAN调试器(canv2调试器),也可以通过评论区置顶链接(https://item.taobao.com/item.htm?spm=a21n57.1.0.0.2b9a523cYE9t78&id=734695507467&ns=1&abbucket=15#detail)直接跳转商品。该商品也上架了俄罗斯电商平台OZON,你可以通过搜索关键词“Отладчик DroneCAN”找到该商品,也可以通过评论区置顶链接(https://www.ozon.ru/product/otladchik-dronecan-uavcan-konverter-usb-can-izmenenie-proshivki-s-pomoshchyu-qgc-1346580712/?asb=Oaqy7GWh%252BuG5Uct4DT5YEaFYsnMz6G%252Fs7Or0MSlWDhw%253D&asb2=8OXO2usSNqJRQIWXLtovWVB92lxf2fcf01rcW64dRBUB00ytZba_n5caH5gOrcj_OAQ1ShXm3WPGz5O50L9Ck1ipLgk3QMcbK7fBpzXdlII8Ao00psQcK1RhANh79JFT&avtc=1&avte=2&avts=1703434129&keywords=%D0%9E%D1%82%D0%BB%D0%B0%D0%B4%D1%87%D0%B8%D0%BA+DroneCAN)跳转商品。

我们用canv2调试器模拟dronecan设备来和can-convertor转换器进行数据收发操作。canv2调试器搭载官方默认固件--Pogo_SLCAN.bin(https://gitee.com/pogo-tech/candle-light_fw/releases),can-convertor转换器搭载着官方默认固件--can-convertor.bin(https://gitee.com/pogo-tech/can-convertor-lua/releases)。上述两个固件都可以在官方对应的代码仓库的发行版中找到。

在这期演示过程中,我们不仅需要用到UartAssist串口调试助手,还需要用到dronecan_gui_tool上位机,在第一期视频中我们已经介绍过UartAssist串口调试助手的安装与使用(CAN协议转换模块/转换器介绍和“HelloWorld“例程演示-CSDN博客),dronecan_gui_tool上位机的安装与使用可以参考Pogo-DroneCAN调试器系列教程(Windows下安装和使用dronecan_gui_tool,DroneCAN/UAVCAN调试器,USB-CAN模块-CSDN博客)。

我们先用GH1.25-4P双头反向端子线将canv2调试器和can-convertor转换器连接起来,注意,在can-convertor转换器上有两组CAN口,左右两侧分别对应CAN1口和CAN0口,在演示中我们使用CAN1口进行演示模拟,所以这里我们将canv2调试器接在can-convertor转换器的左侧接口上。can-convertor转换器和canv2调试器连接完成后,我们再将两根typeC转USB线连接到两个设备上。在之后的演示中我们需要通过typeC线将canv2调试器和can-convertor转换器连接到电脑。

准备工作完成,我们开始第一个例程“DroneCAN_getNode”。将can-convertor转换器端通过typeC线连接到电脑,can-convertor转换器会被电脑识别成一个U盘,且U盘内存放着我们的Lua脚本文件pogo.lua。将pogo.lua脚本文件内容替换成DroneCAN_getNode例程代码,代码如下:

local can_num = 1
local get_can_id = 125

candrv.set_BitRate(can_num, 1000)
candrv.set_Protocol(can_num, 1)
candrv.enable(can_num)

dronecan.init(80);

while true do
    local mode = dronecan.get_Node_Mode(get_can_id);
    local time = dronecan.get_Node_Time(get_can_id);

    print("mode:", mode, "time:", time)

    delay(100)
end

上面代码中首先声明两个常量can_num和get_can_id。在can-convertor转换器模块上提供两组CAN口,常量can_num表示所选用的CAN口,其值可以为0和1,分别对应转换器上的CAN0和CAN1口。can_num值为1,所以代码中candrv.enable(can_num)函数表示使能CAN1口,此时dronecan设备便可以通过CAN1口和can-convertor转换器进行数据通信。

candrv.set_BitRate()函数是用来设置CAN口通信的波特率,其接收的第二个参数的数值单位为K,比如说candrv.se_BitRatet(0, 500)代表着将CAN0口通信的波特率设置为500K,因此例程代码中candrv.set_BitRate(can_num, 1000)表示将CAN1口通信的波特率设置为1000K。

candrv.set_Protocol()则是设置CAN口的通信协议,第二个参数表示所选用的通信协议。can-convertor转换器默认提供原生CAN协议和DroneCAN协议的支持,0表示原生CAN协议,1表示DroneCAN协议,当然如果你想要使用其他协议,也可以通过编写Lua脚本实现,在后续教程中我也会讲解如何通过Lua脚本自定义通信协议。这里candrv.set_Protocol(can_num, 1)表示将CAN1口所使用的通信协议设置为DroneCAN协议。

CAN口以及CAN口使用的通信协议设置完成后。can-convertor转换器通过dronecan.init(80)函数将自身节点id设置为80。

所有配置代码执行完成,让我们来看一下逻辑代码部分。逻辑代码使用while死循环包裹,循环中通过dronecan.get_Node_Mode()和dronecan.get_Node_Time()两个函数从get_can_id指定的节点,即获取125节点数据,并使用print函数将获取的数据打印出来。在演示中便是打印can-convertor转换器(对应80节点)从canv2调试器(对应125节点)获取到的数据。

代码替换完成后,我们将can-convertor转换器拔掉后重新接入电脑。在第一期教程中,我们替换完“hello world”例程代码后也同样进行了该操作。这是因为只有将can-convertor转换器重新上电,它才会执行新的Lua脚本。

我们开始调试例程。打开UartAssist串口调试助手,在UartAssist中将识别到一个#USB 串行设备,选中它,点击打开,便可以在UartAssist的数据日志窗口中看到调试信息,数据日志窗口中以每秒10次的频率打印两个get方法获取的数据。此时获取到mode和time值都为-1,说明并没有获取到数据。

我们将canv2调试器端也连接到电脑上。打开dronecan_gui_tool,此时dronecan_tui_tool将识别到两个串口连接设备,分别为USB串行设备和STMicroelec......。USB 串行设备是我们连接的can-convertor转换器,STM...则是我们的刚刚接入的canv2调试器。我们可以尝试选中USB 串行设备,点击“OK”连接,dronecan_gui_tool会提示拒绝访问错误,这是因为UartAssist串口调试助手已经占用了can-convertor转换器设备。

选择STM...,点击“OK”,进入连接界面。代码中我们通过两个get函数获取get_can_id节点数据,也就是125节点。所以我们需要将canv2调试器节点id设置为125,点击勾号确认。再点击小火箭图标,可以看到dronecan_gui_tool检测到两个设备,分别为125节点的canv2调试器和80节点的can-convertor转换器。

此时我们可以看到,在UartAssist串口调试助手的数据日志窗口中打印的mode和time不再是-1了。然后我们点击dronecan_gui_tool左上角的Tools,再点击下拉框中的Bus Monitor打开数据监视窗口监看125节点数据,也就是canv2调试器的数据。

在数据监视窗口存在两种类型数据,TX和RX,TX表示节点发送的数据,RX表示节点接收到的数据。我们可以在监视窗口中看到,125节点设备即canv2调试器会以每秒一次的频率向can-convertor转换器发送数据(TX)。在监视窗口中选中一条发送数据(TX)。可以看到,发送的数据中存在uptime_sec和mode字段,Lua脚本中dronecan.get_Node_Time()和dronecan.get_Node_Mode()函数从125节点TX数据中分别读取uptime_sec和mode字段值。在Lua脚本中代码以每秒10次的频率打印canv2调试器发送过来的数据。由于canv2调试器是以每秒一次的频率发送数据。所以在UartAssist日志窗口中,我们能够看到,窗口中一秒内打印的10条数据相同。例程执行成功。

Pogo官方帮助我们封装了一系列操作DroneCAN协议数据方法,在我们的第一个例程中,我们通过其中dronecan.get_Node_Mode()和dronecan.get_Node_Time()函数,成功读取到canv2调试器发送的数据。更多的相关函数可以阅读官方提供的Lua函数库说明文档(https://gitee.com/pogo-tech/can-convertor-lua/blob/master/Lua_Doc/docs.lua)。

知道了如何获取dronecan设备数据发送的数据,那我们该如何向dronecan设备发送数据呢。下面我将用“DroneCAN_setKeyValue”、“DroneCAN_setRGB”两个例程向大家演示如何在can-convertor转换器中通过Lua脚本向dronecan设备发送数据。

我们从“DroneCAN_setKeyValue”例程开始演示。我们将串联好的设备的can-convertor转换器端连接到电脑,按之前步骤将pogo.lua代码更新为"DroneCAN_setKeyValue"历程代码,拔掉转换器,再重新连接。打开UartAssist串口调试助手,在UartAssist中选中转换器,点击打开按钮开始调试。连接canv2调试器端,打开dronecan_gui_tool,选中canv2调试器,点击“OK”后,设置节点ID值。我这里将调试器节点id设置为127。点击勾号,再点击小火箭按钮。和前一个例程一样,dronecan_gui_tool检测到存在两个节点,分别为我们手动设置的127节点的canv2调试器和通过Lua脚本设置的节点id为80的can-convertor转换器。

local can_num = 1

candrv.set_BitRate(can_num, 1000)
candrv.set_Protocol(can_num, 1)
candrv.enable(can_num)

dronecan.init(80);

local keyvalue = {}
local cnt = 0.0
keyvalue["roll"] = 0.0
keyvalue["pitch"] = 0.0
keyvalue["yaw"] = 0.0

while true do
    cnt = cnt + 1.0
    if (cnt > 90.0) then
        cnt = -90.0;
    end

    keyvalue["roll"] = cnt
    keyvalue["pitch"] = cnt
    keyvalue["yaw"] = cnt

    dronecan.set_keyvalue("roll", keyvalue["roll"]);
    dronecan.set_keyvalue("pitch", keyvalue["pitch"]);
    dronecan.set_keyvalue("yaw", keyvalue["yaw"]);


    delay(500)
end

在“DroneCAN_setKeyValue”例程代码中同样进行了设置波特率、CAN口,CAN口通信协议以及初始化dronecan设备节点ID操作。配置代码执行完成后,我们来看逻辑代码。逻辑代码中我们通过死循环不断用dronecan.set_keyvalue()函数向dronecan设备发送键值对数据。dronecan.set_keyvalue()函数接受两个参数,分别是发送的键值对的key和键值对的value值。逻辑代码中,存在三组键值对数据,它们的key值分别为“roll”,“pitch”,“yaw”,value值都为cnt。cnt的初始值为0,每次循环,cnt加一,并通过三次dronecan.set_keyvalue()函数将["roll", cnt],["pitch", cnt], ["yaw", cnt]三组键值对数据发送给dronecan设备。在死循环中当cnt值大于90时,cnt会被重置为-90。

我们此时在dronecan_gui_tool中打开监控127节点的Bus Monitor数据监视窗口,监看canv2调试器从can-convertor转换器接收到的数据RX。我们看其中一组接收到的数据(RX)。

在Lua脚本的一次循环中,三次调用dronecan.set_keyvalue()函数向canv2调试器发送["roll", cnt],["pitch", cnt], ["yaw", cnt]三组键值对数据。上图中我们可以看到,在canv2调试器接收到的一组RX数据中,存在三条数据分别与["roll", cnt],["pitch", cnt], ["yaw", cnt]对应,说明can-convertor转换器成功通过dronecan.set_keyvalue()函数向dronecan设备发送键值对数据,例程演示成功。dronecan.set_keyvalue()是一种较为通用的数据发送方法,而Pogo官方也为一些dronecan设备封装了特定的指令函数,我们来看下一个"DroneCAN_setRGB"例程。

“DroneCAN_setRGB”例程中调用了为RGB灯封装的指令函数dronecan.set_RGB()。函数接受三个参数,三个参数分别表示红绿蓝三原色的亮度,三参数的数值范围为0-255,其共同组成RGB色彩模式数据。比如dronecan.set_RGB(100, 10, 1),表示红、绿、蓝三原色亮度分别为100,10,1所组成的颜色。我们来看其例程代码和演示结果。

“DroneCAN_setRGB”例程通过dronecan.set_RGB()函数向dronecan设备发送RGB灯指令,当连接实际的dronecan设备时可以控制RGB灯根据接收的RGB数据变换颜色。实际效果如下:

代码如下:

local can_num = 1

candrv.set_BitRate(can_num, 1000)
candrv.set_Protocol(can_num, 1)
candrv.enable(can_num)

dronecan.init(80);

while true do
    dronecan.set_RGB(100, 0, 0);
    delay(100)
    dronecan.set_RGB(0, 100, 0);
    delay(100)
end

替换完Lua脚本代码,我们按照前文相同操作,连接设备,并配置好UartAssist串口调试助手和dronecan_gui_tool后,便可以开始我们的例程调试。

我们选中一条canv2调试器接收到的数据。我们可以看到canv2调试器接收到的数据是commands指令数据且包含红绿蓝所组成的RGB颜色数据,当然,在封装的代码中会对dronecan.set_RGB()接收到的参数进行移位处理,所以我们获取到的数据会产生和发送的数据不同。例程演示成功。

can-convertor转换器关于读写DroneCAN协议数据的例程演示到这里就结束了,我们通过例程演示了can-convertor转换器如何通过Lua脚本获取dronecan设备发送的数据以及如何向dronecan设备发送数据。演示所用例程代码均在官方gitee代码仓库中有提供(https://gitee.com/pogo-tech/can-pro-lua/tree/master),有需要的可以自行查找。

这期视频就到这里了,我们下期视频,不见不散。

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的例程,用于在 rk3399 上创建一个字符设备,并利用 dma-buf 机制从网卡读取数据: ```c #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/miscdevice.h> #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/dma-mapping.h> #define DEV_NAME "mydev" #define BUF_SIZE 4096 static struct miscdevice my_misc_device; static char *rx_buf; static dma_addr_t rx_buf_dma; static int my_open(struct inode *inode, struct file *file) { return 0; } static int my_release(struct inode *inode, struct file *file) { return 0; } static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret = 0; if (count > BUF_SIZE) count = BUF_SIZE; if (copy_to_user(buf, rx_buf, count)) ret = -EFAULT; else ret = count; return ret; } static struct file_operations my_fops = { .owner = THIS_MODULE, .open = my_open, .release = my_release, .read = my_read, }; static int my_probe(struct platform_device *pdev) { struct net_device *dev = dev_get_by_name(&init_net, "eth0"); struct sk_buff *skb; struct scatterlist sg; int i, len; if (!dev) { pr_err("Failed to get eth0 device\n"); return -ENODEV; } skb = netdev_alloc_skb(dev, BUF_SIZE, GFP_KERNEL); if (!skb) { pr_err("Failed to allocate skb\n"); return -ENOMEM; } skb_reserve(skb, NET_SKB_PAD); skb_put(skb, BUF_SIZE); sg_init_one(&sg, skb->data, skb->len); if (dma_map_sg(&pdev->dev, &sg, 1, DMA_FROM_DEVICE) != 1) { pr_err("Failed to map SG to DMA buffer\n"); return -ENOMEM; } rx_buf = dma_alloc_coherent(&pdev->dev, BUF_SIZE, &rx_buf_dma, GFP_KERNEL); if (!rx_buf) { pr_err("Failed to allocate DMA buffer\n"); return -ENOMEM; } len = skb->len; for (i = 0; i < len; i += skb_tailroom(skb)) { skb_reset_tail_pointer(skb); skb_set_tail_pointer(skb, skb->len); sg_init_one(&sg, skb->data, skb_tailroom(skb)); dma_sync_sg_for_cpu(&pdev->dev, &sg, 1, DMA_FROM_DEVICE); memcpy(rx_buf + i, skb->data, skb_tailroom(skb)); dma_sync_sg_for_device(&pdev->dev, &sg, 1, DMA_FROM_DEVICE); } netdev_rx(skb); misc_register(&my_misc_device); return 0; } static int my_remove(struct platform_device *pdev) { misc_deregister(&my_misc_device); dma_free_coherent(&pdev->dev, BUF_SIZE, rx_buf, rx_buf_dma); return 0; } static struct platform_driver my_driver = { .driver = { .name = "my_driver", }, .probe = my_probe, .remove = my_remove, }; static int __init my_init(void) { my_misc_device.minor = MISC_DYNAMIC_MINOR; my_misc_device.name = DEV_NAME; my_misc_device.fops = &my_fops; return platform_driver_register(&my_driver); } static void __exit my_exit(void) { platform_driver_unregister(&my_driver); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL"); ``` 以上代码仅供参考,实际使用时需要根据具体需求进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值