开源EtherCAT主站SOEM入门使用

开源EtherCAT主站SOEM入门使用

文章目录

目的

去年工作上用到了EtherCAT,EtherCAT同学是分主从的,作为学习测试来说主站最常用的是TwinCAT。不过TwinCAT支持的网卡信号有限,又没法应用到各种平台上。所以实际使用时又找了一些主站方案,适应性最广的就是SOEM库(Simple Open EtherCAT Master Library)。

项目地址:https://github.com/OpenEtherCATsociety/SOEM
文档地址:https://docs.rt-labs.com/soem/

SOEM库目前主要分为1.4.0版本和2.0.0版本,前者仓库中自带文档,后者文档需要去RT-Labs官网看(需要注册账号),本文将使用2.0.0版本:

在这里插入图片描述

本文测试时EtherCAT从站使用了LAN9252和AX58100,找那种支持DIO独立工作的板子:

在这里插入图片描述


这两个从站芯片都支持不依赖外部的控制器独立工作在DIO模式下。LAN9252支持总共16通道DIO,AX58100支持总共32路DIO。

上手体验

Releases中包含了已经编译好的示例和静态库,示例可以直接拿来体验:

在这里插入图片描述


需要注意的是Windows上需要安装Npcap才可以(如果有问题可以尝试安装WinPcap):
https://npcap.com/
https://www.winpcap.org/

对于EtherCAT主站来说其实就是收发特定格式的以太网报文而已,但是Windows上默认是不支持收发以太网原始帧的,需要借助诸如Npcap等库。

slaveinfo 示例可以读取EEPROM的数据。直接运行会提示用法:

在这里插入图片描述


指定网卡运行:

在这里插入图片描述

simple_ng 示例是个最简单的读写信号示例:

在这里插入图片描述

基础使用

SOEM库提供的是基础的EtherCAT数据帧的收发,应用层的功能和网络管理都是需要用户写代码手动处理的:

SOEM is a library that lets your application send and receive EtherCAT frames. It does not contain any logic for maintaining the EtherCAT network in an operational state; however, it has all the building blocks for doing so. In SOEM, it is the user application’s responsibility to handle these tasks:Reading and writing process data.Keeping local I/O data synchronized with the global I/O map.Detecting errors reported by SOEM.Managing errors reported by SOEM.

SOEM库使用有多种方式,这里在项目中直接使用SOEM源码。项目结构图下:

在这里插入图片描述

CMakeLists.txt 文件内容如下:

cmake_minimum_required(VERSION 3.28) project(soem_demo VERSION 1.0.1) add_subdirectory(SOEM-2.0.0) add_executable(soem_demo main.cpp) target_link_libraries(soem_demo soem)

main.cpp 文件内容如下:

