feat: 实现api调用
This commit is contained in:
parent
afe64406e5
commit
b65b94643c
148
http_server.py
148
http_server.py
@ -12,6 +12,7 @@ from flask import jsonify, request
|
|||||||
import gazebo_ctrl
|
import gazebo_ctrl
|
||||||
from heartbeat import HeartbeatServer
|
from heartbeat import HeartbeatServer
|
||||||
from model_mgr.manager import ModelManager
|
from model_mgr.manager import ModelManager
|
||||||
|
from model_mgr.model_types import Model
|
||||||
from scene_mgr.manager import SceneManager
|
from scene_mgr.manager import SceneManager
|
||||||
|
|
||||||
|
|
||||||
@ -86,8 +87,12 @@ class GazeboSimHttpServer(HttpRPCServer):
|
|||||||
# 模块与数据
|
# 模块与数据
|
||||||
self.rlock = threading.RLock()
|
self.rlock = threading.RLock()
|
||||||
self.scene_mgr = SceneManager()
|
self.scene_mgr = SceneManager()
|
||||||
self.model_mgr = ModelManager()
|
self.model_mgr = None
|
||||||
self.heartbeat_server = HeartbeatServer()
|
|
||||||
|
def llost():
|
||||||
|
self.shut_scene()
|
||||||
|
self.heartbeat_server = HeartbeatServer(close_func=llost)
|
||||||
|
self.heartbeat_server.start()
|
||||||
# 启动roscore
|
# 启动roscore
|
||||||
self.roscore_proc = subprocess.Popen(
|
self.roscore_proc = subprocess.Popen(
|
||||||
['roscore'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
['roscore'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
@ -95,47 +100,160 @@ class GazeboSimHttpServer(HttpRPCServer):
|
|||||||
rospy.init_node('gazebo_world_manager', anonymous=True)
|
rospy.init_node('gazebo_world_manager', anonymous=True)
|
||||||
|
|
||||||
# 添加接口
|
# 添加接口
|
||||||
self._app.add_url_rule('/api/v1/scenes', view_func=self.query_scenes, methods=['GET'])
|
self._app.add_url_rule(
|
||||||
self._app.add_url_rule('/api/v1/scene/load', view_func=self.load_scene, methods=['GET'])
|
'/api/v1/scenes', view_func=self.query_scenes, methods=['GET'])
|
||||||
self._app.add_url_rule('/api/v1/scene/objects', view_func=self.get_scene_objects, methods=['GET'])
|
self._app.add_url_rule('/api/v1/scene/load',
|
||||||
self._app.add_url_rule('/api/v1/scene/object', view_func=self.modify_scene_object, methods=['POST'])
|
view_func=self.start_scene, methods=['GET'])
|
||||||
self._app.add_url_rule('/api/v1/scene/object', view_func=self.add_scene_object, methods=['PUT'])
|
self._app.add_url_rule('/api/v1/scene/objects',
|
||||||
self._app.add_url_rule('/api/v1/scene/object', view_func=self.remove_scene_object, methods=['DELETE'])
|
view_func=self.get_all_models, methods=['GET'])
|
||||||
|
self._app.add_url_rule(
|
||||||
|
'/api/v1/scene/object', view_func=self.modify_model, methods=['POST'])
|
||||||
|
self._app.add_url_rule('/api/v1/scene/object',
|
||||||
|
view_func=self.add_model, methods=['PUT'])
|
||||||
|
self._app.add_url_rule(
|
||||||
|
'/api/v1/scene/object', view_func=self.remove_model, methods=['DELETE'])
|
||||||
|
|
||||||
|
print('Sever init done.')
|
||||||
|
|
||||||
def query_scenes(self):
|
def query_scenes(self):
|
||||||
# 查询场景
|
# 查询场景
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
pass
|
ret = {'code': 200, 'message': ''}
|
||||||
|
try:
|
||||||
|
scs = self.scene_mgr.get_scenes()
|
||||||
|
data = [sc.to_dict for sc in scs]
|
||||||
|
ret['data'] = data
|
||||||
|
except Exception as e:
|
||||||
|
ret['code'] = 400
|
||||||
|
ret['message'] = str(e)
|
||||||
|
print('Server query scenes done.')
|
||||||
|
return jsonify(ret)
|
||||||
|
|
||||||
def start_scene(self):
|
def start_scene(self):
|
||||||
# 启动场景
|
# 启动场景
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
pass
|
ret = {'code': 200, 'message': ''}
|
||||||
|
try:
|
||||||
|
# 检查参数
|
||||||
|
id = request.args.get('id', type=int, default=None)
|
||||||
|
if not id:
|
||||||
|
raise ValueError('Scene ID is required')
|
||||||
|
# 关闭现有场景
|
||||||
|
if self.scene_mgr.running_scene:
|
||||||
|
self.shut_scene()
|
||||||
|
time.sleep(25)
|
||||||
|
# 启动场景
|
||||||
|
self.scene_mgr.start_scene(id)
|
||||||
|
self.model_mgr = ModelManager()
|
||||||
|
time.sleep(30)
|
||||||
|
self.model_mgr.load_models(
|
||||||
|
self.scene_mgr.scene_id_dict[id].preload_models)
|
||||||
|
except Exception as e:
|
||||||
|
ret['code'] = 400
|
||||||
|
ret['message'] = str(e)
|
||||||
|
print('Server start scene done.')
|
||||||
|
return jsonify(ret)
|
||||||
|
|
||||||
def shut_scene(self):
|
def shut_scene(self):
|
||||||
# 关闭场景,仅供start_scene、心跳线程使用
|
# 关闭场景,仅供start_scene、心跳线程使用
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
pass
|
try:
|
||||||
|
if not self.scene_mgr.running_scene:
|
||||||
|
raise RuntimeError('No scene is running')
|
||||||
|
|
||||||
|
def shutt():
|
||||||
|
self.scene_mgr.shut_scene_truly()
|
||||||
|
|
||||||
|
threading.Thread(target=shutt, daemon=True).start()
|
||||||
|
self.model_mgr = None
|
||||||
|
except Exception as e:
|
||||||
|
print(str(e))
|
||||||
|
print('Server shut scene done.')
|
||||||
|
|
||||||
def get_all_models(self):
|
def get_all_models(self):
|
||||||
# 获取所有模型
|
# 获取所有模型
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
pass
|
ret = {'code': 200, 'message': ''}
|
||||||
|
try:
|
||||||
|
mods = self.model_mgr.get_all_models()
|
||||||
|
cnt = len(mods)
|
||||||
|
data = {}
|
||||||
|
data['total_count'] = cnt
|
||||||
|
data['list'] = [m.to_dict() for m in mods]
|
||||||
|
except Exception as e:
|
||||||
|
ret['code'] = 400
|
||||||
|
ret['message'] = str(e)
|
||||||
|
print('Server get all models done.')
|
||||||
|
return jsonify(ret)
|
||||||
|
|
||||||
def modify_model(self):
|
def modify_model(self):
|
||||||
# 修改模型
|
# 修改模型
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
pass
|
ret = {'code': 200, 'message': ''}
|
||||||
|
try:
|
||||||
|
# 解析参数
|
||||||
|
info = request.get_json()
|
||||||
|
scene_id = info.get('scene_id', type=int, default=None)
|
||||||
|
if not scene_id or scene_id != self.scene_mgr.running_scene:
|
||||||
|
raise ValueError(
|
||||||
|
f'Scene {scene_id} does not match the running scene {self.scene_mgr.running_scene}')
|
||||||
|
object_id = info.get('object_id', type=int, default=None)
|
||||||
|
if not object_id:
|
||||||
|
raise ValueError('Object ID is required')
|
||||||
|
# 制作Model
|
||||||
|
info['id'] = object_id
|
||||||
|
model = self.model_mgr.get_model(object_id)
|
||||||
|
model.overwrite_from_dict(info)
|
||||||
|
# 添加模型
|
||||||
|
self.model_mgr.modify_model(model)
|
||||||
|
except Exception as e:
|
||||||
|
ret['code'] = 400
|
||||||
|
ret['message'] = str(e)
|
||||||
|
print('Server modify model done.')
|
||||||
|
return jsonify(ret)
|
||||||
|
|
||||||
def add_model(self):
|
def add_model(self):
|
||||||
# 添加模型
|
# 添加模型
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
pass
|
ret = {'code': 200, 'message': ''}
|
||||||
|
try:
|
||||||
|
# 解析参数
|
||||||
|
info = request.get_json()
|
||||||
|
scene_id = info.get('scene_id', type=int, default=None)
|
||||||
|
if not scene_id or scene_id != self.scene_mgr.running_scene:
|
||||||
|
raise ValueError(
|
||||||
|
f'Scene {scene_id} does not match the running scene {self.scene_mgr.running_scene}')
|
||||||
|
# 制作Model,和modify的区别在于没有id
|
||||||
|
info['id'] = -1
|
||||||
|
model = Model.from_dict(info)
|
||||||
|
# 添加模型
|
||||||
|
self.model_mgr.add_model(model)
|
||||||
|
except Exception as e:
|
||||||
|
ret['code'] = 400
|
||||||
|
ret['message'] = str(e)
|
||||||
|
print('Server add model done.')
|
||||||
|
return jsonify(ret)
|
||||||
|
|
||||||
def remove_model(self):
|
def remove_model(self):
|
||||||
# 删除模型
|
# 删除模型
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
pass
|
ret = {'code': 200, 'message': ''}
|
||||||
|
try:
|
||||||
|
# 解析参数
|
||||||
|
info = request.get_json()
|
||||||
|
scene_id = info.get('scene_id', type=int, default=None)
|
||||||
|
if not scene_id or scene_id != self.scene_mgr.running_scene:
|
||||||
|
raise ValueError(
|
||||||
|
f'Scene {scene_id} does not match the running scene {self.scene_mgr.running_scene}')
|
||||||
|
object_id = info.get('object_id', type=int, default=None)
|
||||||
|
# 删除模型
|
||||||
|
self.model_mgr.remove_model(object_id)
|
||||||
|
except Exception as e:
|
||||||
|
ret['code'] = 400
|
||||||
|
ret['message'] = str(e)
|
||||||
|
print('Server remove model done.')
|
||||||
|
return jsonify(ret)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
server = GazeboSimHttpServer()
|
server = GazeboSimHttpServer()
|
||||||
|
|||||||
@ -13,6 +13,11 @@ class Position:
|
|||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {"x": self.x, "y": self.y, "z": self.z}
|
return {"x": self.x, "y": self.y, "z": self.z}
|
||||||
|
|
||||||
|
def overwrite_from_dict(self, data):
|
||||||
|
self.x = data.get("x", self.x)
|
||||||
|
self.y = data.get("y", self.y)
|
||||||
|
self.z = data.get("z", self.z)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, data):
|
def from_dict(cls, data):
|
||||||
@ -32,6 +37,11 @@ class Orientation:
|
|||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {"roll": self.roll, "pitch": self.pitch, "yaw": self.yaw}
|
return {"roll": self.roll, "pitch": self.pitch, "yaw": self.yaw}
|
||||||
|
|
||||||
|
def overwrite_from_dict(self, data):
|
||||||
|
self.roll = data.get("roll", self.roll)
|
||||||
|
self.pitch = data.get("pitch", self.pitch)
|
||||||
|
self.yaw = data.get("yaw", self.yaw)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, data):
|
def from_dict(cls, data):
|
||||||
return cls(
|
return cls(
|
||||||
@ -52,6 +62,10 @@ class Pose:
|
|||||||
position: Position = dataclasses.field(default_factory=Position)
|
position: Position = dataclasses.field(default_factory=Position)
|
||||||
orientation: Orientation = dataclasses.field(default_factory=Orientation)
|
orientation: Orientation = dataclasses.field(default_factory=Orientation)
|
||||||
|
|
||||||
|
def overwrite_from_dict(self, data):
|
||||||
|
self.position.overwrite_from_dict(data.get("position", {}))
|
||||||
|
self.orientation.overwrite_from_dict(data.get("orientation", {}))
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {
|
return {
|
||||||
"position": self.position.to_dict(),
|
"position": self.position.to_dict(),
|
||||||
@ -79,6 +93,11 @@ class Size:
|
|||||||
"height": self.height,
|
"height": self.height,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def overwrite_from_dict(self, data):
|
||||||
|
self.length = data.get("length", self.length)
|
||||||
|
self.width = data.get("width", self.width)
|
||||||
|
self.height = data.get("height", self.height)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, data):
|
def from_dict(cls, data):
|
||||||
return cls(
|
return cls(
|
||||||
@ -113,12 +132,17 @@ class Model:
|
|||||||
mass: int = 1
|
mass: int = 1
|
||||||
size: Size = dataclasses.field(default_factory=Size)
|
size: Size = dataclasses.field(default_factory=Size)
|
||||||
|
|
||||||
def __post_init__(self):
|
@classmethod
|
||||||
|
def gen_id(cls):
|
||||||
global _nr_model_id
|
global _nr_model_id
|
||||||
|
global _nr_model_id_lock
|
||||||
|
with _nr_model_id_lock:
|
||||||
|
_nr_model_id += 1
|
||||||
|
return _nr_model_id
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
if self.id == -1:
|
if self.id == -1:
|
||||||
with _nr_model_id_lock:
|
self.id = self.gen_id()
|
||||||
self.id = _nr_model_id
|
|
||||||
_nr_model_id += 1
|
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {
|
return {
|
||||||
@ -133,12 +157,23 @@ class Model:
|
|||||||
"size": self.size.to_dict(),
|
"size": self.size.to_dict(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def overwrite_from_dict(self, data):
|
||||||
|
self.name = data.get("name", self.name)
|
||||||
|
self.obj_type = ModelType(data.get("obj_type", self.obj_type))
|
||||||
|
self.id = data.get("id", self.id)
|
||||||
|
self.pose.overwrite_from_dict(data.get("pose", {}))
|
||||||
|
self.description = data.get("description", self.description)
|
||||||
|
self.ability_code = data.get("ability_code", self.ability_code)
|
||||||
|
self.tag_id = data.get("tag_id", self.tag_id)
|
||||||
|
self.mass = data.get("mass", self.mass)
|
||||||
|
self.size.overwrite_from_dict(data.get("size", {}))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, data):
|
def from_dict(cls, data):
|
||||||
return cls(
|
return cls(
|
||||||
name=data.get("name", ""),
|
name=data.get("name", ""),
|
||||||
obj_type=ModelType(data.get("obj_type", 0)),
|
obj_type=ModelType(data.get("obj_type", 0)),
|
||||||
id=data.get("id", -1),
|
id=data.get("id", cls.gen_id()), # 添加模型用
|
||||||
pose=Pose.from_dict(data.get("pose", {})),
|
pose=Pose.from_dict(data.get("pose", {})),
|
||||||
description=data.get("description", ""),
|
description=data.get("description", ""),
|
||||||
ability_code=data.get("ability_code", []),
|
ability_code=data.get("ability_code", []),
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class SceneManager:
|
|||||||
self.scene_name_dict[name] = scene
|
self.scene_name_dict[name] = scene
|
||||||
self.scene_id_dict[scene.id] = scene
|
self.scene_id_dict[scene.id] = scene
|
||||||
|
|
||||||
def get_scene(self):
|
def get_scenes(self):
|
||||||
return list(self.scene_name_dict.values())
|
return list(self.scene_name_dict.values())
|
||||||
|
|
||||||
def get_scripts(self, name):
|
def get_scripts(self, name):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user