EtherCAT igh主站控制3个台达asdaa2伺服转圈圈

2023-11-27 17:20

本文主要是介绍EtherCAT igh主站控制3个台达asdaa2伺服转圈圈,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.查看ASDA的PDO映射

在这里插入图片描述
打开ASDA的Delta_ASDA2-E_rev4-00_XML_TSE_20160620.xml文件
在这里插入图片描述
修改main.c的pdo部分

2.使能伺服

在这里插入图片描述
设置0x6060和0x60C2

    for(int i=0;i<3;i++){ecrt_slave_config_sdo8(sc_asda[i], 0x6060, 0, 8);//设置为csp模式ecrt_slave_config_sdo8(sc_asda[i], 0x60C2, 1, 1);//设置插补周期为1ms}

设置伺服DC,我写了篇文章有谈到这个函数EtherCAT igh源码的ecrt_slave_config_dc()函数的理解。
https://blog.csdn.net/cln512/article/details/103365240

    ecrt_slave_config_dc(sc_asda[0], 0x0300, 1000000, 0, 0, 0);ecrt_slave_config_dc(sc_asda[1], 0x0300, 1000000, 0, 0, 0);ecrt_slave_config_dc(sc_asda[2], 0x0300, 1000000, 0, 0, 0);

将【Controlword:6040h】依序设定为 (0x06 > 0x07 > 0x0F),使驱动器 Servo On 并让电机开始运作。

                switch (ecstate){case 1:EC_WRITE_U16(domainOutput_pd + cntlwd[i], 0x80);       break;case 7:curpos = EC_READ_S32(domainInput_pd + actpos[i]);       EC_WRITE_S32(domainOutput_pd + ipData[i], EC_READ_S32(domainInput_pd + actpos[i])); printf("x@rtITP >>> Axis %d current position = %d\n", i, curpos);break;case 9:EC_WRITE_U16(domainOutput_pd + cntlwd[i], 0x06);break;case 11:EC_WRITE_U16(domainOutput_pd + cntlwd[i], 0x07);break;case 13:EC_WRITE_U16(domainOutput_pd + cntlwd[i], 0xF);break;}

3.完整代码

/********************************************************************************  2019-12-02*  三个台达伺服每秒转1圈,100000 pulse/r*  *  ******************************************************************************/
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <rtdm/rtdm.h>
#include <native/task.h>
#include <native/sem.h>
#include <native/mutex.h>
#include <native/timer.h>
#include <rtdk.h>
#include <pthread.h>#include "ecrt.h"
#define     Bool                              int
#define     false                             0
#define     true                              1
#define     ETHERCAT_STATUS_OP                0x08
#define     STATUS_SERVO_ENABLE_BIT           (0x04)
//master status
typedef enum  _SysWorkingStatus
{SYS_WORKING_POWER_ON,SYS_WORKING_SAFE_MODE,SYS_WORKING_OP_MODE,SYS_WORKING_LINK_DOWN,SYS_WORKING_IDLE_STATUS       //系统空闲
}SysWorkingStatus;typedef  struct  _GSysRunningParm
{SysWorkingStatus   m_gWorkStatus;
}GSysRunningParm;GSysRunningParm    gSysRunning;RT_TASK InterpolationTask;int run = 1;
int ecstate = 0;
#define     CLOCK_TO_USE         CLOCK_REALTIME
#define     NSEC_PER_SEC         (1000000000L)
#define     TIMESPEC2NS(T)       ((uint64_t) (T).tv_sec * NSEC_PER_SEC + (T).tv_nsec)
static int64_t  system_time_base = 0LL;
//获取当前系统时间
RTIME system_time_ns(void)
{struct timespec  rt_time;clock_gettime(CLOCK_TO_USE, &rt_time);RTIME time = TIMESPEC2NS(rt_time);return time - system_time_base;
}
/****************************************************************************/// EtherCAT
ec_master_t *master = NULL;
static ec_master_state_t master_state = {};static ec_domain_t *domainServoInput = NULL;
static ec_domain_state_t domainServoInput_state = {};
static ec_domain_t *domainServoOutput = NULL;
static ec_domain_state_t domainServoOutput_state = {};static uint8_t *domainOutput_pd = NULL;
static uint8_t *domainInput_pd = NULL;static ec_slave_config_t *sc_asda[3];
static ec_slave_config_state_t sc_asda_state[3];
/****************************************************************************/
#define asda_Pos0 0, 0
#define asda_Pos1 0, 1
#define asda_Pos2 0, 2
#define asda 0x000001dd, 0x10305070
// offsets for PDO entries
static unsigned int  cntlwd[3];
static unsigned int  ipData[3];
static unsigned int  status[3];
static unsigned int  actpos[3];
static unsigned int  actvel[3];
// process data
ec_pdo_entry_reg_t domainServoOutput_regs[] = {{asda_Pos0, asda, 0x6040, 0x00, &cntlwd[0], NULL},{asda_Pos0, asda, 0x607a, 0x00, &ipData[0], NULL},{asda_Pos1, asda, 0x6040, 0x00, &cntlwd[1], NULL},{asda_Pos1, asda, 0x607a, 0x00, &ipData[1], NULL},{asda_Pos2, asda, 0x6040, 0x00, &cntlwd[2], NULL},{asda_Pos2, asda, 0x607a, 0x00, &ipData[2], NULL},{}
};
ec_pdo_entry_reg_t domainServoInput_regs[] = {{asda_Pos0, asda, 0x6064, 0x00, &actpos[0], NULL},{asda_Pos0, asda, 0x6041, 0x00, &status[0], NULL},{asda_Pos0, asda, 0x606c, 0x00, &actvel[0], NULL},{asda_Pos1, asda, 0x6064, 0x00, &actpos[1], NULL},{asda_Pos1, asda, 0x6041, 0x00, &status[1], NULL},{asda_Pos1, asda, 0x606c, 0x00, &actvel[1], NULL},{asda_Pos2, asda, 0x6064, 0x00, &actpos[2], NULL},{asda_Pos2, asda, 0x6041, 0x00, &status[2], NULL},{asda_Pos2, asda, 0x606c, 0x00, &actvel[2], NULL},{}
};
/****************************************************************************/
/* Master 0, Slave 0* Vendor ID:       0x000001dd* Product code:    0x10305070* Revision number: 0x02040608*/
//《 Delta_ASDA2-E_rev4-00_XML_TSE_20160620.xml》
static ec_pdo_entry_info_t asda_pdo_entries_output[] = {{ 0x6040, 0x00, 16 }, //control word{ 0x607a, 0x00, 32 }  //TargetPosition};static ec_pdo_entry_info_t asda_pdo_entries_input[] = {{ 0x6064, 0x00, 32 }, //actualPosition{ 0x6041, 0x00, 16 }, //status word{ 0x606c, 0x00, 32 }, //Velocity actual value
};//RxPDO
static ec_pdo_info_t asda_pdo_1600[] = {{ 0x1600, 2, asda_pdo_entries_output },
};
//TxPDO
static ec_pdo_info_t asda_pdo_1a00[] = {{ 0x1A00, 3, asda_pdo_entries_input },
};static ec_sync_info_t asda_syncs[] = {
//    { 0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE },
//    { 1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE },{ 2, EC_DIR_OUTPUT, 1, asda_pdo_1600, EC_WD_DISABLE },{ 3, EC_DIR_INPUT, 1, asda_pdo_1a00, EC_WD_DISABLE },{ 0xff }
};
/****************************************************************************/
int ConfigPDO()
{/********************/printf("xenomai Configuring PDOs...\n");domainServoOutput = ecrt_master_create_domain(master);if (!domainServoOutput) {return -1;}domainServoInput = ecrt_master_create_domain(master);if (!domainServoInput) {return -1;}/********************/printf("xenomai Creating slave configurations...\n");sc_asda[0] =ecrt_master_slave_config(master, asda_Pos0, asda);if (!sc_asda[0]) {fprintf(stderr, "Failed to get slave configuration.\n");return -1;}sc_asda[1] =ecrt_master_slave_config(master, asda_Pos1, asda);if (!sc_asda[1]) {fprintf(stderr, "Failed to get slave configuration.\n");return -1;}sc_asda[2] =ecrt_master_slave_config(master, asda_Pos2, asda);if (!sc_asda[2]) {fprintf(stderr, "Failed to get slave configuration.\n");return -1;}/********************/if (ecrt_slave_config_pdos(sc_asda[0], EC_END, asda_syncs)) {fprintf(stderr, "Failed to configure PDOs.\n");return -1;}if (ecrt_slave_config_pdos(sc_asda[1], EC_END, asda_syncs)) {fprintf(stderr, "Failed to configure PDOs.\n");return -1;}if (ecrt_slave_config_pdos(sc_asda[2], EC_END, asda_syncs)) {fprintf(stderr, "Failed to configure PDOs.\n");return -1;}/********************/if (ecrt_domain_reg_pdo_entry_list(domainServoOutput, domainServoOutput_regs)) {fprintf(stderr, "PDO entry registration failed!\n");return -1;}if (ecrt_domain_reg_pdo_entry_list(domainServoInput, domainServoInput_regs)) {fprintf(stderr, "PDO entry registration failed!\n");return -1;}fprintf(stderr, "Creating SDO requests...\n");for(int i=0;i<3;i++){ecrt_slave_config_sdo8(sc_asda[i], 0x6060, 0, 8);ecrt_slave_config_sdo8(sc_asda[i], 0x60C2, 1, 1);}return 0;
}/****************************************************************************** Realtime task****************************************************************************/void rt_check_domain_state(void)
{ec_domain_state_t ds = {};ec_domain_state_t ds1 = {};//domainServoInputecrt_domain_state(domainServoInput, &ds);if (ds.working_counter != domainServoInput_state.working_counter) {rt_printf("domainServoInput: WC %u.\n", ds.working_counter);}if (ds.wc_state != domainServoInput_state.wc_state) {rt_printf("domainServoInput: State %u.\n", ds.wc_state);}domainServoInput_state = ds;//domainServoOutputecrt_domain_state(domainServoOutput, &ds1);if (ds1.working_counter != domainServoOutput_state.working_counter) {rt_printf("domainServoOutput: WC %u.\n", ds1.working_counter);}if (ds1.wc_state != domainServoOutput_state.wc_state) {rt_printf("domainServoOutput: State %u.\n", ds1.wc_state);}domainServoOutput_state = ds1;
}/****************************************************************************/void rt_check_master_state(void)
{ec_master_state_t ms;ecrt_master_state(master, &ms);if (ms.slaves_responding != master_state.slaves_responding) {rt_printf("%u slave(s).\n", ms.slaves_responding);}if (ms.al_states != master_state.al_states) {rt_printf("AL states: 0x%02X.\n", ms.al_states);}if (ms.link_up != master_state.link_up) {rt_printf("Link is %s.\n", ms.link_up ? "up" : "down");}master_state = ms;
}/****************************************************************************/
void check_slave_config_states(void)
{ec_slave_config_state_t s;ecrt_slave_config_state(sc_asda[0],&s);if (s.al_state != sc_asda_state[0].al_state)printf("sc_asda_state[0]: State 0x%02X.\n", s.al_state);if (s.online != sc_asda_state[0].online)printf("sc_asda_state[0]: %s.\n", s.online ? "online" : "offline");if (s.operational != sc_asda_state[0].operational)printf("sc_asda_state[0]: %soperational.\n",s.operational ? "" : "Not ");sc_asda_state[0] = s;ec_slave_config_state_t s1;ecrt_slave_config_state(sc_asda[1],&s1);if (s1.al_state != sc_asda_state[1].al_state)printf("sc_asda_state[1]: State 0x%02X.\n", s1.al_state);if (s1.online != sc_asda_state[1].online)printf("sc_asda_state[1]: %s.\n", s1.online ? "online" : "offline");if (s1.operational != sc_asda_state[1].operational)printf("sc_asda_state[1]: %soperational.\n",s1.operational ? "" : "Not ");sc_asda_state[1] = s1;ec_slave_config_state_t s2;ecrt_slave_config_state(sc_asda[2],&s2);if (s2.al_state != sc_asda_state[2].al_state)printf("sc_asda_state[2]: State 0x%02X.\n", s2.al_state);if (s2.online != sc_asda_state[2].online)printf("sc_asda_state[2]: %s.\n", s2.online ? "online" : "offline");if (s2.operational != sc_asda_state[2].operational)printf("sc_asda_state[2]: %soperational.\n",s2.operational ? "" : "Not ");sc_asda_state[2] = s2;
}
/****************************************************************************/
void ReleaseMaster()
{if(master){printf("xenomai End of Program, release master\n");ecrt_release_master(master);master = NULL;}
}
/****************************************************************************/
int ActivateMaster()
{int ret;printf("xenomai Requesting master...\n");if(master)return 0;master = ecrt_request_master(0);if (!master) {return -1;}ConfigPDO();// configure SYNC signals for this slaveecrt_slave_config_dc(sc_asda[0], 0x0300, 1000000, 0, 0, 0);ecrt_slave_config_dc(sc_asda[1], 0x0300, 1000000, 0, 0, 0);ecrt_slave_config_dc(sc_asda[2], 0x0300, 1000000, 0, 0, 0);ecrt_master_application_time(master, system_time_ns());ret = ecrt_master_select_reference_clock(master, NULL);if (ret < 0) {fprintf(stderr, "xenomai Failed to select reference clock: %s\n",strerror(-ret));return ret;}/********************/printf("xenomai Activating master...\n");if (ecrt_master_activate(master)) {printf("xenomai Activating master...failed\n");return -1;}/********************/if (!(domainInput_pd = ecrt_domain_data(domainServoInput))) {fprintf(stderr, "xenomai Failed to get domain data pointer.\n");return -1;}if (!(domainOutput_pd = ecrt_domain_data(domainServoOutput))) {fprintf(stderr, "xenomai Failed to get domain data pointer.\n");return -1;}printf("xenomai Activating master...success\n");return 0;
}
/****************************************************************************/
void DriverEtherCAT()
{static int curpos = 0;//处于刚开机(需要等待其他操作完成),返回等待下次周期if(gSysRunning.m_gWorkStatus == SYS_WORKING_POWER_ON)return ;static int cycle_counter = 0;cycle_counter++;if(cycle_counter >= 90*1000){cycle_counter = 0;run = 0;}// receive EtherCAT framesecrt_master_receive(master);ecrt_domain_process(domainServoOutput);ecrt_domain_process(domainServoInput);rt_check_domain_state();if (!(cycle_counter % 500)) {rt_check_master_state();check_slave_config_states();}//状态机操作switch (gSysRunning.m_gWorkStatus){case SYS_WORKING_SAFE_MODE:{//检查主站是否处于 OP 模式, 若不是,则调整为 OP 模式rt_check_master_state();check_slave_config_states();if((master_state.al_states & ETHERCAT_STATUS_OP)){int tmp = true;for(int i=0;i<3;i++){if(sc_asda_state[i].al_state != ETHERCAT_STATUS_OP){tmp = false;break ;}}if(tmp){ecstate = 0;gSysRunning.m_gWorkStatus = SYS_WORKING_OP_MODE;printf("xenomai SYS_WORKING_OP_MODE\n");}}}break;case SYS_WORKING_OP_MODE:{ecstate++;//使能伺服if(ecstate <= 16){for(int i=0;i<3;i++){switch (ecstate){case 1:EC_WRITE_U16(domainOutput_pd + cntlwd[i], 0x80);       break;case 7:curpos = EC_READ_S32(domainInput_pd + actpos[i]);       EC_WRITE_S32(domainOutput_pd + ipData[i], EC_READ_S32(domainInput_pd + actpos[i])); printf("x@rtITP >>> Axis %d current position = %d\n", i, curpos);break;case 9:EC_WRITE_U16(domainOutput_pd + cntlwd[i], 0x06);break;case 11:EC_WRITE_U16(domainOutput_pd + cntlwd[i], 0x07);break;case 13:EC_WRITE_U16(domainOutput_pd + cntlwd[i], 0xF);break;}}}else {int tmp  = true;for(int i=0;i<3;i++){if((EC_READ_U16(domainInput_pd + status[i]) & (STATUS_SERVO_ENABLE_BIT)) == 0){tmp = false;break ;}}if(tmp){ecstate = 0;gSysRunning.m_gWorkStatus = SYS_WORKING_IDLE_STATUS;printf("xenomai SYS_WORKING_IDLE_STATUS\n");}}}break;default:{if (!(cycle_counter % 1000)) {printf("curpos = %d\t",curpos);printf("asda0 actpos... %d\t",EC_READ_S32(domainInput_pd + actpos[0]));printf("asda1 actpos... %d\t",EC_READ_S32(domainInput_pd + actpos[1]));printf("asda2 actpos... %d\n",EC_READ_S32(domainInput_pd + actpos[2]));}curpos += 100;for(int i=0;i<3;i++){EC_WRITE_S32(domainOutput_pd + ipData[i], curpos);}}break;}// write application time to masterecrt_master_application_time(master, system_time_ns());ecrt_master_sync_reference_clock(master);   ecrt_master_sync_slave_clocks(master);      // send process dataecrt_domain_queue(domainServoOutput);ecrt_domain_queue(domainServoInput);ecrt_master_send(master);
}
/****************************************************************************/
void InterpolationThread(void *arg)
{RTIME wait, previous;previous = rt_timer_read();wait = previous;while (run) {wait += 1000000; //1ms//Delay the calling task (absolute).Delay the execution of the calling task until a given date is reached.rt_task_sleep_until(wait);DriverEtherCAT();}
}/***************************************************************************** Signal handler***************************************************************************/void signal_handler(int sig)
{run = 0;
}/***************************************************************************** Main function***************************************************************************/int main(int argc, char *argv[])
{int ret;/* Perform auto-init of rt_print buffers if the task doesn't do so */rt_print_auto_init(1);signal(SIGTERM, signal_handler);signal(SIGINT, signal_handler);mlockall(MCL_CURRENT | MCL_FUTURE);gSysRunning.m_gWorkStatus = SYS_WORKING_POWER_ON;if(gSysRunning.m_gWorkStatus == SYS_WORKING_POWER_ON){ActivateMaster();ecstate = 0;gSysRunning.m_gWorkStatus = SYS_WORKING_SAFE_MODE;printf("xenomai SYS_WORKING_SAFE_MODE\n"); }ret = rt_task_create(&InterpolationTask, "InterpolationTask", 0, 99, T_FPU);if (ret < 0) {fprintf(stderr, "xenomai Failed to create task: %s\n", strerror(-ret));return -1;}printf("Starting InterpolationTask...\n");ret = rt_task_start(&InterpolationTask, &InterpolationThread, NULL);if (ret < 0) {fprintf(stderr, "xenomai Failed to start task: %s\n", strerror(-ret));return -1;}while (run) {rt_task_sleep(50000000);}printf("xenomai Deleting realtime InterpolationTask task...\n");rt_task_delete(&InterpolationTask);ReleaseMaster();return 0;
}/****************************************************************************/

这篇关于EtherCAT igh主站控制3个台达asdaa2伺服转圈圈的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/428178

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

控制反转 的种类

之前对控制反转的定义和解释都不是很清晰。最近翻书发现在《Pro Spring 5》(免费电子版在文章最后)有一段非常不错的解释。记录一下,有道翻译贴出来方便查看。如有请直接跳过中文,看后面的原文。 控制反转的类型 控制反转的类型您可能想知道为什么有两种类型的IoC,以及为什么这些类型被进一步划分为不同的实现。这个问题似乎没有明确的答案;当然,不同的类型提供了一定程度的灵活性,但

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理 秒杀系统是应对高并发、高压力下的典型业务场景,涉及到并发控制、库存管理、事务管理等多个关键技术点。本文将深入剖析秒杀商品业务中常见的几个核心问题,包括 AOP 事务管理、同步锁机制、乐观锁、CAS 操作,以及用户限购策略。通过这些技术的结合,确保秒杀系统在高并发场景下的稳定性和一致性。 1. AOP 代理对象与事务管理 在秒杀商品

PostgreSQL中的多版本并发控制(MVCC)深入解析

引言 PostgreSQL作为一款强大的开源关系数据库管理系统,以其高性能、高可靠性和丰富的功能特性而广受欢迎。在并发控制方面,PostgreSQL采用了多版本并发控制(MVCC)机制,该机制为数据库提供了高效的数据访问和更新能力,同时保证了数据的一致性和隔离性。本文将深入解析PostgreSQL中的MVCC功能,探讨其工作原理、使用场景,并通过具体SQL示例来展示其在实际应用中的表现。 一、

vue2实践:el-table实现由用户自己控制行数的动态表格

需求 项目中需要提供一个动态表单,如图: 当我点击添加时,便添加一行;点击右边的删除时,便删除这一行。 至少要有一行数据,但是没有上限。 思路 这种每一行的数据固定,但是不定行数的,很容易想到使用el-table来实现,它可以循环读取:data所绑定的数组,来生成行数据,不同的是: 1、table里面的每一个cell,需要放置一个input来支持用户编辑。 2、最后一列放置两个b

【电机控制】数字滤波算法(持续更新)

文章目录 前言1. 数字低通滤波 前言 各种数字滤波原理,离散化公式及代码。 1. 数字低通滤波 滤波器公式 一阶低通滤波器的输出 y [ n ] y[n] y[n] 可以通过以下公式计算得到: y [ n ] = α x [ n ] + ( 1 − α ) y [ n − 1 ] y[n] = \alpha x[n] + (1 - \alpha) y[n-1]

OpenStack离线Train版安装系列—3控制节点-Keystone认证服务组件

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版

OpenStack离线Train版安装系列—1控制节点-环境准备

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版

OpenStack离线Train版安装系列—10.控制节点-Heat服务组件

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版

OpenStack Victoria版——7.1控制节点-Neutron网络服务组件

7.1控制节点-Neutron网络服务组件 更多步骤:OpenStack Victoria版安装部署系列教程 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版 离线安装部署系列教程(全) OpenStack Train版 离线安装部署系列教程(全) 欢迎留言沟通,共同进步。 文章目录 一、创建n