372 lines
11 KiB
GDScript
372 lines
11 KiB
GDScript
#@tool
|
|
extends Node3D
|
|
|
|
# 模拟对象分类标签的常量
|
|
enum label {
|
|
UNKNOWN,
|
|
CAR,
|
|
TRUCK,
|
|
BUS,
|
|
TRAILER,
|
|
MOTORCYCLE,
|
|
BICYCLE,
|
|
PEDESTRIAN
|
|
}
|
|
|
|
|
|
# 定义不同类型对象的模型池,包含预加载的场景资源和对象池
|
|
var model_types = {
|
|
"car": {"scene": preload("res://Dynamic_Object/car.tscn"), "pool": []},
|
|
"pedestrian": {"scene": preload("res://Dynamic_Object/pedestrian.tscn"), "pool": []},
|
|
"truck": {"scene": preload("res://Dynamic_Object/suv.tscn"), "pool": []},
|
|
"trailer": {"scene": preload("res://Dynamic_Object/trailer.tscn"), "pool": []},
|
|
"bus": {"scene": preload("res://Dynamic_Object/bus.tscn"), "pool": []},
|
|
"bicycle": {"scene": preload("res://Dynamic_Object/bicycle.tscn"), "pool": []},
|
|
"motorcycle": {"scene": preload("res://Dynamic_Object/motorcycle.tscn"), "pool": []},
|
|
}
|
|
func _ready() -> void:
|
|
|
|
Websocket.connected_to_server.connect(Callable(self, "connected_to_server"))
|
|
Websocket.message_received.connect(Callable(self, "message_received"))
|
|
|
|
|
|
func connected_to_server():
|
|
update_vector_map_marker()
|
|
update_dynamic_object_marker()
|
|
update_path_drivable_area_marker()
|
|
update_trajectory_marker()
|
|
update_global_path_traiectory()
|
|
|
|
#%LoadingPage.set_jd(50)
|
|
pass # Replace with function body
|
|
|
|
func message_received(data: Dictionary):
|
|
if data.is_empty():
|
|
return
|
|
if !data.has("topic"):return
|
|
match data.topic:
|
|
"/map/vector_map_marker":
|
|
var vector_map_list = []
|
|
var vector_map_list_ns = []
|
|
for pos in data.msg.markers:
|
|
for marker in pos.points: # visualisation all
|
|
vector_map_list.append(Vector3(marker.x, marker.z, -marker.y))
|
|
|
|
visualize_mesh(vector_map_list)
|
|
|
|
# visualisation parking space chaging color
|
|
if pos.ns == "parking_space":
|
|
#print("Detected parking space marker with id: ", pos.id)
|
|
var a = func ():
|
|
# parking space 的坐标
|
|
for node in %ParkingSpace.get_children():
|
|
node.queue_free()
|
|
var verts = []
|
|
for i in pos.points.size()/6:
|
|
vector_map_list_ns = []
|
|
|
|
for index in 6:
|
|
var _marker = pos.points[(i*6)+index]
|
|
#print((i*6)+index)
|
|
vector_map_list_ns.append(Vector3(_marker.x, _marker.z, -_marker.y))
|
|
|
|
verts.append(Vector3(_marker.x, _marker.z, -_marker.y))
|
|
|
|
visualize_mesh_ps(vector_map_list_ns)
|
|
#await get_tree().create_timer(2).timeout
|
|
#$StaticBody3D/CollisionShape3D.shape = ConcavePolygonShape3D.new()
|
|
#$StaticBody3D/CollisionShape3D.shape.set_faces(verts)
|
|
a.call()
|
|
|
|
#%LoadingPage.set_jd(100)
|
|
|
|
|
|
"/perception/object_recognition/objects":
|
|
var objects_list = {}
|
|
for obj in data.msg.objects:
|
|
if obj.classification[0].label == label.UNKNOWN:
|
|
continue
|
|
|
|
var pos = obj.kinematics.initial_pose_with_covariance.pose.position
|
|
var quat = obj.kinematics.initial_pose_with_covariance.pose.orientation
|
|
var shape = obj.shape
|
|
|
|
# 将字典转换为 Quaternion 对象
|
|
var my_quat = dictionary_to_quaternion(quat)
|
|
|
|
var euler_angles = quat_to_euler(my_quat)
|
|
var roll = euler_angles.x
|
|
var pitch = euler_angles.y
|
|
var yaw = euler_angles.z
|
|
|
|
#print("test yaw data: ", yaw)
|
|
|
|
var dynamic_object = {
|
|
"position": ros2_to_godot(pos.x, pos.y, pos.z),
|
|
|
|
"rotation": ros2_to_godot(roll, pitch, yaw),
|
|
"size": ros2_to_godot(shape.dimensions.x, shape.dimensions.y, shape.dimensions.z)
|
|
}
|
|
|
|
var calss_name = ret_class(obj.classification[0].label)
|
|
if !objects_list.has(calss_name):
|
|
objects_list[calss_name] = []
|
|
objects_list[calss_name].append(dynamic_object)
|
|
|
|
visualize_dynamic_objects(objects_list)
|
|
|
|
# path drivable area marker
|
|
"/planning/scenario_planning/lane_driving/behavior_planning/path":
|
|
var arr = []
|
|
var arr2 = []
|
|
for post in data.msg.left_bound:
|
|
arr.append(Vector3(post.x,post.z,-post.y))
|
|
for post in data.msg.right_bound:
|
|
arr2.append(Vector3(post.x,post.z,-post.y))
|
|
add_ptah(arr2,%left_line)
|
|
add_ptah(arr,%right_line)
|
|
|
|
|
|
var vertices = []
|
|
for point in data.msg.points:
|
|
var post = (point.pose.position)
|
|
vertices.push_back(Vector3(post.x, post.z, -post.y))
|
|
pass
|
|
%GlobalPathTraiectory.add_ptah(vertices,%GlobalPathTraiectory,preload("res://line_4.tres"))
|
|
|
|
"/planning/scenario_planning/trajectory":
|
|
var vertices = []
|
|
for point in data.msg.points:
|
|
var post = (point.pose.position)
|
|
vertices.push_back(Vector3(post.x, post.z, -post.y))
|
|
pass
|
|
$Traiectory.add_ptah(vertices,$Traiectory)
|
|
|
|
"/planning/path_candidate/start_planner":
|
|
pass
|
|
|
|
|
|
|
|
|
|
func ret_class(id):
|
|
match id:
|
|
label.PEDESTRIAN:
|
|
return"pedestrian"
|
|
label.BICYCLE:
|
|
return"bicycle"
|
|
label.CAR:
|
|
return"car"
|
|
label.TRUCK:
|
|
return"truck"
|
|
label.MOTORCYCLE:
|
|
return"motorcycle"
|
|
label.BUS:
|
|
return"bus"
|
|
label.TRAILER:
|
|
return"trailer"
|
|
_:
|
|
return"unknown"
|
|
# 将字典转换为 Quaternion
|
|
func dictionary_to_quaternion(quat_dict: Dictionary) -> Quaternion:
|
|
return Quaternion(quat_dict["x"], quat_dict["y"], quat_dict["z"], quat_dict["w"])
|
|
|
|
|
|
# 将四元数转换为欧拉角的函数
|
|
func quat_to_euler(quat: Quaternion) -> Vector3:
|
|
var basis = Basis(quat) # 使用四元数创建一个 Basis 对象
|
|
var euler = basis.get_euler() # 获取欧拉角,返回一个包含滚转、俯仰和偏航角的 Vector3
|
|
return euler
|
|
|
|
# parking space 可视化函数
|
|
func visualize_mesh_ps(parking_space_list):
|
|
var st = StaticBody3D.new()
|
|
%ParkingSpace.add_child(st)
|
|
var co = CollisionShape3D.new()
|
|
st.add_child(co)
|
|
co.shape = ConcavePolygonShape3D.new()
|
|
co.shape.set_faces(parking_space_list)
|
|
|
|
var node = MeshInstance3D.new()
|
|
st.add_child(node)
|
|
node.name = "mesh"
|
|
|
|
|
|
node.mesh = ArrayMesh.new()
|
|
|
|
var arr = []
|
|
arr.resize(Mesh.ARRAY_MAX)
|
|
var verts = PackedVector3Array()
|
|
var normals = PackedVector3Array()
|
|
|
|
for point in parking_space_list:
|
|
verts.append(point)
|
|
normals.append(Vector3(0, 1, 0))
|
|
arr[Mesh.ARRAY_VERTEX] = verts
|
|
arr[Mesh.ARRAY_NORMAL] = normals
|
|
node.mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr)
|
|
|
|
node.mesh.surface_set_material(0,preload("res://ParkingSpace.tres")) # parking space color
|
|
|
|
# 可视化路面的函数
|
|
func visualize_mesh(triangle_list):
|
|
$RoadSurface.mesh = ArrayMesh.new()
|
|
|
|
var arr = []
|
|
arr.resize(Mesh.ARRAY_MAX)
|
|
var verts = PackedVector3Array()
|
|
var normals = PackedVector3Array()
|
|
|
|
for point in triangle_list:
|
|
verts.append(point)
|
|
normals.append(Vector3(0, 1, 0))
|
|
arr[Mesh.ARRAY_VERTEX] = verts
|
|
arr[Mesh.ARRAY_NORMAL] = normals
|
|
$RoadSurface.mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr)
|
|
$RoadSurface.mesh.surface_set_material(0,preload("res://line_3.tres"))
|
|
|
|
func visualize_dynamic_objects(objects_list):
|
|
|
|
for key in objects_list.keys():
|
|
|
|
var cha_zhi = model_types[key].pool.size() - objects_list[key].size()
|
|
if cha_zhi <= 0:
|
|
for i in abs(cha_zhi):
|
|
var node = model_types[key].scene.instantiate()
|
|
model_types[key].pool.append(node)
|
|
node.visible = false
|
|
$DynamicObject.add_child(node)
|
|
for node in model_types[key].pool:
|
|
node.visible = false
|
|
for index in objects_list[key].size():
|
|
var obj = objects_list[key][index]
|
|
var node = model_types[key].pool[index]
|
|
node.visible = true
|
|
#node.position = obj.position
|
|
#node.rotation = obj.rotation
|
|
#node.scale = obj.size
|
|
|
|
node.mb_post = (Vector3(obj["position"].x, obj["position"].y - obj["size"].y * 0.5, obj["position"].z))
|
|
node.mb_rotation = (obj["rotation"])
|
|
|
|
pass
|
|
|
|
func add_ptah(arr,node):
|
|
#print(arr)
|
|
var vertices = PackedVector3Array()
|
|
for index in arr.size():
|
|
if arr.size() <=2:
|
|
if index >= arr.size() -2: break
|
|
var a_post:Vector3 = arr[index]
|
|
var b_post:Vector3 = arr[index + 1]
|
|
var a1 = calculate_A2_position(Vector2(a_post.x,a_post.z),Vector2(b_post.x,b_post.z),0.1)
|
|
|
|
vertices.push_back(a_post)
|
|
vertices.push_back(Vector3(a1.x,a_post.y,a1.y))
|
|
vertices.push_back(b_post)
|
|
|
|
var b1 = calculate_A2_position(Vector2(b_post.x,b_post.z),Vector2(a_post.x,a_post.z),0.1)
|
|
|
|
vertices.push_back(Vector3(b1.x,b_post.y,b1.y))
|
|
vertices.push_back(b_post)
|
|
|
|
vertices.push_back(Vector3(a1.x,a_post.y,a1.y))
|
|
else:
|
|
if index >= arr.size() -2: break
|
|
var a_post:Vector3 = arr[index]
|
|
var b_post:Vector3 = arr[index + 1]
|
|
var c_post:Vector3 = arr[index + 2]
|
|
var a1 = calculate_A2_position(Vector2(a_post.x,a_post.z),Vector2(b_post.x,b_post.z),0.1)
|
|
|
|
vertices.push_back(a_post)
|
|
vertices.push_back(Vector3(a1.x,a_post.y,a1.y))
|
|
vertices.push_back(b_post)
|
|
|
|
var b1 = calculate_A2_position(Vector2(b_post.x,b_post.z),Vector2(c_post.x,c_post.z),0.1)
|
|
|
|
vertices.push_back(Vector3(b1.x,b_post.y,b1.y))
|
|
vertices.push_back(b_post)
|
|
|
|
vertices.push_back(Vector3(a1.x,a_post.y,a1.y))
|
|
# 初始化 ArrayMesh。
|
|
var arr_mesh = ArrayMesh.new()
|
|
var arrays = []
|
|
arrays.resize(Mesh.ARRAY_MAX)
|
|
arrays[Mesh.ARRAY_VERTEX] = vertices
|
|
# 创建 Mesh。
|
|
arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
|
node.mesh = arr_mesh
|
|
node.mesh.surface_set_material(0,preload("res://line.tres"))
|
|
pass
|
|
|
|
func calculate_A2_position(A1: Vector2, B1: Vector2, distance_to_A2: float) -> Vector2:
|
|
var m_l2 = (B1.y - A1.y) / (B1.x - A1.x) # 计算m_l2 (B1 和 A1之间的斜率)
|
|
var m_l1 = -1 / m_l2 # 计算m_l1 (垂直线的斜率)
|
|
var dx = distance_to_A2 / sqrt(1 + pow(m_l1, 2)) # 计算 dx 和 dy
|
|
var dy = m_l1 * dx
|
|
# 计算 A2 的位置 (有两个可能的解)
|
|
var A2_1 = Vector2(A1.x + dx, A1.y + dy)
|
|
var A2_2 = Vector2(A1.x - dx, A1.y - dy)
|
|
|
|
var direction_to_b1 = (B1 - A1).normalized()
|
|
if direction_to_b1.cross(A2_1 - A1) > 0:
|
|
return A2_1
|
|
else:
|
|
return A2_2
|
|
|
|
# 可视化矢量地图
|
|
func update_vector_map_marker():
|
|
var send_data = {
|
|
"op": "subscribe",
|
|
"topic": "/map/vector_map_marker",
|
|
"type": "visualization_msgs/msg/MarkerArray"
|
|
}
|
|
Websocket.send_msg(var_to_str(send_data))
|
|
|
|
# 可视化障碍物
|
|
func update_dynamic_object_marker():
|
|
var send_data = {
|
|
"op": "subscribe",
|
|
"topic": "/perception/object_recognition/objects",
|
|
"type": "autoware_auto_perception_msgs/msg/PredictedObjects"
|
|
}
|
|
|
|
Websocket.send_msg(var_to_str(send_data))
|
|
|
|
|
|
# path drivable area marker
|
|
func update_path_drivable_area_marker():
|
|
var send_data = {
|
|
"op": "subscribe",
|
|
"topic": "/planning/scenario_planning/lane_driving/behavior_planning/path",
|
|
"type": "autoware_auto_planning_msgs/msg/Path"
|
|
}
|
|
|
|
Websocket.send_msg(var_to_str(send_data))
|
|
|
|
|
|
# trajectory marker
|
|
func update_trajectory_marker():
|
|
var send_data = {
|
|
"op": "subscribe",
|
|
"topic": "/planning/scenario_planning/trajectory",
|
|
"type": "autoware_auto_planning_msgs/msg/Trajectory"
|
|
}
|
|
|
|
Websocket.send_msg(var_to_str(send_data))
|
|
|
|
# add ptah left_line and right_line
|
|
func update_global_path_traiectory():
|
|
var send_data = {
|
|
"op": "subscribe",
|
|
"topic": "/planning/scenario_planning/lane_driving/behavior_planning/path",
|
|
"type": "autoware_auto_planning_msgs/msg/Path"
|
|
}
|
|
|
|
Websocket.send_msg(var_to_str(send_data))
|
|
|
|
|
|
# ROS 到 Godot 的转换函数
|
|
func ros2_to_godot(x, y, z) -> Vector3:
|
|
# 将 ROS 的坐标 (x, y, z) 转换为 Godot 的坐标 (x, z, -y)
|
|
return Vector3(x, z, -y)
|