安川机器人之motoPlus的编程与导入

        由于网上关于安川机器人的motoPlus二次开发实在太少,本人最近由于项目原因接触并学习到了一点,仅此做个分享,有问题可以交流。

        一、motoPlus编译文件的导入与使用

        一般用的比较多的控制柜是DX200系列跟YRC1000系列,motoPlus软件与加密狗需要购买或者找公司相关人员借用。安川示教器本身不具备用户界面功能,程序调试十分麻烦,在使用motoPlus编译的.out文件导入时,需要先长按示教器上的“MainMenu”按钮,再开启控制柜进入维护模式,在维护模式下,需要在系统中将安全模式转换到管理模式。

        管理模式下,在系统设置中,进入选项功能,将motoPlus功能开启,如果后续需要TCP网络服务功能的,可以在这也开启一下,不过开启网络服务需要加密狗权限,并且进入别的模式,本人不是安川员工,这一块可以去咨询相关人员。

        开启motoPlus功能后,可以在主菜单的motoPlus应用中,将装置选择为示教器USB或者控制柜USB,将含有编译文件的U盘进行读取,点击motoPlus应用的安装可以进行安装。注意,控制柜中的motoPlus文件只能存在一个,同名的可以在安装时提示是否覆盖,不同名的只能先删除前一个再进行安装。

        重点的来了,在安装完编译文件后,需要在motoPlus应用里进行额外的设置,后台电源自动运行以及资源权限的设置。安川机器人控制柜的motoPlus编译文件是重启控制柜后,后台自动运行的,在运行时,如果程序存在错误,示教器会进行报错,但是不存在用户界面看到你打印的信息,只能通过对里面的变量或者IO进行读取或写入,十分难绷。所以在写主程序逻辑的时候需要注意如何去看到自己的调试过程,千万别以为motoPlus编译通过了就能完全运行。报错信息可以去查看相关的文档,一般来说都是变量、函数、符号等存在问题,一定要仔细检查。

        二、motoPlus的编程

        其实大多项目二次开发都是用于Socket通讯,与上位机软件交互机器人的当前信息,motoPlus是基于C语言重新开发的,提供了比较多的API接口,大家可以去安川电机的官网搜索motoPlus查看相关的教程与文档。这里我简单的提供几个自己写的函数,以供参考。需要注意的是,机器人关节角度与偏移位置的获取需要将反馈脉冲转换到演算脉冲,再转换到角度,角度再转换到偏移位置,并且单位都是0.0001deg。Socket通信与C语言本身的通信是基本一致的,大家可以在文档中进行查看,这里我也把自己使用的Socket代码贴出来。本人代码能力有限,大伙想优化的自己优化。

//传入数组,获取当前的角度与偏移值
void GetCurPos(float* CurJpos, float* CurPpos) { 
	//Jpos
	long pulse[MP_GRP_AXES_NUM];
	long angle[MP_GRP_AXES_NUM];
	int i, rc;
	MP_CTRL_GRP_SEND_DATA CurJposGrp;
	MP_FB_PULSE_POS_RSP_DATA CurJposData;
	CurJposGrp.sCtrlGrp = 0;
	memset(&CurJposData, 0, sizeof(CurJposData));
	mpGetFBPulsePos(&CurJposGrp, &CurJposData);
	int grp_no = mpCtrlGrpId2GrpNo(MP_R1_GID);
	memset(pulse, 0, sizeof(pulse));
	memset(angle, 0, sizeof(angle));
	rc = mpConvFBPulseToPulse(grp_no, CurJposData.lPos, pulse);
	rc = mpConvPulseToAngle(grp_no, pulse, angle);
	for (i = 0; i <= 5; ++i) {
		CurJpos[i] = angle[i]/10000;
	}
	//Ppos
	MP_COORD bas_coord;
	MP_PULSE_POS_RSP_DATA PlsData;
	memset(&bas_coord, 0, sizeof(bas_coord));
	rc = mpConvAxesToCartPos(grp_no, angle, 0, NULL, &bas_coord);
	CurPpos[0] = bas_coord.x / 1000;
	CurPpos[1] = bas_coord.y / 1000;
	CurPpos[2] = bas_coord.z / 1000;
	CurPpos[3] = bas_coord.rx / 10000;
	CurPpos[4] = bas_coord.ry / 10000;
	CurPpos[5] = bas_coord.rz / 10000;
}

//获取指定的IO状态
bool GetIO(int ioAddr)
{   
    int* signal;
	MP_IO_INFO nfo;
	nfo.ulAddr = ioAddr;
	int a = mpReadIO(&nfo, signal, 1);
	return (bool)(*signal);
}

//获取从指定的Int变量开始,num个int值,存入给定的数组中
void GetVarInt(int index, int num, int* result) {
	int i;
	MP_VAR_INFO sData[20];
	int rData[20];
	for (i = 0; i < num; ++i) {
		sData[i].usType = MP_RESTYPE_VAR_I;
		sData[i].usIndex = index + i;
	}
	int status = mpGetVarData(&sData, rData, num);
	for (i = 0; i < num; ++i) {
		result[i] = rData[i];
	}
}

