توثيق تطوير SDK لهيكل Tbot ثلاثي الأبعاد

يعتمد بروتوكول rosbridge WebSocket للتحكم في الهيكل بلغات متعددة دون الحاجة إلى بيئة ROS. توثّق هذه الصفحة بالكامل حقول الطلب والاستجابة لكل Topic / Service (النوع + الوصف).

الاتصال:ws://192.168.1.151:9090
غلاف الاستجابة العام:بعد كل استدعاء Service يعيد rosbridge رسالة service_response. والـ JSON في عمود «الاستجابة» بالجدول التالي هو محتوى values.

1. نظرة عامة على البروتوكول

الاتجاهالعددالاسم
اشتراك Topic (الهيكل ← التطبيق)5/fast_lio_localization、/aft_pgo_path、/map_list_kitty、/ebot_goal_status_local_planner、/ebot_work_state
استدعاء Service (التطبيق ← الهيكل)9/start_mapping_kitty、/save_map_kitty、/select_map_and_start_kitty、/delete_map_kitty、/docking_kitty、/navigate_to_pose(تنقل + إلغاء)、/add_goal_kitty、/delete_goal_kitty

2. اشتراك Topic (الهيكل ← التطبيق)

اشتراك. الرسالة المستقبلة في حقل msg.

3. جدول ملخص Service

Serviceنوع الخدمةالحقول الرئيسية
/start_mapping_kittystd_srvs/Triggerطلب فارغ ← success,message
/save_map_kittykitty_runtime_manager/SaveMapfilepath → success,message
/select_map_and_start_kittykitty_runtime_manager/SaveMapfilepath → success,message
/delete_map_kittykitty_runtime_manager/DeleteMapmap_name → success,message
/docking_kittystd_srvs/Triggerطلب فارغ ← success,message
/navigate_to_posenav_msgs/GetPlangoal.pose.position.x/y/z → plan.poses[]
/add_goal_kittykitty_runtime_manager/AddGoalmap_name,goal_name,x,y,theta → success,message
/delete_goal_kittykitty_runtime_manager/DeleteGoalmap_name,goal_name → success,message

2.1 تحديد موقع الروبوت nav_msgs/Odometry

الهيكل يرسل الوضعية الحالية دورياً.

msg المستلمة:
{
  "pose": { "pose": {
    "position": {"x": 1.23, "y": 4.56, "z": 0.0},
    "orientation": {"x": 0, "y": 0, "z": 0.5, "w": 0.866}
  }}
}
الحقلالنوعالوصف
pose.pose.position.xfloat64إحداثي x للروبوت (متر)
pose.pose.position.yfloat64إحداثي y للروبوت (متر)
pose.pose.position.zfloat64إحداثي z للروبوت (متر، ثابت 0 للهيكل)
pose.pose.orientation.x/y/z/wfloat64اتجاه رباعي؛ الواجهة تستخدم yaw = atan2(2*(w*z+x*y), 1-2*(z*z+y*y)) بالراديان

2.2 المسار العام nav_msgs/Path

بعد بدء الملاحة يُرسل مرة كل 5 ثوانٍ، 5 مرات (حوالي 30 ثانية).

msg المستلمة:
{ "poses": [
  {"pose":{"position":{"x":0,"y":0,"z":0}}},
  {"pose":{"position":{"x":1,"y":2,"z":0}}}
]}
الحقلالنوعالوصف
posesarray[PoseStamped]مصفوفة نقاط المسار
poses[].pose.position.xfloat64إحداثي x لنقطة المسار (متر)
poses[].pose.position.yfloat64إحداثي y لنقطة المسار (متر)
poses[].pose.position.zfloat64إحداثي z لنقطة المسار (ثابت 0 للهيكل)

2.3 قائمة الخرائط kitty_runtime_manager/MapList

بعد الاشتراك يُرجع كل الخرائط ونقاط الهدف المحفوظة.

msg المستلمة:
{ "maps": [
  {"map_name":"Lobby","map_path":"/maps/floor1",
   "goals":[
     {"name":"Reception","x":1.0,"y":2.0,"theta":0.5},
     {"name":"Elevator","x":3.0,"y":4.0,"theta":1.2}
   ]}
]}
الحقلالنوعالوصف
mapsarray[Map]مصفوفة الخرائط
maps[].map_namestringاسم عرض الخريطة
maps[].map_pathstringمسار ملف الخريطة (داخلي)
maps[].goalsarray[Goal]نقاط الهدف المحفوظة تحت هذه الخريطة
maps[].goals[].namestringاسم نقطة الهدف
maps[].goals[].xfloat64x نقطة الهدف (متر)
maps[].goals[].yfloat64y نقطة الهدف (متر)
maps[].goals[].thetafloat64اتجاه نقطة الهدف (راديان)

2.4 حالة الملاحة std_msgs/Float64MultiArray

Topic: /ebot_goal_status_local_planner.

