SOEM控制伺服电机方法

本文介绍了作者修复并重新编写的EtherCAT控制程序,用于管理23位编码器电机的伺服运动,包括pdo_config函数配置、状态处理和数据传输,展示了从站进入操作状态和简单的测试过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前我写了一个控制伺服的程序,但是方式是错误的,后来也不怎么SOEM了,最近有用到,就重新写了一个测试程序,重新发布一下
我使用的是23位编码器电机

#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>

#include "ethercattype.h"
#include "nicdrv.h"
#include "ethercatbase.h"
#include "ethercatmain.h"
#include "ethercatdc.h"
#include "ethercatcoe.h"
#include "ethercatfoe.h"
#include "ethercatconfig.h"
#include "ethercatprint.h"

char IOmap[4096];
typedef struct{
	uint16 control;
	uint8 mode;
	int32 tposition;
	int32 velocity;
}TxPdo_t;
typedef struct{
	uint16 status;
	int32 cposition;
}RxPdo_t;

TxPdo_t *tpdo;
RxPdo_t *rpdo;

int pdo_config(uint16 i);
int run = 1;
// 从站进入op状态
void slavetop(int i)
{
	int loop = 0;
	do{
		ec_slave[i].state = EC_STATE_OPERATIONAL;
		ec_send_processdata();
		ec_receive_processdata(EC_TIMEOUTRET);
		ec_writestate(i);
		ec_readstate();
		loop++;
		if(loop == 10000)
		{
			if(ec_slave[i].ALstatuscode != 0)
				printf("ALstate code:%x\n",ec_slave[i].ALstatuscode);
			loop = 0;
		}
	}while(ec_slave[i].state != EC_STATE_OPERATIONAL);

}
void endsignal()
{
	run = 0;
	printf("EtherCAT stop.\n");
	signal( SIGINT, SIG_DFL );
}
void simpletest(char *ifname)
{
	int app = 0;
	int firstflag = 1;
	int64 dctime = 0;
	int activebit4 = 0;
	if(ec_init(ifname))
	{
		printf("start ethernet at %s\n",ifname);
		if ( ec_config_init(FALSE) > 0 )
		{
			ec_slavet *slave;
			printf("found %d slave on the bus\n",ec_slavecount);
			ec_slave[0].state = EC_STATE_PRE_OP;
			ec_writestate(0);
			ec_send_processdata();
			ec_receive_processdata(EC_TIMEOUTRET);
			slave = &ec_slave[1];
			slave->PO2SOconfig = pdo_config;
			ec_config_map(&IOmap);
			ec_configdc();
			ec_dcsync0(1,TRUE,2000000,5000);
			slavetop(0);
			if(ec_slave[0].state == EC_STATE_OPERATIONAL)
			{
				printf("all slave to op\n");
				tpdo = (TxPdo_t *)ec_slave[1].outputs;
				rpdo = (RxPdo_t *)ec_slave[1].inputs;
				while(run)
				{
					app++;
					ec_receive_processdata(EC_TIMEOUTRET);
					if(firstflag)
					{
						firstflag = 0;	
						tpdo->control = 0x00;
						tpdo->control = 0x40;
					}
					else if(((rpdo->status)&0x4f) == 0x40)
					{
						tpdo->control = 0x06;
						tpdo->mode = 1;
						tpdo->tposition = rpdo->cposition;
					}
					else if(((rpdo->status)&0x6f) == 0x21)
					{
						tpdo->control = 0x07;
						tpdo->mode = 1;
						tpdo->tposition = rpdo->cposition;
					}
					else if(((rpdo->status)&0x6f) == 0x23)
					{
						int32 adv = 8388608;//加减速
						tpdo->control = 0x0f;
						tpdo->mode = 1;
						tpdo->tposition = rpdo->cposition;
						ec_SDOwrite(1,0x6083,0x00,FALSE,4,&adv,EC_TIMEOUTRXM);
						ec_SDOwrite(1,0x6084,0x00,FALSE,4,&adv,EC_TIMEOUTRXM);
						tpdo->velocity = 838860;
						//tpdo->tposition = 214748364;
						tpdo->tposition = 0;
					}
					else if(((rpdo->status)&0x6f) == 0x27)
					{
						activebit4++;
						if(activebit4 < 1000)
						{
							if(((tpdo->control) & 0x10) == 0x10)
							{
								tpdo->control &= ~0x0010;
							}	
							else
							{
								tpdo->control |= 0x0010;
							}
						}
					}
					else
					{
						tpdo->control = 0x40;
						tpdo->mode = 0;

					}

					ec_send_processdata();
					usleep(2000);// 周期大小
				}
				printf("cyclic task end\n");
				do{
					ec_slave[1].state = EC_STATE_SAFE_OP;
					ec_writestate(1);
				}while(ec_slave[1].state == EC_STATE_OPERATIONAL);
				do{
					ec_slave[1].state = EC_STATE_PRE_OP;
					ec_writestate(1);
				}while(ec_slave[1].state == EC_STATE_SAFE_OP);
				do{
					ec_slave[1].state = EC_STATE_INIT;
					ec_writestate(1);
				}while(ec_slave[1].state == EC_STATE_PRE_OP);
				ec_close();
			}
			else
			{
				printf("slave again to op\n");
			}
		}
		else
		{
			printf("no slave on the bus\n");
		}
	}
	else
	{
		printf("no ethernet card\n");
	}
}
int main(int argc, char *argv[])
{
	printf("SOEM (Simple Open EtherCAT Master)\nSimple test\n");
	signal( SIGINT , endsignal );

	if (argc > 1)
	{      
		simpletest(argv[1]);
	}
	else
	{
		printf("Usage: simple_test ifname1\nifname = eth0 for example\n");
	}   

	printf("End program\n");
	return (0);
}
//PDO配置
int pdo_config(uint16 i)
{
	uint16 value16 = 0;
	uint32 value32 = 0;

	value16 = 0;
	ec_SDOwrite(i,0x1C12,0,FALSE,sizeof(value16),&value16,EC_TIMEOUTRXM);
	ec_SDOwrite(i,0x1C13,0,FALSE,sizeof(value16),&value16,EC_TIMEOUTRXM);

	value16 = 0;
	ec_SDOwrite(i,0x1A00,0,FALSE,sizeof(value16),&value16,EC_TIMEOUTRXM);
	value32 = 0x60410010;
	ec_SDOwrite(i,0x1A00,1,FALSE,sizeof(value32),&value32,EC_TIMEOUTRXM);
	value32 = 0x60640020;
	ec_SDOwrite(i,0x1A00,2,FALSE,sizeof(value32),&value32,EC_TIMEOUTRXM);
	value16 = 2;
	ec_SDOwrite(i,0x1A00,0,FALSE,sizeof(value16),&value16,EC_TIMEOUTRXM);

	value16 = 0;
	ec_SDOwrite(i,0x1600,0,FALSE,sizeof(value16),&value16,EC_TIMEOUTRXM);
	value32 = 0x60400010;
	ec_SDOwrite(i,0x1600,1,FALSE,sizeof(value32),&value32,EC_TIMEOUTRXM);
	value32 = 0x60600008;
	ec_SDOwrite(i,0x1600,2,FALSE,sizeof(value32),&value32,EC_TIMEOUTRXM);
	value32 = 0x607A0020;
	ec_SDOwrite(i,0x1600,3,FALSE,sizeof(value32),&value32,EC_TIMEOUTRXM);
	//value32 = 0x60FF0020;
	value32 = 0x60810020;
	ec_SDOwrite(i,0x1600,4,FALSE,sizeof(value32),&value32,EC_TIMEOUTRXM);
	value16 = 4;
	ec_SDOwrite(i,0x1600,0,FALSE,sizeof(value16),&value16,EC_TIMEOUTRXM);

	value16 = 1;
	ec_SDOwrite(i,0x1C12,0,FALSE,sizeof(value16),&value16,EC_TIMEOUTRXM);
	ec_SDOwrite(i,0x1C13,0,FALSE,sizeof(value16),&value16,EC_TIMEOUTRXM);
	return 0;

}
### SOEM伺服电机回原点方法 在处理SOEM(Simple Open EtherCAT Master)控制下的伺服电机时,实现电机回原点功能通常涉及配置特定的操作模式以及设置相应的参数。当遇到无法使电机转动的情况时,可能的原因包括操作模式配置错误、硬件连接问题或是软件中的初始化不当。 #### CSP模式下电机不转的潜在原因分析 如果CSP(Controlled Speed Positioning, 控制速度定位)模式能够成功使能电机但电机却不旋转,则可能是由于以下几个方面的问题: - **目标位置未设定**:即使选择了适当的位置控制模式,在没有指定具体的目标位置之前,电机不会执行任何动作。 - **速度限制过低**:某些情况下,默认的速度上限可能会被设得非常低以至于看起来像是电机根本没有启动。 - **加减速时间不合适**:太短或太长的加速/减速时间段可能导致实际运动表现不符合预期。 - **反馈信号丢失**:编码器或其他形式的位置传感器未能正确提供反馈数据给主站,这会阻止控制系统确认当前位置并据此调整输出指令[^1]。 针对上述情况,建议按照以下步骤排查和解决: 1. 检查并验证所有必要的通信链路都处于良好状态; 2. 确认所使用的PDO映射包含了用于发送命令字节及接收状态信息的对象; 3. 审核SDO请求以确保已正确定义了诸如最大速度、加速度等关键属性; 4. 使用调试工具监控实时变量的变化趋势来辅助诊断过程。 #### 实现回零位的具体做法 为了完成回到机械零点的动作序列,一般遵循如下流程: ```cpp // 假定已经建立了有效的EtherCAT网络连接,并且设备已被识别 void moveToHomePosition(EthercatMaster& master){ // 设置为绝对移动模式 (Homing Mode) setOperationMode(master, HOMING_MODE); // 发送寻参脉冲寻找参考标记 sendReferenceMarkPulse(master); // 启动向家方向搜索直到检测到开关触发 startSearchForSwitchInPositiveDirection(master); // 减速至接近停止后反转一定距离远离限位开关 moveAwayFromLimitSwitchAtReducedSpeed(master); // 再次靠近直至再次触碰限位开关从而精确定位 approachToFinalizeHommingProcess(master); // 将当前坐标记录为新的逻辑上的'0' resetLogicalZeroPoint(master); } ``` 此函数展示了如何通过编程手段指导驱动器完成一系列标准化程序最终达到定义好的起始位置。需要注意的是不同品牌型号之间可能存在差异因此务必参照官方文档获取最准确的方法指南[^2]。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值