开源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

彻底解决 Codex / Copilot 修改中文乱码【含自动化解决方案】

彻底解决 Codex / Copilot 修改中文乱码【含自动化解决方案】

引言 在使用 GitHub Copilot 或 OpenAI Codex 自动重构代码时,你是否遇到过这样的尴尬:AI 生成的代码逻辑完美,但原本注释里的中文却变成了 我爱中文 这样的乱码?有时候这种字符甚至会污染正确的代码,带来巨大的稳定性隐患。 一、 问题核心:被忽视的“终端中转” 乱码的根源不在于 AI 的大脑,也不在于编辑器的显示,而在于执行链路的编码不一致。 Copilot/Codex 在执行某些修改任务(如:重构整个文件或批量替换)时,往往会通过终端调用系统指令。由于 Windows 终端(PowerShell/CMD)默认使用 GBK 编码,它在处理 AI 传来的 UTF-8 字节时会发生“误读”,导致写入文件的内容从源头上就损坏了。

By Ne0inhk
【优质开源项目】AIGC开源推荐-全球情报监控平台worldmonitor

【优质开源项目】AIGC开源推荐-全球情报监控平台worldmonitor

1.概述 World Monitor 是一个开源的实时情报/监测仪表盘,聚合多类数据源(新闻、地理/卫星、航运/空中、财经、威胁情报等),提供交互式地理视图、AI 摘要、事件聚合与报警,支持 Web / PWA / Tauri 桌面三种运行方式,并可通过变体(WORLD / TECH / FINANCE)切换功能集。 2. 总体技术架构(分层视角) 客户端层(Browser / PWA / Tauri desktop) * • React + TypeScript + Vite 构建。 * • 地图/可视化:deck.gl(WebGL 3D globe)、MapLibre GL、D3

By Ne0inhk
FossFLOW:开源等距图表工具,为技术文档注入立体活力!

FossFLOW:开源等距图表工具,为技术文档注入立体活力!

文章简介:FossFLOW是一款创新的开源等距图表工具,专为技术文档设计。它通过立体视角将复杂的系统架构转化为直观的3D图表,支持拖放式操作和离线使用,让技术图表变得生动易懂。无需注册,数据安全存储在本地,并提供JSON导入导出功能。无论是Docker快速部署还是在线体验,FossFLOW都能为架构图、流程图注入立体活力,是提升技术文档表现力的得力助手。 你是否曾经为了绘制清晰的技术架构图或系统流程图而烦恼?是否觉得传统的平面图表难以表达复杂的层次关系?今天,我要向大家介绍一款令人惊艳的开源工具——FossFLOW,它能让你的技术图表瞬间变得立体、生动! 🌟 什么是FossFLOW? FossFLOW 是一款功能强大的、开源的渐进式 Web 应用(PWA),专为创建精美的等距图表而设计。它基于 React 和 Isoflow(现已 fork 并以 fossflow 名称发布到 NPM)库构建,完全在浏览器中运行,并支持离线使用,让你随时随地都能创作出专业级的技术图表! github地址:https://github.com/stan-smith/FossFLOW/ 在线地

By Ne0inhk