睿尔曼复合机器人

Forrest 2023-11-18

复合机器人
  复合机器人集成了AGV移动机器人和机械臂,可搭载自动化夹具、视觉系统、智能螺丝刀等执行单元,在未来智慧场景中,复合机器人更为精细化,能够适应高复杂度、高精度的环境,具备移动性、自主性、协作性。与传统机器人相比,具有非标自动化设备所不具备的能力,即可完成移动搬运取料的任务,又可加入产线承担具体工种的加工操作。

        AGV复合机器人是一种具备移动机器人和协作机械臂二者功能的新型机器人,复合机器人可配备多种传感器,如激光雷达、视觉传感器、磁导航传感器、超声测距传感器、碰撞传感器、红外传感器、IMU传感器等。根据移动底盘的不同,可实现室内外不同场景下的巡检、采摘、仓储转运等任务。

       本文以睿尔曼超轻量仿人机械臂+云迹全向底盘实现集成开发一台AGV复合机器人,并将集成过程作记录。

  复合机器人实物示意图:



协作机械臂

根据场景要求,选择睿尔曼超轻量仿人六轴机械臂作为复合机械臂的操作机械臂,并且在机械臂末端集成执行器。

        主要参数如下:


移动底盘

       根据工作场景要求,选择“云迹水滴2”作为移动底盘,实现建图、导航、避障功能,同时底盘具备自主回充功能。

主要参数如下:


复合机器人硬件连接示意图:

接线说明:机械臂、移动底盘、NX主控通过网线连接至小型交换机,用于各模块之间通信;NX主控、交换机的供电从移动底盘分别通过1个稳压模块完成;末端执行器安装并连接至机械臂末端,与机械臂进行通信,且机械臂供电给末端执行器。

      复合机器人硬件完成搭建之后进行软件的适配,机器人各模块之间采用TCP/IP的通信方式。主要实现方式为机械臂和底盘均为Socket通信的服务端,NX主控作为客户端,创建连接且分别连接机械臂与移动底盘,连接成功之后机械臂、移动底盘的控制指令与返回值接收都在NX主控完成。

移动底盘API资料

