|
|
|
@ -10,7 +10,8 @@ import cv2
|
|
|
|
import numpy as np
|
|
|
|
import numpy as np
|
|
|
|
from std_srvs.srv import Trigger
|
|
|
|
from std_srvs.srv import Trigger
|
|
|
|
from tf2_ros import Buffer, TransformListener
|
|
|
|
from tf2_ros import Buffer, TransformListener
|
|
|
|
|
|
|
|
from gen_locations_on_mesh_msgs.msg import LocationsOnMesh
|
|
|
|
|
|
|
|
from gen_locations_on_mesh_msgs.srv import RemoveLocation
|
|
|
|
|
|
|
|
|
|
|
|
class FireExtinguisherEmulatorNode(Node):
|
|
|
|
class FireExtinguisherEmulatorNode(Node):
|
|
|
|
|
|
|
|
|
|
|
|
@ -26,6 +27,8 @@ class FireExtinguisherEmulatorNode(Node):
|
|
|
|
|
|
|
|
|
|
|
|
self.declare_parameter('show_target', True)
|
|
|
|
self.declare_parameter('show_target', True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.declare_parameter('sof_r', 0.5)
|
|
|
|
|
|
|
|
|
|
|
|
self.crosshair_alpha = self.get_parameter('crosshair_alpha').value
|
|
|
|
self.crosshair_alpha = self.get_parameter('crosshair_alpha').value
|
|
|
|
self.crosshair_speed = self.get_parameter('crosshair_speed').value
|
|
|
|
self.crosshair_speed = self.get_parameter('crosshair_speed').value
|
|
|
|
self.crosshair_color = self.get_parameter('crosshair_color').value
|
|
|
|
self.crosshair_color = self.get_parameter('crosshair_color').value
|
|
|
|
@ -34,8 +37,9 @@ class FireExtinguisherEmulatorNode(Node):
|
|
|
|
self.robot_frame = self.get_parameter('robot_frame').value
|
|
|
|
self.robot_frame = self.get_parameter('robot_frame').value
|
|
|
|
|
|
|
|
|
|
|
|
self.show_target = self.get_parameter('show_target').value
|
|
|
|
self.show_target = self.get_parameter('show_target').value
|
|
|
|
|
|
|
|
self.sof_r = self.get_parameter('sof_r').value
|
|
|
|
|
|
|
|
|
|
|
|
# Sources of Fire positions in (x, y, z, r)
|
|
|
|
# Sources of Fire positions in (id, x, y, z, r)
|
|
|
|
self.sof_poisitions = []
|
|
|
|
self.sof_poisitions = []
|
|
|
|
|
|
|
|
|
|
|
|
# Publishers
|
|
|
|
# Publishers
|
|
|
|
@ -66,6 +70,9 @@ class FireExtinguisherEmulatorNode(Node):
|
|
|
|
self.tf_buffer = Buffer()
|
|
|
|
self.tf_buffer = Buffer()
|
|
|
|
self.tf_listener = TransformListener(self.tf_buffer, self)
|
|
|
|
self.tf_listener = TransformListener(self.tf_buffer, self)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# remove SoF
|
|
|
|
|
|
|
|
self.remove_sof_srv = self.create_client(RemoveLocation, 'remove_location')
|
|
|
|
|
|
|
|
|
|
|
|
# Timers and subscriptions
|
|
|
|
# Timers and subscriptions
|
|
|
|
self.target_timer = self.create_timer(0.1, self.target_timer_cb) # 10 Hz
|
|
|
|
self.target_timer = self.create_timer(0.1, self.target_timer_cb) # 10 Hz
|
|
|
|
|
|
|
|
|
|
|
|
@ -73,9 +80,14 @@ class FireExtinguisherEmulatorNode(Node):
|
|
|
|
self.create_subscription(Point, 'target_point', self.target_cb, 10)
|
|
|
|
self.create_subscription(Point, 'target_point', self.target_cb, 10)
|
|
|
|
self.sub_camera_info = self.create_subscription(CameraInfo, 'camera_info', self.cam_info_cb, 10)
|
|
|
|
self.sub_camera_info = self.create_subscription(CameraInfo, 'camera_info', self.cam_info_cb, 10)
|
|
|
|
self.create_subscription(Image, 'raw_image', self.raw_image_cb, 10)
|
|
|
|
self.create_subscription(Image, 'raw_image', self.raw_image_cb, 10)
|
|
|
|
|
|
|
|
self.create_subscription(LocationsOnMesh, 'locations', self.locations_cb, 10)
|
|
|
|
|
|
|
|
|
|
|
|
self.create_service(Trigger, 'fe_burst', self.fe_burst_cb)
|
|
|
|
self.create_service(Trigger, 'fe_burst', self.fe_burst_cb)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def locations_cb(self, msg):
|
|
|
|
|
|
|
|
for idx, x, y, z in zip(msg.location_id, msg.x, msg.y, msg.z):
|
|
|
|
|
|
|
|
self.sof_poisitions.append((idx, x, y, z, self.sof_r))
|
|
|
|
|
|
|
|
|
|
|
|
def fe_burst_cb(self, req, res):
|
|
|
|
def fe_burst_cb(self, req, res):
|
|
|
|
|
|
|
|
|
|
|
|
intersected_spheres = find_intersected_spheres(
|
|
|
|
intersected_spheres = find_intersected_spheres(
|
|
|
|
@ -91,8 +103,11 @@ class FireExtinguisherEmulatorNode(Node):
|
|
|
|
res.success = True
|
|
|
|
res.success = True
|
|
|
|
res.message = str(intersected_spheres[0][0]) # add ID of source of fire if success
|
|
|
|
res.message = str(intersected_spheres[0][0]) # add ID of source of fire if success
|
|
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
remove_req = RemoveLocation.Request()
|
|
|
|
|
|
|
|
remove_req.location_id = int(intersected_spheres[0][0])
|
|
|
|
|
|
|
|
future = self.remove_sof_srv.call_async(remove_req) # TODO: check future
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
|
def target_cb(self, msg):
|
|
|
|
def target_cb(self, msg):
|
|
|
|
"""Received target point in normalized coordinates [-1, 1]"""
|
|
|
|
"""Received target point in normalized coordinates [-1, 1]"""
|
|
|
|
@ -245,7 +260,7 @@ class FireExtinguisherEmulatorNode(Node):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def find_intersected_spheres(
|
|
|
|
def find_intersected_spheres(
|
|
|
|
spheres: list[tuple[float, float, float, float]], # [(x, y, z, r)]
|
|
|
|
spheres: list[tuple[int, float, float, float, float]], # [(id, x, y, z, r)]
|
|
|
|
camera_vector: Vector3, # единичный вектор в координатах камеры
|
|
|
|
camera_vector: Vector3, # единичный вектор в координатах камеры
|
|
|
|
camera_vector_length: float, # длина луча
|
|
|
|
camera_vector_length: float, # длина луча
|
|
|
|
tf_buffer: Buffer,
|
|
|
|
tf_buffer: Buffer,
|
|
|
|
@ -291,7 +306,8 @@ def find_intersected_spheres(
|
|
|
|
# 4. Проходим по всем сферам
|
|
|
|
# 4. Проходим по всем сферам
|
|
|
|
intersected = []
|
|
|
|
intersected = []
|
|
|
|
|
|
|
|
|
|
|
|
for idx, (xs, ys, zs, r) in spheres:
|
|
|
|
for sphere in spheres:
|
|
|
|
|
|
|
|
idx, xs, ys, zs, r = sphere
|
|
|
|
p_s = np.array([xs, ys, zs]) # центр сферы в мире
|
|
|
|
p_s = np.array([xs, ys, zs]) # центр сферы в мире
|
|
|
|
|
|
|
|
|
|
|
|
# k = p₀ - pₛ (вектор от сферы до камеры)
|
|
|
|
# k = p₀ - pₛ (вектор от сферы до камеры)
|
|
|
|
|