//获取从指定的Real变量开始,num个float值,存入给定的数组中
void GetVarFlt(int index, int num, float* result) {
	int i;
	MP_VAR_INFO sData[20];
	float rData[20];
	for (i = 0; i < num; ++i) {
		sData[i].usType = MP_RESTYPE_VAR_R;
		sData[i].usIndex = index + i;
	}
	int status = mpGetVarData(&sData, rData, num);
	for (i = 0; i < num; ++i) {
		result[i] = rData[i];
	}
}

//将input数组中的值设置到从index开始的num个Int变量中,其中sData的大小自己可以设置
void SetVarInt(int index, int* input, int num) {
	MP_VAR_DATA sData[20];
	int i;
	for (i = 0; i < num; ++i) {
		sData[i].usType = MP_RESTYPE_VAR_I;
		sData[i].usIndex = index + i;
		sData[i].ulValue = input[i];
	}
	long status = mpPutVarData(&sData, num);
}

//将input数组中的值设置到从index开始的num个R变量中,其中sData的大小自己可以设置
void SetVarFlt(int index, float* input, int num) {
	MP_VAR_DATA sData[20];
	int i;
	for (i = 0; i < num; ++i) {
		sData[i].usType = MP_RESTYPE_VAR_R;
		sData[i].usIndex = index + i;
		sData[i].ulValue = input[i];
	}
	long status = mpPutVarData(&sData, num);
}

//设置一个value值到index编号的Int变量中
void SetOnlyInt(int index, int value) {
	MP_VAR_DATA sData;
	sData.usType = MP_RESTYPE_VAR_I;
	sData.usIndex = index;
	sData.ulValue = value;
	long status = mpPutVarData(&sData, 1);
}

//获取index编号的Int变量值
int GetOnlyInt(int index) {
	MP_VAR_INFO sData;
	sData.usType = MP_RESTYPE_VAR_I;
	sData.usIndex = index;
	int rData = 0;
	long status = mpGetVarData(&sData, &rData, 1);
	return rData;
}

Socket的使用如下,这里我使用循环去控制通讯的交互,再断连后可以重新连接,机器人做服务端。

//将服务端Socket定义全局,后续可以拿来重新连接,初始化socket,返回连接的客户端socket
int SeverSocket;
int TcpInit() {
	const int SeverPort = 8800;
	struct sockaddr_in  serverSockAddr;
	struct sockaddr_in cilentSockAddr;
	int status;
	int AcceptHandle;
	SeverSocket = mpSocket(AF_INET, SOCK_STREAM, 0);
	if (SeverSocket < 0) {
		printf("create socket fail\n");
		return -1;
	}
	memset(&cilentSockAddr, 0, sizeof(cilentSockAddr));	
	memset(&serverSockAddr, 0, sizeof(serverSockAddr));
	serverSockAddr.sin_family = AF_INET;
	serverSockAddr.sin_addr.s_addr = INADDR_ANY;
	serverSockAddr.sin_port = mpHtons(SeverPort);
	status = mpBind(SeverSocket, (struct sockaddr*)&serverSockAddr, sizeof(serverSockAddr));
	if (status < 0) {
		printf("Bind socket fail\n");
		CloseSocket(SeverSocket);
	}
	status = mpListen(SeverSocket, SOMAXCONN);
	if (status < 0) {
		printf("listen port fail\n");
		CloseSocket(SeverSocket);
	}
	AcceptHandle = mpAccept(SeverSocket, (struct sockaddr*)&cilentSockAddr, sizeof(cilentSockAddr));
	if (AcceptHandle < 0) {
	AcceptHandle = Reconnect(AcceptHandle);
	}
	
	return AcceptHandle;
}

//接收数据
void Analyze(int AcceptHandle) {
	int byteRecv, Order;
	char Buffer[10] = { 0 }; //接收数据的长度自己定义
	int DelayTime = mpGetRtc();
	while (1) {
		mpTaskDelay(20*DelayTime);
		ResetVar();
		memset(Buffer, 0, sizeof(Buffer));
		byteRecv = mpRecv(AcceptHandle, Buffer, 10, 0); //这里也需要修改
		if ((byteRecv <= 0)) {
			printf("recieve data fail");
			AcceptHandle = Reconnect(AcceptHandle);
			continue; 
		}
        
    AnalyzeDataLogic();//处理数据的逻辑写在这
    
    char SendBuffer[10];//需要发送的数据
    int byteSend = mpSend(CilentSocket, SendBuffer, strlen(SendBuffer), 0);
    if (byteSend != 10) { //发送数据的长度
	    printf("send data error \n");
    }

    }
}

//客户端断开后,关闭客户端socket资源,不然服务端会拒绝连接,重新建立客户端进行连接,并返回客户端描述符
int Reconnect(int ClientSocket) {
	CloseSocket(ClientSocket);
	struct sockaddr_in cilentSockAddr;
	memset(&cilentSockAddr, 0, sizeof(cilentSockAddr));	
	int AcceptHandle = mpAccept(SeverSocket, (struct sockaddr*)&cilentSockAddr, sizeof(cilentSockAddr));
	return AcceptHandle;
}

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值