#include<iostream>#include"SOEM-2.0.0/include/soem/soem.h"usingnamespace std;#defineMAX_ADAPTERS_QTY(32)#defineMAX_ADAPTER_NAME(128)intbasic_examples(char*ifname){printf("SOEM baisc examples start: \n"); ecx_contextt ctx; uint8 IOmap[4096]={0};int expectedWKC;/************************* Init BUS *************************/if(!ecx_init(&ctx, ifname)){printf("Init adapter failed.\n");return-1;}if(ecx_config_init(&ctx)<=0){printf("Enum and init slaves failed.\n");return-1;}else{for(size_t i =0; i < ctx.slavecount; i++){printf("Slave %03d: ", i);printf("Name %s, ", ctx.slavelist[i].name);printf("Output %d bytes %d bits", ctx.slavelist[i].Obytes, ctx.slavelist[i].Obits);printf("Input %d bytes %d bits", ctx.slavelist[i].Ibytes, ctx.slavelist[i].Ibits);printf("Delay %d ns, Has DC %d\n", ctx.slavelist[i].pdelay, ctx.slavelist[i].hasdc);}}ecx_config_map_group(&ctx, IOmap,0); expectedWKC = ctx.grouplist[0].outputsWKC *2+ ctx.grouplist[0].inputsWKC;ecx_configdc(&ctx);ecx_statecheck(&ctx,0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE *4);ecx_send_processdata(&ctx);ecx_receive_processdata(&ctx, EC_TIMEOUTRET);// using slave 0, which will broadcast the request to all slaves on the network ctx.slavelist[0].state = EC_STATE_OPERATIONAL;ecx_writestate(&ctx,0);for(size_t i =0; i <10; i++){ecx_send_processdata(&ctx);ecx_receive_processdata(&ctx, EC_TIMEOUTRET);ecx_statecheck(&ctx,0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE /10);if(ctx.slavelist[0].state == EC_STATE_OPERATIONAL)break;}if(ctx.slavelist[0].state != EC_STATE_OPERATIONAL){printf("Set operational state failed.\n");return-1;}/************************* Main loop *************************/for(size_t turn =0; turn <10000; turn++){ ec_timet start, end, diff;osal_usleep(5000);/********* Change output data if need *********/// change by slavefor(size_t i =0; i < ctx.slavecount; i++){for(size_t j =0; j < ctx.slavelist[i].Obytes; j++){ ctx.slavelist[i].outputs[j]= turn %256;}}// change by group// for (size_t i = 0; i < ctx.grouplist[0].Obytes; i++)// {// ctx.grouplist[0].outputs[i] = turn % 256;// } start =osal_current_time();ecx_send_processdata(&ctx);int wkc =ecx_receive_processdata(&ctx, EC_TIMEOUTRET); end =osal_current_time();osal_time_diff(&start,&end,&diff);printf("Iteration %05d: ", turn +1);printf("%08d usec, WKC %d",(int)(diff.tv_sec *1000000+ diff.tv_nsec /1000), wkc);printf(", O:");for(size_t n =0; n < ctx.grouplist[0].Obytes;++n){printf(" %02X", ctx.grouplist[0].outputs[n]);}printf(", I:");for(size_t n =0; n < ctx.grouplist[0].Ibytes;++n){printf(" %02X", ctx.grouplist[0].inputs[n]);}printf(", T: %lld",(longlong)ctx.DCtime);if(((turn +1)%1000))printf("\r");elseprintf("\n");if(wkc != expectedWKC)break;// error: stop or reinit slave}/************************* Stop BUS *************************/ ctx.slavelist[0].state = EC_STATE_INIT;ecx_writestate(&ctx,0);ecx_close(&ctx);printf("SOEM baisc examples end.\n");return0;}char*find_and_select_adapters(void){char adapter_name[MAX_ADAPTERS_QTY][MAX_ADAPTER_NAME]={0};int index =0; ec_adaptert *adapter =NULL; ec_adaptert *head =NULL;printf("\nAvailable adapters:\n"); head = adapter =ec_find_adapters();while(adapter !=NULL){printf("%02d - %s (%s)\n", index, adapter->name, adapter->desc);strncpy(adapter_name[index], adapter->name, MAX_ADAPTER_NAME); index++; adapter = adapter->next;}ec_free_adapters(head);printf("Please input the network adapter number: ");scanf("%d",&index);staticchar selected_name[MAX_ADAPTER_NAME];strncpy(selected_name, adapter_name[index], MAX_ADAPTER_NAME);return selected_name;}intmain(){char*ifname =find_and_select_adapters();basic_examples(ifname);return0;}

使用情况如下:

在这里插入图片描述


测试过程中output数据是在代码中不断改变的,input数据是板子上接了开关的IO口,拨动开关时数据会显示变化。

资料和例程

本文所设计的一些EtherCAT_SOEM相关资料可以从下面下载:
https://pan.baidu.com/s/1lDRk10TK2AKJm_mdseNO9Q?pwd=39qh
https://download.ZEEKLOG.net/download/Naisu_kun/92573410

其中LAN9252和AX58100烧录的ESI(EtherCAT SubDevice Information)文件分别如下:

  • AX58100_EVB_DIO_ESI_00010200_00000001_20220323.xml
  • Microchip EVB-LAN9252-DIGIO-8IN-8OUT.xml

烧录EEPROM可以使用安装倍福的SSC(EtherCAT Slave Stack Code Tool)工具时自带的 EEPROM Programmer 工具进行烧录:

在这里插入图片描述


上面工具比TwinCAT好的一点是不挑网卡,USB网卡等的都能用。

总结

SOEM总体使用是比较简单的,对于EtherCAT主站来说除了基本的读写,可能更多的挑战会在于对于时间稳定性上的处理。

最近发现类似的CherryECAT库也不错:
https://github.com/cherry-embedded/CherryECAT
https://cherryecat.readthedocs.io/

Read more

GitHub访问加速全攻略:开发者必备的5种提速方案(亲测有效)!!!

