Files
Uni-Lab-OS/unilabos/devices/arm/elite_robot.py
q434343 dcc970a091 Device visualization (#67)
* Update README and MQTTClient for installation instructions and code improvements

* feat: 支持local_config启动
add: 增加对crt path的说明,为传入config.py的相对路径
move: web component

* add: registry description

* add 3d visualization

* 完成在main中启动设备可视化

完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model

添加物料模型管理类,遍历物料与resource_model,完成TF数据收集

* 完成TF发布

* 修改模型方向,在yaml中添加变换属性

* 添加物料tf变化时,发送topic到前端

另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题

* 添加关节发布节点与物料可视化节点进入unilab

* 使用json启动plr与3D模型仿真

* feat: node_info_update srv
fix: OTDeck cant create

* close #12
feat: slave node registry

* feat: show machine name
fix: host node registry not uploaded

* feat: add hplc registry

* feat: add hplc registry

* fix: hplc status typo

* fix: devices/

* 完成启动OT并联动rviz

* add 3d visualization

* 完成在main中启动设备可视化

完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model

添加物料模型管理类,遍历物料与resource_model,完成TF数据收集

* 完成TF发布

* 修改模型方向,在yaml中添加变换属性

* 添加物料tf变化时,发送topic到前端

另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题

* 添加关节发布节点与物料可视化节点进入unilab

* 使用json启动plr与3D模型仿真

* 完成启动OT并联动rviz

* fix: device.class possible null

* fix: HPLC additions with online service

* fix: slave mode spin not working

* fix: slave mode spin not working

* 修复rviz位置问题,

修复rviz位置问题,
在无tf变动时减缓发送频率
在backend中添加物料跟随方法

* feat: 多ProtocolNode 允许子设备ID相同
feat: 上报发现的ActionClient
feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报

* feat: 支持env设置config

* fix: running logic

* fix: running logic

* fix: missing ot

* 在main中直接初始化republisher和物料的mesh节点

* 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中

* Device visualization (#14)

* add 3d visualization

* 完成在main中启动设备可视化

完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model

添加物料模型管理类,遍历物料与resource_model,完成TF数据收集

* 完成TF发布

* 修改模型方向,在yaml中添加变换属性

* 添加物料tf变化时,发送topic到前端

另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题

* 添加关节发布节点与物料可视化节点进入unilab

* 使用json启动plr与3D模型仿真

* 完成启动OT并联动rviz

* add 3d visualization

* 完成在main中启动设备可视化

完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model

添加物料模型管理类,遍历物料与resource_model,完成TF数据收集

* 完成TF发布

* 修改模型方向,在yaml中添加变换属性

* 添加物料tf变化时,发送topic到前端

另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题

* 添加关节发布节点与物料可视化节点进入unilab

* 使用json启动plr与3D模型仿真

* 完成启动OT并联动rviz

* 修复rviz位置问题,

修复rviz位置问题,
在无tf变动时减缓发送频率
在backend中添加物料跟随方法

* fix: running logic

* fix: running logic

* fix: missing ot

* 在main中直接初始化republisher和物料的mesh节点

* 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中

---------

Co-authored-by: zhangshixiang <@zhangshixiang>
Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com>

* fix: missing hostname in devices_names
fix: upload_file for model file

* fix: missing paho-mqtt package
bump version to 0.9.0

* fix startup
add ResourceCreateFromOuter.action

* fix type hint

* update actions

* update actions

* host node add_resource_from_outer
fix cmake list

* pass device config to device class

* add: bind_parent_ids to resource create action
fix: message convert string

* fix: host node should not be re_discovered

* feat: resource tracker support dict

* feat: add more necessary params

* feat: fix boolean null in registry action data

* feat: add outer resource

* 编写mesh添加action

* feat: append resource

* add action

* feat: vis 2d for plr

* fix

* fix: browser on rviz

* fix: cloud bridge error fallback to local

* fix: salve auto run rviz

* 初始化两个plate

* Device visualization (#22)

* add 3d visualization

* 完成在main中启动设备可视化

完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model

添加物料模型管理类,遍历物料与resource_model,完成TF数据收集

* 完成TF发布

* 修改模型方向,在yaml中添加变换属性

* 添加物料tf变化时,发送topic到前端

另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题

* 添加关节发布节点与物料可视化节点进入unilab

* 使用json启动plr与3D模型仿真

* 完成启动OT并联动rviz

* add 3d visualization

* 完成在main中启动设备可视化

完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model

添加物料模型管理类,遍历物料与resource_model,完成TF数据收集

* 完成TF发布

* 修改模型方向,在yaml中添加变换属性

* 添加物料tf变化时,发送topic到前端

另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题

* 添加关节发布节点与物料可视化节点进入unilab

* 使用json启动plr与3D模型仿真

* 完成启动OT并联动rviz

* 修复rviz位置问题,

修复rviz位置问题,
在无tf变动时减缓发送频率
在backend中添加物料跟随方法

* fix: running logic

* fix: running logic

* fix: missing ot

* 在main中直接初始化republisher和物料的mesh节点

* 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中

* 编写mesh添加action

* add action

* fix

* fix: browser on rviz

* fix: cloud bridge error fallback to local

* fix: salve auto run rviz

* 初始化两个plate

---------

Co-authored-by: zhangshixiang <@zhangshixiang>
Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com>

* fix: multi channel

* fix: aspirate

* fix: aspirate

* fix: aspirate

* fix: aspirate

* 提交

* fix: jobadd

* fix: jobadd

* fix: msg converter

* tijiao

* add resource creat easy action

* identify debug msg

* mq client id

* 提取lh的joint发布

* unify liquid_handler definition

* 修改物料跟随与物料添加逻辑

修改物料跟随与物料添加逻辑
将joint_publisher类移出lh的backends,但仍需要对lh的backends进行一些改写

* Revert "修改物料跟随与物料添加逻辑"

This reverts commit 498c997ad7.

* Reapply "修改物料跟随与物料添加逻辑"

This reverts commit 3a60d2ae81.

* Revert "Merge remote-tracking branch 'upstream/dev' into device_visualization"

This reverts commit fa727220af, reversing
changes made to 498c997ad7.

* 修改物料放下时的方法,如果选择

修改物料放下时的方法,
如果选择drop_trash,则删除物料显示
如果选择drop,则让其解除连接

* unilab添加moveit启动

1,整合所有moveit节点到一个move_group中,并整合所有的controller依次激活
2,添加pymoveit2的节点,使用json可直接启动
3,修改机械臂规划方式,添加约束,让冗余关节不会进行过多移动

* 修改物体attach时,多次赋值当前时间导致卡顿问题,

* Revert "修改物体attach时,多次赋值当前时间导致卡顿问题,"

This reverts commit 56d45b94f5.

* Reapply "修改物体attach时,多次赋值当前时间导致卡顿问题,"

This reverts commit 07d9db20c3.

* 添加缺少物料:"plate_well_G12",

* add

* fix tip resource data

* liquid states

* change to debug level

* Revert "change to debug level"

This reverts commit 5d9953c3e5.

* Reapply "change to debug level"

This reverts commit 2487bb6ffc.

* fix tip resource data

* add full device

* add moveit yaml

* 修复moveit
增加post_init阶段,给予ros_node反向

* remove necessary node

* fix moveit action client

* remove necessary imports

* Update moveit_interface.py

* fix handler_key uppercase

* json add liquids

* fix setup

* add

* change to "sources" and "targets" for lh

* bump version

* remove parent's parent link

* change arm's name

* change name

* fix ik error

* 修改moveit_interface,并在mqtt上报时发送一个时间戳

* 添加机械臂和移液站

* 添加

* 添加硬件

* update

* 添加

---------

Co-authored-by: Harvey Que <Q-Query@outlook.com>
Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com>
Co-authored-by: zhangshixiang <@zhangshixiang>
Co-authored-by: Junhan Chang <changjh@pku.edu.cn>
2025-08-01 01:06:10 +08:00

196 lines
7.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import socket
import re
import time
from rclpy.node import Node
from sensor_msgs.msg import JointState
class EliteRobot:
def __init__(self,device_id, host, **kwargs):
self.host = host
self.node = Node(f"{device_id}")
self.joint_state_msg = JointState()
self.joint_state_msg.name = [f"{device_id}_shoulder_pan_joint",
f"{device_id}_shoulder_lift_joint",
f"{device_id}_elbow_joint",
f"{device_id}_wrist_1_joint",
f"{device_id}_wrist_2_joint",
f"{device_id}_wrist_3_joint"]
self.job_id = 0
self.joint_state_pub = self.node.create_publisher(JointState, "/joint_states", 10)
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 实现一个简单的Modbus TCP/IP协议客户端端口为502
self.modbus_port = 502
self.modbus_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.modbus_sock.connect((self.host, self.modbus_port))
print(f"已成功连接到Modbus服务器 {self.host}:{self.modbus_port}")
except Exception as e:
print(f"连接到Modbus服务器 {self.host}:{self.modbus_port} 失败: {e}")
try:
self.sock.connect((self.host, 40011))
print(f"已成功连接到 {self.host}:{40011}")
except Exception as e:
print(f"连接到 {self.host}:{40011} 失败: {e}")
def modbus_close(self):
self.modbus_sock.close()
@property
def arm_pose(self) -> list[float]:
return self.get_actual_joint_positions()
def modbus_write_single_register(self, unit_id, register_addr, value):
"""
写入单个Modbus保持寄存器带符号整数
:param unit_id: 从站地址
:param register_addr: 寄存器地址
:param value: 要写入的值(-32768~32767带符号16位整数
:return: True表示写入成功False表示失败
"""
transaction_id = 0x0001
protocol_id = 0x0000
length = 6 # 后续字节数
function_code = 0x06 # 写单个保持寄存器
header = transaction_id.to_bytes(2, 'big') + protocol_id.to_bytes(2, 'big') + length.to_bytes(2, 'big')
# value用带符号16位整数编码
body = (
unit_id.to_bytes(1, 'big') +
function_code.to_bytes(1, 'big') +
register_addr.to_bytes(2, 'big') +
value.to_bytes(2, 'big', signed=True)
)
request = header + body
try:
self.modbus_sock.sendall(request)
response = self.modbus_sock.recv(1024)
# 响应应与请求的body部分一致
if len(response) >= 12 and response[7] == function_code:
# 响应的寄存器值也要按带符号整数比对
if response[8:12] == body[2:]:
return True
else:
print("Modbus写入响应内容与请求不一致")
return False
else:
print("Modbus写入响应格式错误或功能码不匹配")
return False
except Exception as e:
print("Modbus写入寄存器时出错:", e)
return False
def modbus_read_holding_registers(self, unit_id, start_addr, quantity):
"""
读取Modbus保持寄存器带符号整数
:param unit_id: 从站地址
:param start_addr: 起始寄存器地址
:param quantity: 读取数量
:return: 读取到的数据list of int带符号16位整数或None
"""
# 构造Modbus TCP帧
transaction_id = 0x0001
protocol_id = 0x0000
length = 6 # 后续字节数
function_code = 0x03 # 读保持寄存器
header = transaction_id.to_bytes(2, 'big') + protocol_id.to_bytes(2, 'big') + length.to_bytes(2, 'big')
body = (
unit_id.to_bytes(1, 'big') +
function_code.to_bytes(1, 'big') +
start_addr.to_bytes(2, 'big') +
quantity.to_bytes(2, 'big')
)
request = header + body
try:
self.modbus_sock.sendall(request)
response = self.modbus_sock.recv(1024)
# 简单解析响应
if len(response) >= 9 and response[7] == function_code:
byte_count = response[8]
data_bytes = response[9:9+byte_count]
# 按带符号16位整数解码
result = []
for i in range(0, len(data_bytes), 2):
val = int.from_bytes(data_bytes[i:i+2], 'big', signed=True)
result.append(val)
return result
else:
print("Modbus响应格式错误或功能码不匹配")
return None
except Exception as e:
print("Modbus读取寄存器时出错:", e)
return None
def modbus_task(self, job_id):
self.modbus_write_single_register(1, 256, job_id)
self.job_id = job_id
job = self.modbus_read_holding_registers(1, 257, 1)[0]
while job != self.job_id:
time.sleep(0.1)
job = self.modbus_read_holding_registers(1, 257, 1)[0]
self.get_actual_joint_positions()
def modbus_task_cmd(self, command):
if command == "lh2hplc":
self.modbus_task(1)
self.modbus_task(2)
elif command == "hplc2lh":
self.modbus_task(3)
self.modbus_task(4)
self.modbus_task(0)
def send_command(self, command):
self.sock.sendall(command.encode('utf-8'))
response = self.sock.recv(1024).decode('utf-8')
return response
def close(self):
self.sock.close()
def __del__(self):
self.close()
def parse_success_response(self, response):
"""
解析以[success]开头的返回数据,提取数组
:param response: 字符串,形如 "[success] : [[3.158915, -1.961981, ...]]"
:return: 数组list of float如果解析失败则返回None
"""
if response.startswith("[1] [success]"):
match = re.search(r"\[\[([^\]]+)\]\]", response)
if match:
data_str = match.group(1)
try:
data_array = [float(x.strip()) for x in data_str.split(',')]
return data_array
except Exception as e:
print("解析数组时出错:", e)
return None
return None
def get_actual_joint_positions(self):
response = self.send_command(f"req 1 get_actual_joint_positions()\n")
joint_positions = self.parse_success_response(response)
if joint_positions:
self.joint_state_msg.position = joint_positions
self.joint_state_pub.publish(self.joint_state_msg)
return joint_positions
return None
if __name__ == "__main__":
import rclpy
rclpy.init()
client = EliteRobot('aa',"192.168.1.200")
print(client.parse_success_response(client.send_command("req 1 get_actual_joint_positions()\n")))
client.modbus_write_single_register(1, 256, 4)
print(client.modbus_read_holding_registers(1, 257, 1))
client.close()