msg المستلمة:{"data": [1]}
الحقلالنوعالوصف
data[0]float641 = بلغ نقطة الهدف؛ 0 = لم يبلغها. وفي وضع Docking لا يُرسل 1 إلا عند بدء الشحن فعلاً

2.5 البطارية وحالة الشحن std_msgs/Float64MultiArray

Topic: /ebot_work_state.

msg المستلمة:{"data": [2, 75.5]}
الحقلالنوعالوصف
data[0]float64حالة الشحن: 1=شحن 2=غير شحن
data[1]float64نسبة البطارية (0~100)

3.1 بدء بناء الخريطة std_srvs/Trigger

Service:/start_mapping_kitty

الطلب:
{}
(طلب فارغ)
قيم الاستجابة:
{ "success": true, "message": "Mapping started" }
الحقلالنوعالاتجاهالوصف
successboolالاستجابةنجاح العملية
messagestringالاستجابةرسالة النتيجة (السبب عند الفشل)

3.2 حفظ الخريطة kitty_runtime_manager/SaveMap

Service:/save_map_kitty

الطلب:
{ "filepath": "map_name" }
قيم الاستجابة:
{ "success": true, "message": "Map saved" }
الحقلالنوعالاتجاهالوصف
filepathstringالطلبmap_name (بدون مسار)
successboolالاستجابةنجاح العملية
messagestringالاستجابةرسالة النتيجة

3.3 اختيار خريطة وبدء الملاحة kitty_runtime_manager/SaveMap

Service:/select_map_and_start_kitty

الطلب:
{ "filepath": "map_name" }
قيم الاستجابة:
{ "success": true, "message": "Map selected and navigation started" }
الحقلالنوعالاتجاهالوصف
filepathstringالطلبmap_name (بدون مسار)
successboolالاستجابةنجاح العملية
messagestringالاستجابةرسالة النتيجة

3.4 حذف الخريطة kitty_runtime_manager/DeleteMap

Service:/delete_map_kitty

الطلب:
{ "map_name": "map_name" }
قيم الاستجابة:
{ "success": true, "message": "Deleted successfully" }
الحقلالنوعالاتجاهالوصف
map_namestringالطلبmap_name المراد حذفه
successboolالاستجابةنجاح العملية
messagestringالاستجابةرسالة النتيجة

3.5 العودة لمحطة الشحن std_srvs/Trigger

Service:/docking_kitty

الطلب:
{}
قيم الاستجابة:
{ "success": true, "message": "Docking started" }
الحقلالنوعالاتجاهالوصف
successboolالاستجابةنجاح العملية (يعني بدء عملية Docking فقط، لا يعني اكتمال الشحن)
messagestringالاستجابةرسالة النتيجة

3.6 الملاحة لنقطة الهدف nav_msgs/GetPlan

Service:/navigate_to_pose

الطلب:
{
  "goal": { "pose": { "position": { "x": 1.0, "y": 2.0, "z": 0.0 } } }
}
قيم الاستجابة:
{ "plan": { "poses": [
  {"pose":{"position":{"x":0,"y":0,"z":0}}},
  {"pose":{"position":{"x":1,"y":2,"z":0}}}
]}}
الحقلالنوعالاتجاهالوصف
goal.pose.position.xfloat64الطلبx نقطة الهدف (متر)
goal.pose.position.yfloat64الطلبy نقطة الهدف (متر)
goal.pose.position.zfloat64الطلبz نقطة الهدف (ثابت 0 للهيكل)
plan.posesarray[PoseStamped]الاستجابةمصفوفة نقاط المسار المخطط (لرسم المسار بالواجهة)
ملاحظة:للتحقق من الوصول الفعلي لا تنظر لهذه الاستجابة، بل اشترك ebot_goal_status واستقبل data[0]==1.

3.7 إلغاء الملاحة nav_msgs/GetPlan

Service:/navigate_to_pose((مع الملاحة في نفس الخدمة، تمييز بإحداثيات خاصة))

الطلب:
{
  "goal": { "pose": { "position": { "x": 999999, "y": 888888, "z": 0 } } }
}
قيم الاستجابة:
{ "plan": { "poses": [] } }
الحقلالنوعالاتجاهالوصف
goal.pose.position.xfloat64الطلبثابت 999999 (علامة الإلغاء)
goal.pose.position.yfloat64الطلبثابت 888888 (علامة الإلغاء)
goal.pose.position.zfloat64الطلبثابت 0
plan.posesarrayالاستجابةمسار فارغ أو مقطوع

3.8 إضافة نقطة هدف kitty_runtime_manager/AddGoal

Service:/add_goal_kitty

الطلب:
{
  "map_name": "Lobby",
  "goal_name": "Reception",
  "x": 1.0, "y": 2.0, "theta": 0.5
}
قيم الاستجابة:
{ "success": true, "message": "Added successfully" }
الحقلالنوعالاتجاهالوصف
map_namestringالطلبmap_name
goal_namestringالطلباسم نقطة الهدف
xfloat64الطلبx نقطة الهدف (متر)
yfloat64الطلبy نقطة الهدف (متر)
thetafloat64الطلبزاوية الاتجاه (راديان)
successboolالاستجابةنجاح العملية
messagestringالاستجابةرسالة النتيجة