GitHub访问加速全攻略:开发者必备的5种提速方案(亲测有效)!!!

文章目录 * 一、为什么GitHub这么慢?(先搞懂原理) * 1.1 网络延迟的罪魁祸首 * 1.2 DNS污染问题 * 二、5大加速方案实测对比(附详细步骤) * 2.1 镜像站大法(新手首选) * 2.2 修改Hosts文件(永久生效) * 2.3 Git配置代理(程序员必备) * 2.4 使用Gitee中转(适合大项目) * 2.5 终极方案:GitHub加速器(黑科技) * 三、避坑指南(血泪经验) * 3.1 不要用盗版加速器! * 3.2 SSH连接比HTTPS更快 * 3.3 大文件用Git LFS * 四、速度测试对比(单位:

By Ne0inhk
ClaudeCode武装三件套:Ghostty + Yazi + Lazygit 打造高效开发环境

ClaudeCode武装三件套:Ghostty + Yazi + Lazygit 打造高效开发环境

引言:多终端切换之痛 在终端里深度使用 Claude Code 一段时间后,你很快会遇到一个现实问题: 场景:前后端需求同时开发,一个终端跑 Claude Code,另一个查看日志,还需要随时管理文件、提交代码……多个终端窗口切来切去,既麻烦又不直观,完全看不到各终端的实时状态。 以前我的解法是 tmux。但 tmux 毕竟是上个世纪的工具:命令多、记不住,界面也不美观,感觉像在用古董。 直到我在 X 上看到 Claude Code 之父 Boris 的推文,他在用 Ghostty。我去试了试,然后又发现了 Yazi 和 Lazygit,这套组合彻底改变了我的终端工作流。 今天我们就来聊这个终端三件套: * 🖥️ Ghostty:现代化终端模拟器,原生支持多标签、分屏 * 📂 Yazi:用

By Ne0inhk

免费开源!50+算法,Java基于YOLO框架的视频AI识别算法平台,适配低空无人机巡检、摄像头安防场景

文末联系小编,获取项目源码 YOLO视频AI识别算法管理平台核心是 YOLO v8神经网络模型的推理运算,推理运算涉及操作CPU内存、GPU内存、GPU并行计算等环节,这些环节可通过Python或C++来实现,每隔1分钟将推理结果信息和对应的图片推送到文件服务器MinIO和消息队列RocketMQ,便于开发者获取到推理结果进行业务开发。同时支持基于ONNX的推理运算和基于Tensorrt的加速推理运算两种方式,只需在调用时传递不同参数即可。 YOLO视频AI识别算法管理平台支持Linux和Windows环境,代码自动判断运行的环境并执行对应的.bat或.sh脚本文件以启动AI模型推理,包含前端完整代码和后端完整代码,开箱即用,为Java开发者训练、部署、使用AI模型提供了参考。可实现人、车、火灾烟雾、河道漂浮物、道路裂痕等视频的实时识别,并将识别结果通过 FFmpeg 推流到 ZLMediaKit 流媒体服务器,使得在 Web页面上可以同时查看原始视频和实时计算视频。 YOLO(You Only Look Once)是一种基于深度神经网络的高效、实时的目标检测算法。它将目标检测

By Ne0inhk
【Linux工具】git

【Linux工具】git

文章目录 * Git 概述 * 主要功能 * 使用场景 * 资源链接 * 使用和下载git * 总结 Git 概述 Git是一个流行的分布式版本控制系统,主要用于跟踪计算机文件的变化,尤其是在软件开发中。它允许多个开发者协同工作,并管理项目的版本历史。 主要功能 1. 版本跟踪 记录文件的每次更改,用户可以随时回溯到先前的版本。 2. 分支管理 允许开发者创建独立的工作线,便于新特性的开发和实验。 3. 合并功能 轻松合并不同分支的更改,处理冲突并保持代码整洁。 4. 分布式操作 每个开发者都有完整的代码库副本,允许离线工作并提高效率。 使用场景 * 软件开发 最常见的用途,管理源代码的版本控制。 * 文档管理 跟踪文档修改历史,尤其是在团队协作中。 资源链接 * Git官方文档 * Atlassian的Git指南 使用和下载git 如果在你的Linux系统上没有下载git那么我们可以使用下面命令进行下载 sudo yum install -y git 这里我

By Ne0inhk