rabo-robocap 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
rabo_robocap/__init__.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""
|
|
2
|
+
rabo_robocap: ROS2 机器人能力封装
|
|
3
|
+
|
|
4
|
+
PyPI 发布的 loader shell — 核心代码从阿里云 OSS 自动拉取。
|
|
5
|
+
设置环境变量 RABO_DEV=1 可跳过 loader,直接从源码导入(开发/测试用)。
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from rabo_robocap import UR5
|
|
9
|
+
|
|
10
|
+
# 仿真模式
|
|
11
|
+
arm = UR5(robot_id='ur5_model', mode='sim')
|
|
12
|
+
|
|
13
|
+
# 真实硬件
|
|
14
|
+
arm = UR5(robot_id='ur5', mode='real')
|
|
15
|
+
|
|
16
|
+
arm.move_to(0.3, 0.2, 0.4)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
|
|
22
|
+
if os.environ.get("RABO_DEV"):
|
|
23
|
+
# ---- 开发模式:直接从源码导入 ----
|
|
24
|
+
from .exceptions import (
|
|
25
|
+
RobocapError, IKSolutionError, JointLimitError,
|
|
26
|
+
CommunicationError, TrajectoryError,
|
|
27
|
+
)
|
|
28
|
+
from .arms import UR5, UR10, GalaxeaA1X
|
|
29
|
+
from .mobile import AgilexScoutMini, GalaxeaR1LiteChassis
|
|
30
|
+
from .clients import MobileClient, ArmClient, TorsoClient, GripperClient
|
|
31
|
+
from .torso import GalaxeaR1LiteTorso
|
|
32
|
+
from .grippers import GalaxeaG1Gripper
|
|
33
|
+
from .base import ArmBase, MobileBase, TorsoBase, GripperBase
|
|
34
|
+
|
|
35
|
+
__version__ = "2.0.0-dev"
|
|
36
|
+
|
|
37
|
+
def check_update():
|
|
38
|
+
print("rabo_robocap: dev mode (RABO_DEV=1), hot-update disabled")
|
|
39
|
+
else:
|
|
40
|
+
# ---- 生产模式:从 OSS 缓存的 zip 加载 ----
|
|
41
|
+
from ._updater import ensure_updated, get_core_zip_path, install_redirector, check_update
|
|
42
|
+
|
|
43
|
+
# 1. 确保核心包是最新的(检查缓存/下载)
|
|
44
|
+
ensure_updated()
|
|
45
|
+
|
|
46
|
+
# 2. 将 zip 加入 sys.path(zipimport)
|
|
47
|
+
_zip_path = get_core_zip_path()
|
|
48
|
+
if _zip_path not in sys.path:
|
|
49
|
+
sys.path.insert(0, _zip_path)
|
|
50
|
+
|
|
51
|
+
# 3. 安装 import 重定向(支持 from rabo_robocap.arms import UR5)
|
|
52
|
+
install_redirector()
|
|
53
|
+
|
|
54
|
+
# 4. 从 _rabo_core 导入并重新导出
|
|
55
|
+
from _rabo_core import __version__ # noqa: E402
|
|
56
|
+
from _rabo_core.arms import UR5, UR10, GalaxeaA1X # noqa: E402
|
|
57
|
+
from _rabo_core.mobile import AgilexScoutMini, GalaxeaR1LiteChassis # noqa: E402
|
|
58
|
+
from _rabo_core.clients import MobileClient, ArmClient, TorsoClient, GripperClient # noqa: E402
|
|
59
|
+
from _rabo_core.torso import GalaxeaR1LiteTorso # noqa: E402
|
|
60
|
+
from _rabo_core.grippers import GalaxeaG1Gripper # noqa: E402
|
|
61
|
+
from _rabo_core.exceptions import ( # noqa: E402
|
|
62
|
+
RobocapError, IKSolutionError, JointLimitError,
|
|
63
|
+
CommunicationError, TrajectoryError,
|
|
64
|
+
)
|
|
65
|
+
from _rabo_core.base import ArmBase, MobileBase, TorsoBase, GripperBase # noqa: E402
|
|
66
|
+
|
|
67
|
+
__all__ = [
|
|
68
|
+
'__version__',
|
|
69
|
+
'UR5', 'UR10', 'GalaxeaA1X',
|
|
70
|
+
'AgilexScoutMini', 'GalaxeaR1LiteChassis',
|
|
71
|
+
'MobileClient', 'ArmClient', 'TorsoClient', 'GripperClient',
|
|
72
|
+
'GalaxeaR1LiteTorso',
|
|
73
|
+
'GalaxeaG1Gripper',
|
|
74
|
+
'ArmBase', 'MobileBase', 'TorsoBase', 'GripperBase',
|
|
75
|
+
'RobocapError', 'IKSolutionError', 'JointLimitError',
|
|
76
|
+
'CommunicationError', 'TrajectoryError',
|
|
77
|
+
]
|
rabo_robocap/_updater.py
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Hot-update loader: 从阿里云 OSS 拉取最新核心代码 zip,本地缓存后 zipimport。
|
|
3
|
+
|
|
4
|
+
流程:
|
|
5
|
+
1. import rabo_robocap 时调用 ensure_updated()
|
|
6
|
+
2. 检查本地 meta.json 的 last_check 时间戳,TTL 内跳过
|
|
7
|
+
3. TTL 过期 → GET version.json,比较版本
|
|
8
|
+
4. 远端更新 → 下载 core-cp3{minor}.zip
|
|
9
|
+
5. 网络异常 → 静默使用本地缓存
|
|
10
|
+
6. 无缓存 + 无网络 → 抛出明确错误
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import importlib
|
|
14
|
+
import importlib.abc
|
|
15
|
+
import importlib.machinery
|
|
16
|
+
import importlib.util
|
|
17
|
+
import json
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
import time
|
|
22
|
+
import types
|
|
23
|
+
import urllib.request
|
|
24
|
+
import urllib.error
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger("rabo_robocap._updater")
|
|
27
|
+
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# 配置
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
OSS_BASE_URL = (
|
|
32
|
+
"https://rabo-apt-repo.oss-cn-hangzhou.aliyuncs.com/rabo_robocap/"
|
|
33
|
+
)
|
|
34
|
+
CACHE_DIR = os.path.join(os.path.expanduser("~"), ".rabo_robocap")
|
|
35
|
+
_HTTP_TIMEOUT = 10 # 秒
|
|
36
|
+
|
|
37
|
+
# Python 版本标识
|
|
38
|
+
_PY_TAG = f"cp3{sys.version_info.minor}"
|
|
39
|
+
_ZIP_NAME = f"core-{_PY_TAG}.zip"
|
|
40
|
+
|
|
41
|
+
# 本地文件路径
|
|
42
|
+
_META_PATH = os.path.join(CACHE_DIR, "meta.json")
|
|
43
|
+
_ZIP_PATH = os.path.join(CACHE_DIR, _ZIP_NAME)
|
|
44
|
+
|
|
45
|
+
# 内部核心包名(zip 内的顶层目录)
|
|
46
|
+
_CORE_PACKAGE = "_rabo_core"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
# 内部工具
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
def _read_meta():
|
|
54
|
+
"""读取本地 meta.json,不存在或损坏返回空 dict。"""
|
|
55
|
+
try:
|
|
56
|
+
with open(_META_PATH, "r") as f:
|
|
57
|
+
return json.load(f)
|
|
58
|
+
except (FileNotFoundError, json.JSONDecodeError, OSError):
|
|
59
|
+
return {}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _write_meta(meta):
|
|
63
|
+
"""写入本地 meta.json。"""
|
|
64
|
+
os.makedirs(CACHE_DIR, exist_ok=True)
|
|
65
|
+
with open(_META_PATH, "w") as f:
|
|
66
|
+
json.dump(meta, f)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _fetch_json(url):
|
|
70
|
+
"""GET 请求并解析 JSON,失败返回 None。"""
|
|
71
|
+
try:
|
|
72
|
+
req = urllib.request.Request(url)
|
|
73
|
+
with urllib.request.urlopen(req, timeout=_HTTP_TIMEOUT) as resp:
|
|
74
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
75
|
+
except (urllib.error.URLError, OSError, json.JSONDecodeError, ValueError) as e:
|
|
76
|
+
logger.debug("fetch %s failed: %s", url, e)
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _download_file(url, dest):
|
|
81
|
+
"""下载文件到 dest,成功返回 True。"""
|
|
82
|
+
os.makedirs(os.path.dirname(dest), exist_ok=True)
|
|
83
|
+
tmp = dest + ".tmp"
|
|
84
|
+
try:
|
|
85
|
+
req = urllib.request.Request(url)
|
|
86
|
+
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
87
|
+
with open(tmp, "wb") as f:
|
|
88
|
+
while True:
|
|
89
|
+
chunk = resp.read(65536)
|
|
90
|
+
if not chunk:
|
|
91
|
+
break
|
|
92
|
+
f.write(chunk)
|
|
93
|
+
# 原子替换
|
|
94
|
+
if os.path.exists(dest):
|
|
95
|
+
os.remove(dest)
|
|
96
|
+
os.rename(tmp, dest)
|
|
97
|
+
return True
|
|
98
|
+
except (urllib.error.URLError, OSError) as e:
|
|
99
|
+
logger.debug("download %s failed: %s", url, e)
|
|
100
|
+
# 清理临时文件
|
|
101
|
+
try:
|
|
102
|
+
os.remove(tmp)
|
|
103
|
+
except OSError:
|
|
104
|
+
pass
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _version_tuple(version_str):
|
|
109
|
+
"""将 '1.2.3' 转成 (1, 2, 3) 用于比较。"""
|
|
110
|
+
try:
|
|
111
|
+
return tuple(int(x) for x in version_str.split("."))
|
|
112
|
+
except (ValueError, AttributeError):
|
|
113
|
+
return (0,)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
# 公开 API
|
|
118
|
+
# ---------------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
def ensure_updated():
|
|
121
|
+
"""检查并更新核心包。每次 import 时调用。
|
|
122
|
+
|
|
123
|
+
- 每次都检查远端版本,有更新就下载
|
|
124
|
+
- 网络异常 → 静默使用本地缓存
|
|
125
|
+
- 无缓存 + 无网络 → RuntimeError
|
|
126
|
+
"""
|
|
127
|
+
meta = _read_meta()
|
|
128
|
+
|
|
129
|
+
# 尝试获取远端版本信息
|
|
130
|
+
remote = _fetch_json(OSS_BASE_URL + "version.json")
|
|
131
|
+
|
|
132
|
+
if remote is not None:
|
|
133
|
+
remote_ver = remote.get("version", "0.0.0")
|
|
134
|
+
local_ver = meta.get("version", "0.0.0")
|
|
135
|
+
|
|
136
|
+
if remote_ver != local_ver or not os.path.isfile(_ZIP_PATH):
|
|
137
|
+
# 需要下载
|
|
138
|
+
zip_url = OSS_BASE_URL + _ZIP_NAME
|
|
139
|
+
logger.info("rabo_robocap: downloading %s (v%s)...", _ZIP_NAME, remote_ver)
|
|
140
|
+
if _download_file(zip_url, _ZIP_PATH):
|
|
141
|
+
meta["version"] = remote_ver
|
|
142
|
+
logger.info("rabo_robocap: updated to v%s", remote_ver)
|
|
143
|
+
_write_meta(meta)
|
|
144
|
+
else:
|
|
145
|
+
logger.warning("rabo_robocap: download failed, using cache if available")
|
|
146
|
+
else:
|
|
147
|
+
# 网络不可用
|
|
148
|
+
if os.path.isfile(_ZIP_PATH):
|
|
149
|
+
logger.debug("rabo_robocap: offline, using cached core")
|
|
150
|
+
else:
|
|
151
|
+
raise RuntimeError("rabo_robocap 初始化失败,请检查网络连接")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def check_update():
|
|
155
|
+
"""打印当前版本信息并检查远端是否有更新。
|
|
156
|
+
|
|
157
|
+
Usage:
|
|
158
|
+
import rabo_robocap
|
|
159
|
+
rabo_robocap.check_update()
|
|
160
|
+
"""
|
|
161
|
+
meta = _read_meta()
|
|
162
|
+
local_ver = meta.get("version", "unknown")
|
|
163
|
+
has_cache = os.path.isfile(_ZIP_PATH)
|
|
164
|
+
|
|
165
|
+
print(f"rabo_robocap hot-update status:")
|
|
166
|
+
print(f" local core version : {local_ver}")
|
|
167
|
+
print(f" cache file : {_ZIP_PATH} ({'exists' if has_cache else 'MISSING'})")
|
|
168
|
+
|
|
169
|
+
# 查询远端
|
|
170
|
+
print(f" checking remote : {OSS_BASE_URL}version.json ...")
|
|
171
|
+
remote = _fetch_json(OSS_BASE_URL + "version.json")
|
|
172
|
+
if remote is None:
|
|
173
|
+
print(f" remote version : unavailable (network error)")
|
|
174
|
+
else:
|
|
175
|
+
remote_ver = remote.get("version", "unknown")
|
|
176
|
+
print(f" remote version : {remote_ver}")
|
|
177
|
+
if remote_ver != local_ver:
|
|
178
|
+
print(f" status : VERSION CHANGED ({local_ver} → {remote_ver})")
|
|
179
|
+
print(f" restart Python to load the new version")
|
|
180
|
+
else:
|
|
181
|
+
print(f" status : up to date")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def get_core_zip_path():
|
|
185
|
+
"""返回核心 zip 路径,不存在则抛错。"""
|
|
186
|
+
if os.path.isfile(_ZIP_PATH):
|
|
187
|
+
return _ZIP_PATH
|
|
188
|
+
raise RuntimeError(
|
|
189
|
+
f"rabo_robocap: core zip not found at '{_ZIP_PATH}'. "
|
|
190
|
+
"Run ensure_updated() first."
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# ---------------------------------------------------------------------------
|
|
195
|
+
# Import 重定向器(使用 find_spec API,兼容 Python 3.4+)
|
|
196
|
+
# ---------------------------------------------------------------------------
|
|
197
|
+
|
|
198
|
+
class _CoreRedirector(importlib.abc.MetaPathFinder):
|
|
199
|
+
"""将 rabo_robocap.* 的子包导入重定向到 _rabo_core.*
|
|
200
|
+
|
|
201
|
+
例如:
|
|
202
|
+
from rabo_robocap.arms import UR5
|
|
203
|
+
→ 实际导入 _rabo_core.arms.UR5
|
|
204
|
+
|
|
205
|
+
仅拦截 rabo_robocap 的子模块,不拦截 rabo_robocap 本身。
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
_PREFIX = "rabo_robocap."
|
|
209
|
+
|
|
210
|
+
def find_spec(self, fullname, path, target=None):
|
|
211
|
+
if not fullname.startswith(self._PREFIX):
|
|
212
|
+
return None
|
|
213
|
+
|
|
214
|
+
# rabo_robocap.arms.ur5 → _rabo_core.arms.ur5
|
|
215
|
+
core_name = _CORE_PACKAGE + fullname[len("rabo_robocap"):]
|
|
216
|
+
|
|
217
|
+
return importlib.machinery.ModuleSpec(
|
|
218
|
+
fullname,
|
|
219
|
+
_CoreLoader(core_name),
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class _CoreLoader(importlib.abc.Loader):
|
|
224
|
+
"""将 rabo_robocap.xxx 加载为 _rabo_core.xxx 的代理。"""
|
|
225
|
+
|
|
226
|
+
def __init__(self, core_name):
|
|
227
|
+
self._core_name = core_name
|
|
228
|
+
|
|
229
|
+
def create_module(self, spec):
|
|
230
|
+
# 加载真实模块
|
|
231
|
+
real_mod = importlib.import_module(self._core_name)
|
|
232
|
+
# 注册到 sys.modules 供后续直接命中
|
|
233
|
+
sys.modules[spec.name] = real_mod
|
|
234
|
+
return real_mod
|
|
235
|
+
|
|
236
|
+
def exec_module(self, module):
|
|
237
|
+
# create_module 已完成所有工作,无需额外执行
|
|
238
|
+
pass
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
_redirector_installed = False
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def install_redirector():
|
|
245
|
+
"""在 sys.meta_path 中安装重定向器(幂等)。"""
|
|
246
|
+
global _redirector_installed
|
|
247
|
+
if _redirector_installed:
|
|
248
|
+
return
|
|
249
|
+
sys.meta_path.insert(0, _CoreRedirector())
|
|
250
|
+
_redirector_installed = True
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""rabo_robocap 异常定义"""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class RobocapError(Exception):
|
|
5
|
+
"""rabo_robocap 基础异常类"""
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class IKSolutionError(RobocapError):
|
|
10
|
+
"""逆运动学无解异常"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, target_pose=None, message=None):
|
|
13
|
+
self.target_pose = target_pose
|
|
14
|
+
if message is None:
|
|
15
|
+
message = "无法找到逆运动学解"
|
|
16
|
+
if target_pose is not None:
|
|
17
|
+
message += f": target={target_pose}"
|
|
18
|
+
super().__init__(message)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class JointLimitError(RobocapError):
|
|
22
|
+
"""关节超限异常"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, joint_index=None, value=None, limits=None, message=None):
|
|
25
|
+
self.joint_index = joint_index
|
|
26
|
+
self.value = value
|
|
27
|
+
self.limits = limits
|
|
28
|
+
if message is None:
|
|
29
|
+
message = "关节角度超出限位"
|
|
30
|
+
if joint_index is not None:
|
|
31
|
+
message += f": joint[{joint_index}]={value}, limits={limits}"
|
|
32
|
+
super().__init__(message)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CommunicationError(RobocapError):
|
|
36
|
+
"""通信超时异常"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, topic=None, timeout=None, message=None):
|
|
39
|
+
self.topic = topic
|
|
40
|
+
self.timeout = timeout
|
|
41
|
+
if message is None:
|
|
42
|
+
message = "通信超时"
|
|
43
|
+
if topic is not None:
|
|
44
|
+
message += f": topic={topic}, timeout={timeout}s"
|
|
45
|
+
super().__init__(message)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class TrajectoryError(RobocapError):
|
|
49
|
+
"""轨迹规划/执行异常"""
|
|
50
|
+
|
|
51
|
+
def __init__(self, reason=None, message=None):
|
|
52
|
+
self.reason = reason
|
|
53
|
+
if message is None:
|
|
54
|
+
message = "轨迹执行失败"
|
|
55
|
+
if reason is not None:
|
|
56
|
+
message += f": {reason}"
|
|
57
|
+
super().__init__(message)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rabo_robocap
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: rabo_robocap: ROS2 机器人能力封装
|
|
5
|
+
Requires-Python: >=3.8
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: numpy
|
|
8
|
+
Provides-Extra: test
|
|
9
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
10
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
11
|
+
Provides-Extra: build
|
|
12
|
+
Requires-Dist: oss2; extra == "build"
|
|
13
|
+
|
|
14
|
+
# rabo_robocap
|
|
15
|
+
|
|
16
|
+
ROS2 机器人能力封装 SDK,为 Gazebo 仿真中的机器人提供高级控制接口。
|
|
17
|
+
|
|
18
|
+
支持热更新:`pip install` 一次后,每次 `import` 自动获取最新版本。
|
|
19
|
+
|
|
20
|
+
## 安装
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# 1. 安装 Python 包(仅需一次)
|
|
24
|
+
pip install rabo_robocap
|
|
25
|
+
|
|
26
|
+
# 2. 构建 ROS2 消息包(需要 ROS2 环境)
|
|
27
|
+
cd ~/ros2_ws/src/rabo-lib
|
|
28
|
+
colcon build --paths rabo_robocap_msgs
|
|
29
|
+
source install/setup.bash
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
详细构建说明请参考 [构建指南](docs/build.md)。
|
|
33
|
+
|
|
34
|
+
## 使用
|
|
35
|
+
|
|
36
|
+
### 移动底盘
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from rabo_robocap import AgilexScoutMini
|
|
40
|
+
|
|
41
|
+
# 仿真模式(自动从 API 获取配置,rclpy 自动初始化)
|
|
42
|
+
base = AgilexScoutMini(robot_id='scout_model', mode='sim')
|
|
43
|
+
|
|
44
|
+
# 或 真实硬件模式
|
|
45
|
+
# base = AgilexScoutMini(robot_id='scout', mode='real')
|
|
46
|
+
|
|
47
|
+
base.set_velocity(linear_x=0.5, angular_z=0.0)
|
|
48
|
+
base.move_distance(1.0)
|
|
49
|
+
x, y, theta = base.get_odometry()
|
|
50
|
+
print(f"Position: ({x:.2f}, {y:.2f}), Heading: {theta:.2f}")
|
|
51
|
+
|
|
52
|
+
base.shutdown()
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 机械臂
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
import numpy as np
|
|
59
|
+
from rabo_robocap import UR5
|
|
60
|
+
|
|
61
|
+
# 仿真模式
|
|
62
|
+
arm = UR5(robot_id='ur5_model', mode='sim')
|
|
63
|
+
|
|
64
|
+
# 或 真实硬件
|
|
65
|
+
# arm = UR5(robot_id='ur5', mode='real')
|
|
66
|
+
|
|
67
|
+
# 移动到 ready 位置
|
|
68
|
+
arm.move_joints([0, -np.pi/2, np.pi/2, -np.pi/2, -np.pi/2, 0])
|
|
69
|
+
|
|
70
|
+
# 移动到目标位置
|
|
71
|
+
arm.move_to(0.3, 0.2, 0.4)
|
|
72
|
+
|
|
73
|
+
# 获取当前位姿
|
|
74
|
+
pos, ori = arm.get_pose()
|
|
75
|
+
print(f"Position: {pos}")
|
|
76
|
+
|
|
77
|
+
arm.shutdown()
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 版本管理
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
import rabo_robocap
|
|
84
|
+
|
|
85
|
+
# 查看当前版本
|
|
86
|
+
print(rabo_robocap.__version__)
|
|
87
|
+
|
|
88
|
+
# 查看更新状态
|
|
89
|
+
rabo_robocap.check_update()
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**注意**:
|
|
93
|
+
- rclpy 自动初始化,无需手动调用 `rclpy.init()`
|
|
94
|
+
- 节点内部自动管理 ROS2 回调,**不要**将节点添加到外部 executor
|
|
95
|
+
|
|
96
|
+
## 文档
|
|
97
|
+
|
|
98
|
+
- [构建指南](docs/build.md)
|
|
99
|
+
- [整体架构](docs/architecture.md)
|
|
100
|
+
- [AgilexScoutMini 移动底盘](docs/robots/mobile_agilex_scout_mini.md)
|
|
101
|
+
- [GalaxeaR1LiteChassis 移动底盘](docs/robots/mobile_galaxea_r1_lite_chassis.md)
|
|
102
|
+
- [UR 系列机械臂](docs/robots/arm_ur_series.md)
|
|
103
|
+
- [设计规则](CLAUDE.md)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
rabo_robocap/__init__.py,sha256=I1pqcyTQ_mh5P9oxpzI3xMpFajsoDZjwsZQ_Er8ScIM,2769
|
|
2
|
+
rabo_robocap/_updater.py,sha256=z3tS-z306jeuFvL9ftsPNhq6QRW3TFoV0G0aZ0DKrtQ,7987
|
|
3
|
+
rabo_robocap/exceptions.py,sha256=nLk906wmoVyuZpZuE0iYqNY8FHq3qAxnZCQbq8UPIzQ,1694
|
|
4
|
+
rabo_robocap-2.0.0.dist-info/METADATA,sha256=ojImKFkj6xOtHw9aB-ZGg0niCrGu0m56e5CLNf7HIbM,2404
|
|
5
|
+
rabo_robocap-2.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
6
|
+
rabo_robocap-2.0.0.dist-info/top_level.txt,sha256=XsAkBJVF6ZfyM071uWwDZbNcns-MJ7kPRoEzkLXzltI,13
|
|
7
|
+
rabo_robocap-2.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rabo_robocap
|