3.9 حذف نقطة الهدف kitty_runtime_manager/DeleteGoal

Service:/delete_goal_kitty

الطلب:
{ "map_name": "Lobby", "goal_name": "Reception" }
قيم الاستجابة:
{ "success": true, "message": "Deleted successfully" }
الحقلالنوعالاتجاهالوصف
map_namestringالطلبmap_name
goal_namestringالطلباسم نقطة الهدف
successboolالاستجابةنجاح العملية
messagestringالاستجابةرسالة النتيجة

4. أمثلة تطوير متعددة اللغات

تعرض كل لغة مثالاً سريعاً افتراضياً (اتصال + اشتراك مستوى البطارية + العودة إلى الإرساء)، وبالنقر على «عرض الكود الكامل» يُفتح العرض الكامل لكل 5 Topics + 9 Services.

4.1 Python(roslibpy)

التبعيات:pip install roslibpy

import roslibpy, time
client = roslibpy.Ros(host='192.168.1.151', port=9090)
client.run()

# Subscribe to battery state
roslibpy.Topic(client,'/ebot_work_state','std_msgs/Float64MultiArray').subscribe(
    lambda m: print(f"Battery {m['data'][1]}% charging={m['data'][0]==1}"))
# Dock to charger
roslibpy.Service(client,'/docking_kitty','std_srvs/Trigger').call(roslibpy.ServiceRequest(),
    callback=lambda r: print("Docking:", r['message']))
try:
    while True: time.sleep(1)
except KeyboardInterrupt: client.terminate()
import roslibpy, time, math
client = roslibpy.Ros(host='192.168.1.151', port=9090)
client.run()

# ===== Subscribe to all 5 Topics =====
# 1) Localization
def on_odom(m):
    p = m['pose']['pose']['position']; o = m['pose']['pose']['orientation']
    yaw = math.atan2(2*(o['w']*o['z']+o['x']*o['y']), 1-2*(o['z']**2+o['y']**2))
    print(f"[Pose] x={p['x']:.2f} y={p['y']:.2f} yaw={math.degrees(yaw):.1f}°")
roslibpy.Topic(client,'/fast_lio_localization','nav_msgs/Odometry').subscribe(on_odom)
# 2) Global path
roslibpy.Topic(client,'/aft_pgo_path','nav_msgs/Path').subscribe(
    lambda m: print(f"[Path] {len(m['poses'])}  points"))
# 3) Map list
roslibpy.Topic(client,'/map_list_kitty','kitty_runtime_manager/MapList').subscribe(
    lambda m: [print(f"[Map] {mp['map_name']}  goals:{[g['name'] for g in mp['goals']]}") for mp in m['maps']])
# 4) Navigation status
roslibpy.Topic(client,'/ebot_goal_status_local_planner','std_msgs/Float64MultiArray').subscribe(
    lambda m: m['data'][0]==1 and print("✅ Arrived"))
# 5) Battery
roslibpy.Topic(client,'/ebot_work_state','std_msgs/Float64MultiArray').subscribe(
    lambda m: print(f"[Battery] {m['data'][1]:.0f}% {'Charging' if m['data'][0]==1 else 'Not charging'}"))

# ===== Call all 9 Services =====
def call(svc, args, srv):
    r = roslibpy.Service(client, svc, srv).call(roslibpy.ServiceRequest(args))
    print(f"[SVC] {svc} → {dict(r)}")
time.sleep(1)
call('/start_mapping_kitty', {}, 'std_srvs/Trigger')
call('/save_map_kitty', {'filepath':'test_map'}, 'kitty_runtime_manager/SaveMap')
call('/select_map_and_start_kitty', {'filepath':'test_map'}, 'kitty_runtime_manager/SaveMap')
call('/navigate_to_pose', {'goal':{'pose':{'position':{'x':1.0,'y':2.0,'z':0.0}}}}, 'nav_msgs/GetPlan')
call('/navigate_to_pose', {'goal':{'pose':{'position':{'x':999999,'y':888888,'z':0}}}}, 'nav_msgs/GetPlan')
call('/add_goal_kitty', {'map_name':'test_map','goal_name':'Reception','x':1.0,'y':2.0,'theta':0.5}, 'kitty_runtime_manager/AddGoal')
call('/delete_goal_kitty', {'map_name':'test_map','goal_name':'Reception'}, 'kitty_runtime_manager/DeleteGoal')
call('/docking_kitty', {}, 'std_srvs/Trigger')
call('/delete_map_kitty', {'map_name':'test_map'}, 'kitty_runtime_manager/DeleteMap')

try:
    while True: time.sleep(1)
except KeyboardInterrupt: client.terminate()

4.2 JavaScript / HTML

بلا تبعيات، الصقه في وسماً