一、简介
本案例使用机器人,末端安装onRobot夹爪,实现类似码垛的功能
需要的配方文件作为附件置于文末,运行时需要放置在同目录下
需要的配方文件作为附件置于文末,运行时需要放置在同目录下
二、操作流程
1、以编译的方式安装elite-cs-sdk的python sdk,确保文末的配方文件放置在同目录下
2、修改代码中机器人的IP地址,ROBOT_IP更改为本地机器人ip地址
3、修改代码中所有点位的位置,确保所有点位可达,且保证点位均为笛卡尔位姿
4、执行下方的python文件,此时机器人会重复从取料点PICK_POSE夹取物体,分别搬运物体到九个目标位置。
三、常见问题
1、Q:为什么夹爪夹不住物体
A:夹爪通过modbus RTU来控制,tool_modbus_write_registers用于写modbus数据,其中0x41为设备地址,地址0控制夹爪宽度,地址1控制夹爪力度,地址2控制夹爪速度,地址3控制夹爪命令。所以在使用的时候需要调整夹爪的宽度和力度来夹取物体
四、代码和附件
主要流程:
DashboardClientInterface().connect(ROBOT_IP, 29999)连 Dashboarddash.powerOn()上电 → sleep 2s →dash.brakeRelease()释放抱闸 →dash.disconnect()EliteDriverConfig()配置 headless 模式 →EliteDriver(config)构造 → 轮询driver.isRobotConnected()等就绪send_40011(1, "tool_serial_config(...)")通过 40011 端口初始化末端 RS-485 Modbus 夹爪send_40011("tool_modbus_write_registers(0x41, 0, 800)")+send_40011("...0x41, 3, 1")→gripper_open()张开夹爪cartesian_move(driver, HOME_POSE, 2.0)→ 内部:
driver.setTrajectoryResultCallback(on_done)注册完成回调driver.writeTrajectoryControlAction(START, 1, 200)启动轨迹driver.writeTrajectoryPoint(pose, time, blend, cartesian=True)下发笛卡尔目标点- 循环
driver.writeTrajectoryControlAction(NOOP, 0, 200)保活 +Future等完成 driver.writeIdle(0)回 idle
- 码垛循环(按 P1→P9 顺序 3×3 网格):
cartesian_move(PICK_Z_UP)→cartesian_move(PICK_POSE)→gripper_close()夹取cartesian_move(PICK_Z_UP)→cartesian_move(Z_UP)→cartesian_move(PLACE_POSE)→gripper_open()放置cartesian_move(Z_UP)抬起
driver.stopControl()清理
涉及接口:
组件 | 接口 | 用途 |
|---|---|---|
Dashboard (29999) | connect / powerOn / brakeRelease / disconnect | 上电初始化 |
EliteDriver | isRobotConnected / writeTrajectoryControlAction(START/NOOP) / writeTrajectoryPoint(cartesian=True) / setTrajectoryResultCallback / writeIdle / stopControl | 笛卡尔轨迹控制 |
40011 (Socket) | send_40011 → tool_serial_config / tool_modbus_write_registers | 末端 RS-485 Modbus 夹爪控制 |
"""
Elite CS Robot Palletizing (Cartesian Trajectory)
- EliteDriver trajectory control (Cartesian coordinates)
- Gripper: Tool-end RS-485 Modbus RTU (via port 40011 EliteScript)
- Fixed pick point, 3x3 grid place points
Points [x, y, z, Rx, Ry, Rz] (meters/radians):
HOME: [0.488, -0.148, 0.493, 3.141, 0, -1.571]
PICK: [0.657, -0.170, 0.087, 3.106, -0.013, -1.645] # 2026-04-24 10:50
3x3 Grid (y-axis up):
x=0.499 x=0.567 x=0.634
y=-0.029 P7 P8 P9 top row
y=-0.100 P4 P5 P6 mid row
y=-0.171 P1* P2 P3 bottom row
* = original calibration point
Calibration corners:
BL: [0.499, -0.171, 0.194]
TL: [0.494, -0.029, 0.194]
TR: [0.629, -0.027, 0.194]
Grid span: dx=0.135, dy=0.142
Cell spacing: dx=0.068, dy=0.071
"""
import os
import sys
import time
import socket
import ast
import concurrent.futures
import elite_cs_sdk as cs
from elite_cs_sdk import EliteDriver, EliteDriverConfig, TrajectoryControlAction
# ─────────────────────────────────────────────
# Config
# ─────────────────────────────────────────────
ROBOT_IP = "192.168.1.77"
HOME_POSE = [0.488, -0.148, 0.493, 3.141, 0.0, -1.571]
PICK_POSE = [0.65666, -0.169701, 0.087426, 3.106247, -0.013438, -1.644996]
# 3x3 grid place points
# Row 0 (bottom, y=-0.171): P1(左下) P2(下中) P3(右下)
# Row 1 (mid, y=-0.100): P4(中左) P5(正中) P6(中右)
# Row 2 (top, y=-0.029): P7(左上) P8(上中) P9(右上)
PLACE_LIST = [
{"name": "PLACE_1", "pose": [0.425235, -0.170958, 0.088221, 3.106262, -0.013438, -1.644997]}, # P1(左下)
{"name": "PLACE_2", "pose": [0.496959, -0.170958, 0.088258, 3.106247, -0.013444, -1.645001]}, # P2(下中)
{"name": "PLACE_3", "pose": [0.568684, -0.188144, 0.08811, 3.106257, -0.013438, -1.644996]}, # P3(右下)
{"name": "PLACE_4", "pose": [0.425235, -0.102441, 0.088258, 3.106247, -0.013444, -1.645001]}, # P4(中左)
{"name": "PLACE_5", "pose": [0.496959, -0.102441, 0.088258, 3.106247, -0.013444, -1.645001]}, # P5(正中)
{"name": "PLACE_6", "pose": [0.568684, -0.102441, 0.088258, 3.106247, -0.013444, -1.645001]}, # P6(中右)
{"name": "PLACE_7", "pose": [0.444792, -0.033923, 0.088444, 3.106221, -0.013457, -1.645011]}, # P7(左上)
{"name": "PLACE_8", "pose": [0.496959, -0.033923, 0.088258, 3.106247, -0.013444, -1.645001]}, # P8(上中)
{"name": "PLACE_9", "pose": [0.568684, -0.033923, 0.088258, 3.106247, -0.013444, -1.645001]}, # P9(右上)
]
Z_UP_OFFSET = 0.20
LOOP_COUNT = 0
TRAJECTORY_TIME = 2.0
BLEND_RADIUS = 0.0
WAIT_GRIPPER = 1.5
# ─────────────────────────────────────────────
# Utils
# ─────────────────────────────────────────────
def safe_print(msg: str):
try:
print(msg)
except UnicodeEncodeError:
print(msg.encode("ascii", "ignore").decode("ascii"))
def send_40011(req_id: int, cmd: str, timeout: float = 5.0) -> str:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
try:
sock.connect((ROBOT_IP, 40011))
sock.sendall(f"req {req_id}{cmd}\n".encode())
return sock.recv(4096).decode("utf-8", errors="replace").strip()
finally:
sock.close()
def check_40011(cmd: str, resp: str):
if "failure" in resp.lower():
safe_print(f"[40011] WARN: '{cmd}' -> {resp}")
else:
safe_print(f"[40011] OK: {cmd}")
# ─────────────────────────────────────────────
# Gripper
# ─────────────────────────────────────────────
def gripper_init():
cmd = "tool_serial_config(True, 1000000, 2, 1, 8, True, 0)"
resp = send_40011(1, cmd)
check_40011(cmd, resp)
time.sleep(0.5)
def gripper_open():
send_40011(2, "tool_modbus_write_registers(0x41, 0, 800)")
time.sleep(0.1)
send_40011(3, "tool_modbus_write_registers(0x41, 3, 1)")
time.sleep(WAIT_GRIPPER)
def gripper_close():
send_40011(4, "tool_modbus_write_registers(0x41, 0, 300)")
time.sleep(0.1)
send_40011(5, "tool_modbus_write_registers(0x41, 3, 1)")
time.sleep(WAIT_GRIPPER)
# ─────────────────────────────────────────────
# Cartesian Trajectory Move
# ─────────────────────────────────────────────
def cartesian_move(driver, pose, traj_time=TRAJECTORY_TIME):
move_done = concurrent.futures.Future()
def on_done(result):
if not move_done.done():
move_done.set_result(result)
driver.setTrajectoryResultCallback(on_done)
driver.writeTrajectoryControlAction(TrajectoryControlAction.START, 1, 200)
driver.writeTrajectoryPoint(pose, time=traj_time, blend_radius=BLEND_RADIUS, cartesian=True)
while not move_done.done():
time.sleep(0.01)
driver.writeTrajectoryControlAction(TrajectoryControlAction.NOOP, 0, 200)
result = move_done.result()
driver.writeIdle(0)
safe_print(f"[Traj] Done: {result}")
# ─────────────────────────────────────────────
# Main
# ─────────────────────────────────────────────
def main():
safe_print("=" * 50)
safe_print("Elite CS Palletizing 3x3 (Cartesian)")
safe_print(f"IP: {ROBOT_IP} Points: {len(PLACE_LIST)} Loop: {'INF' if LOOP_COUNT == 0 else LOOP_COUNT}")
safe_print("=" * 50)
# Init
dash = cs.DashboardClientInterface()
dash.connect(ROBOT_IP, 29999)
dash.powerOn()
time.sleep(2.0)
dash.brakeRelease()
time.sleep(1.0)
dash.disconnect()
script_path = os.path.join(os.path.dirname(cs.__file__), "external_control.script")
config = EliteDriverConfig()
config.robot_ip = ROBOT_IP
config.script_file_path = script_path
config.headless_mode = True
driver = EliteDriver(config)
time.sleep(1.0)
while not driver.isRobotConnected():
time.sleep(0.01)
safe_print("[Driver] Connected")
gripper_init()
gripper_open()
PICK_Z_UP = [PICK_POSE[0], PICK_POSE[1], PICK_POSE[2] + Z_UP_OFFSET,
PICK_POSE[3], PICK_POSE[4], PICK_POSE[5]]
cartesian_move(driver, HOME_POSE, traj_time=2.0)
# Palletizing loop
cycle = 0
while True:
for item in PLACE_LIST:
cycle += 1
name = item["name"]
pose = item["pose"]
z_up = [pose[0], pose[1], pose[2] + Z_UP_OFFSET, pose[3], pose[4], pose[5]]
safe_print(f"\n[{cycle}] {name} {[f'{v:.3f}' for v in pose]}")
cartesian_move(driver, PICK_Z_UP)
cartesian_move(driver, PICK_POSE)
gripper_close()
cartesian_move(driver, PICK_Z_UP)
cartesian_move(driver, z_up)
cartesian_move(driver, pose)
gripper_open()
cartesian_move(driver, z_up)
if LOOP_COUNT > 0 and cycle >= LOOP_COUNT:
safe_print(f"\n[DONE] {cycle} cycles")
driver.stopControl()
return
driver.stopControl()
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
sys.exit(0)
except ConnectionRefusedError:
safe_print(f"[ERR] Cannot connect {ROBOT_IP}")
sys.exit(1)
except Exception as e:
safe_print(f"[ERR] {e}")
raise22 字节
27 字节