移动底盘提供一套软件API手册,其中包含机器人地图查询、状态查询、点位创建等等接口,如下所示:
/api/move?marker=target_name
// 调用移动接口,移动至代号为"target_name"的目标点
返回: { "type": "response", "command": "/api/move", "uuid": "", "status": "OK", "error_message": "", "task_id": "xxx" // (软件版本0.7.3之后新增) 32个字节的uuid,例如:436253D1D6284ACC}
/api/move/cancel
// 取消当前正在进行的移动指令 
返回: { "type": "response", "command": "/api/move/cancel", "uuid": "", "status": "OK", "error_message": "" }
/api/robot_status// 获得机器人当前的全局状态
成功时返回:{ "type": "response", "command": "/api/robot_status", "uuid": "", "status": "OK", "error_message": "", "results": { "move_target": "target_name", // 移动指令指定的目标点位名称 "move_status": "running", // 移动指令的执行状态。详细解释见后边 "running_status": "running", // v0.7.12新增,移动任务的具体状态, 详细见后面解释 "move_retry_times": 3, //此次数每增加1,表示机器人进行了新一轮的路径重试;路径规划一 "charge_state": bool, //true->充电中状态。false->未充电状态。 "soft_estop_state": bool, // 通过API接口设置的软急停状态, true->急停中,false->非 "hard_estop_state": bool, // 通过硬件急停按钮设置的硬急停状态, true->急停中,fals "estop_state": bool, // hard_estop_state || sofpt_estop_state, true->急停中 "power_percent": 100, //电量百分比,单位:% "current_pose": { "x": 11.0, // 单位:m "y": 11.0, // 单位:m "theta": 0.5, //单位:rad } "current_floor": 16, "chargepile_id": "1234", // v0.9.6新增。充电状态下表示当前正在充电的充电桩ID,非充 "error_code": "00000000" // v0.7.7新增,16进制错误码,总共8个字节表示,非0表示机 }
失败时返回:{
"type": "response",
"command": "/api/robot_status",
"uuid": "", "status": "UNKNOWN_ERROR", "error_message": "Can't catch current robot status" "results" }失败时请检查地图是否设置正确或者硬件是否有故障。 

其他指令可以通过"WATER(⽔滴)软件API⼿册"查看,下面我们用Python做程序与移动底盘进行通信,实现控制底盘。

机械臂JSON协议资料

机械臂的控制可以直接发送JSON协议指令和使用API进行通信,如下所示:

(1)查询机械臂状态

(2)MoveJ:关节运动 

(3)MoveL:直线运动

 

Python实现Socket通信

 首先来看一下如何用Python实现Socket通信,Python 提供了两个级别访问的网络服务:
      1.低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法。
       2.高级别的网络服务模块 SocketServer,它提供了服务器中心类,可以简化网络服务器的开发。
本文中仅对Socket进行讲述。注意:在使用Socket创建连接时,使用完毕之后必须调用close()方法关闭连接。

Scoket()函数介绍

        Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
Python3 中,我们用 socket() 函数来创建套接字,语法格式如下:

socket.socket([family[, type[, proto]]])

 创建客户端

        Socket客户端创建完成,并且连接服务端之后,会接收到服务端向外广播的信息,且服务端可以获得客户端的IP及其他信息。创建客户端程序如下所示:

# 导入 socket、sys 模块
import socket
import sys
# 创建 socket 对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 服务端/移动底盘的IP
host = '192.168.10.10'
# 移动底盘的端口号
port = 8001
# 连接服务,指定主机和端口
s.connect((host, port))
# 接收小于 1024 字节的数据
msg = s.recv(1024)
s.close()
print (msg.decode('utf-8'))

 实现底盘通信

import socket
import json
import time
client1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#底盘的IP
host1 = '192.168.10.10'
#底盘的控制端口
port1 = 31001
#创建与移动底盘的连接
client1.connect((host1, port1))
str1 = ""
#查询底盘的地图列表指令
point1 = '/api/map/list'
#发送指令
client1.send(point1.encode('utf-8'))
#接收底盘返回
data1 = client1.recv(1024).decode()
print(data1)
point2= '/api/move?marker=071901'
client1.send(point2.encode('utf-8'))
data1 = client1.recv(1024).decode()
point3='/api/move?marker=071902'
client1.send(point3.encode('utf-8'))
data1 = client1.recv(1024).decode()
client1.close()

实现机械臂通信的Python程序

import socket
import time
import json
#创建协议指令,下方几个为机械臂运动指令。
point1= '{"command":"movej","joint":[-41395,195,-2699,103268,872,74955,12639],"v":50,"r":0}\r\n'
 
point2= '{"command":"movej","joint":[-42635,5399,9327,108735,-766,64883,21533],"v":30,"r":0}\r\n'
 
point3= '{"command":"movel","pose":[181030,-121700,225700,3132,16,2189],"v":10,"r":0}\r\n'
 
point4= '{"command":"movel","pose":[181030,-121700,265770,3132,16,2189],"v":10,"r":0}\r\n'
 
point5= '{"command":"movej","joint":[-42845,32180,-41576,52599,21931,100707,20650],"v":30,"r":0}\r\n'
 
point6= '{"command":"movel","pose":[154270,-293080,299560,3133,16,2189],"v":10,"r":0}\r\n'
 
point7= '{"command":"movel","pose":[154270,-293080,354680,3133,16,2189],"v":10,"r":0}\r\n'
#创建Socket连接
client1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host1 = '192.168.1.18'
port1 = 8080
client1.connect((host1, port1))
client1.send(point1.encode('utf-8'))
 
data1 = client1.recv(1024).decode()
 
time.sleep(5)
print(data1)
 
client1.send(point2.encode('utf-8'))
data1 = client1.recv(1024).decode()
time.sleep(0.5)
 
client1.send(point3.encode('utf-8'))
data1 = client1.recv(1024).decode()
time.sleep(0.5)
 
speed_close = '{"command":"write_single_register","port":1,"address":264,"data":1,"device":1}\r\n'
 
speed_100 = '{"command":"write_single_register","port":1,"address":262,"data":100,"device":1}\r\n'
client1.send(speed_100.encode('utf-8'))
data3 = client1.recv(1024).decode()
time.sleep(0.5)
 
str_1000= '{"command":"write_single_register","port":1,"address":261,"data":1000,"device":1}\r\n'
client1.send(str_1000.encode('utf-8'))
data6 = client1.recv(1024).decode()
time.sleep(0.5)
 
client1.send(speed_close.encode('utf-8'))
data2 = client1.recv(1024).decode()
time.sleep(0.5)
 
client1.send(point4.encode('utf-8'))
data1 = client1.recv(1024).decode()
time.sleep(0.5)
 
client1.send(point5.encode('utf-8'))
data1 = client1.recv(1024).decode()
time.sleep(0.5)
 
client1.send(point6.encode('utf-8'))
data1 = client1.recv(1024).decode()
time.sleep(0.5)
str_0= '{"command":"write_single_register","port":1,"address":261,"data":0,"device":1}\r\n'
client1.send(str_0.encode('utf-8'))
data4 = client1.recv(1024).decode()
time.sleep(0.5)
client1.send(speed_close.encode('utf-8'))
data2 = client1.recv(1024).decode()
time.sleep(0.5)
client1.send(point7.encode('utf-8'))
data1 = client1.recv(1024).decode()
time.sleep(0.5)
client1.close()

复合机器人整体程序只需将底盘与机械臂的控制程序整合到一处即可,此处暂不做解释。

0 条评论

关于作者

Forrest

让机械臂成为智能、易用、可靠、通用的作业工具,走入千行百业、千家万户。

选择发帖板块
选择发帖板块