|
|
|
@ -4,6 +4,7 @@ import random
|
|
|
|
|
|
|
|
|
|
|
|
import rclpy
|
|
|
|
import rclpy
|
|
|
|
from rclpy.node import Node
|
|
|
|
from rclpy.node import Node
|
|
|
|
|
|
|
|
from visualization_msgs.msg import MarkerArray, Marker
|
|
|
|
|
|
|
|
|
|
|
|
from gen_locations_on_mesh_msgs.msg import LocationsOnMesh
|
|
|
|
from gen_locations_on_mesh_msgs.msg import LocationsOnMesh
|
|
|
|
from gen_locations_on_mesh_msgs.srv import GenerateLocation, RemoveLocation
|
|
|
|
from gen_locations_on_mesh_msgs.srv import GenerateLocation, RemoveLocation
|
|
|
|
@ -128,15 +129,15 @@ def find_largest_piece(pieces):
|
|
|
|
max_len = max(ls)
|
|
|
|
max_len = max(ls)
|
|
|
|
return pieces[ls.index(max_len)]
|
|
|
|
return pieces[ls.index(max_len)]
|
|
|
|
|
|
|
|
|
|
|
|
def gen_new_point(piece, trs, vs, existing_ps, dist_limit, vert_shift):
|
|
|
|
def gen_new_point(piece, trs, vs, existing_ps, dist_limit, vert_shift,
|
|
|
|
|
|
|
|
max_z_coord, num_generation_trials):
|
|
|
|
'''создать новую точку случайным образом;
|
|
|
|
'''создать новую точку случайным образом;
|
|
|
|
вернуть словарь точек (с новой)'''
|
|
|
|
вернуть словарь точек (с новой)'''
|
|
|
|
# будем снова и снова пытаться сделать точку, удалённую от других;
|
|
|
|
# будем снова и снова пытаться сделать точку, удалённую от других;
|
|
|
|
# если после множества попыток это не получится, смиримся
|
|
|
|
# если после множества попыток это не получится, смиримся
|
|
|
|
# и примем ту, что есть
|
|
|
|
# и примем ту, что есть
|
|
|
|
curr_trial = 0
|
|
|
|
curr_trial = 0
|
|
|
|
max_trials = 500
|
|
|
|
while curr_trial < num_generation_trials:
|
|
|
|
while curr_trial < max_trials:
|
|
|
|
|
|
|
|
# выбрать случайный треугольник
|
|
|
|
# выбрать случайный треугольник
|
|
|
|
tr_ind = random.randrange(len(piece))
|
|
|
|
tr_ind = random.randrange(len(piece))
|
|
|
|
# сформировать координаты случайной точки в нём
|
|
|
|
# сформировать координаты случайной точки в нём
|
|
|
|
@ -153,7 +154,7 @@ def gen_new_point(piece, trs, vs, existing_ps, dist_limit, vert_shift):
|
|
|
|
c2 = vs[ind2,:]
|
|
|
|
c2 = vs[ind2,:]
|
|
|
|
p = c0 + (c1-c0)*alpha + (c2-c0)*beta
|
|
|
|
p = c0 + (c1-c0)*alpha + (c2-c0)*beta
|
|
|
|
p[2] += vert_shift
|
|
|
|
p[2] += vert_shift
|
|
|
|
if p[2] > 1.:
|
|
|
|
if p[2] > max_z_coord:
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
# проверить совпадение координат с существующими точками
|
|
|
|
# проверить совпадение координат с существующими точками
|
|
|
|
succ = True
|
|
|
|
succ = True
|
|
|
|
@ -171,24 +172,6 @@ def gen_new_point(piece, trs, vs, existing_ps, dist_limit, vert_shift):
|
|
|
|
existing_ps[new_ind] = p
|
|
|
|
existing_ps[new_ind] = p
|
|
|
|
return new_ind
|
|
|
|
return new_ind
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
mesh = trimesh.load_mesh("raw_surface.ply")
|
|
|
|
|
|
|
|
trs = get_all_triangles_with_correct_orientation(mesh.vertices,
|
|
|
|
|
|
|
|
mesh.faces,
|
|
|
|
|
|
|
|
0.5)
|
|
|
|
|
|
|
|
conns = calc_connections(trs)
|
|
|
|
|
|
|
|
pieces = calc_pieces(trs, conns)
|
|
|
|
|
|
|
|
the_piece = find_largest_piece(pieces)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
existing_points = {}
|
|
|
|
|
|
|
|
for i in range(10):
|
|
|
|
|
|
|
|
ind = gen_new_point(the_piece, trs, mesh.vertices, existing_points, 0.01, 0.1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print(existing_points)
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GenLocationsOnMeshNode(Node):
|
|
|
|
class GenLocationsOnMeshNode(Node):
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
def __init__(self):
|
|
|
|
@ -199,16 +182,24 @@ class GenLocationsOnMeshNode(Node):
|
|
|
|
self.trs = None
|
|
|
|
self.trs = None
|
|
|
|
self.the_piece = None
|
|
|
|
self.the_piece = None
|
|
|
|
self.existing_points = {}
|
|
|
|
self.existing_points = {}
|
|
|
|
|
|
|
|
self.dropped_points = {}
|
|
|
|
|
|
|
|
|
|
|
|
self.declare_parameter('mesh_filename', '')
|
|
|
|
self.declare_parameter('mesh_filename', '')
|
|
|
|
self.declare_parameter('cache_filename', '')
|
|
|
|
self.declare_parameter('cache_filename', '')
|
|
|
|
self.declare_parameter('init_number_of_points', 10)
|
|
|
|
self.declare_parameter('init_number_of_points', 10)
|
|
|
|
|
|
|
|
self.declare_parameter('max_z_coord', 2.)
|
|
|
|
|
|
|
|
self.declare_parameter('min_distance_between_points', 2.)
|
|
|
|
|
|
|
|
self.declare_parameter('height_upon_surface', 0.1)
|
|
|
|
|
|
|
|
self.declare_parameter('num_generation_trials', 1000)
|
|
|
|
|
|
|
|
|
|
|
|
self._load_data()
|
|
|
|
self._load_data()
|
|
|
|
|
|
|
|
|
|
|
|
# создать инфраструктуру ROS
|
|
|
|
# создать инфраструктуру ROS
|
|
|
|
self.state_pub_msg = LocationsOnMesh()
|
|
|
|
self.state_pub_msg = LocationsOnMesh()
|
|
|
|
self.state_pub = self.create_publisher(LocationsOnMesh, 'locations', 1)
|
|
|
|
self.state_pub = self.create_publisher(LocationsOnMesh, 'locations', 1)
|
|
|
|
|
|
|
|
self.markers_msg = MarkerArray()
|
|
|
|
|
|
|
|
self.markers_dict = {}
|
|
|
|
|
|
|
|
self.markers_pub = self.create_publisher(MarkerArray, 'locations_markers', 1)
|
|
|
|
self.generate_location_srv = self.create_service(GenerateLocation,
|
|
|
|
self.generate_location_srv = self.create_service(GenerateLocation,
|
|
|
|
'generate_location',
|
|
|
|
'generate_location',
|
|
|
|
self.generate_location_cb)
|
|
|
|
self.generate_location_cb)
|
|
|
|
@ -219,13 +210,15 @@ class GenLocationsOnMeshNode(Node):
|
|
|
|
# сгенерировать нужное количество точек
|
|
|
|
# сгенерировать нужное количество точек
|
|
|
|
num_ps = self.get_parameter('init_number_of_points').get_parameter_value().integer_value
|
|
|
|
num_ps = self.get_parameter('init_number_of_points').get_parameter_value().integer_value
|
|
|
|
for i in range(num_ps):
|
|
|
|
for i in range(num_ps):
|
|
|
|
gen_new_point(self.the_piece,
|
|
|
|
self.gen_new_point()
|
|
|
|
self.trs,
|
|
|
|
|
|
|
|
self.vs,
|
|
|
|
|
|
|
|
self.existing_points, 0.01, 0.1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pub_timer_cb(self):
|
|
|
|
def pub_timer_cb(self):
|
|
|
|
'''таймер, периодически публикующий координаты точек'''
|
|
|
|
'''таймер, периодически публикующий координаты точек'''
|
|
|
|
|
|
|
|
self.publish_unity_coords()
|
|
|
|
|
|
|
|
self.publish_real_coords_markers()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def publish_unity_coords(self):
|
|
|
|
|
|
|
|
'''опубликовать результаты в левостроронней системе координат Unity'''
|
|
|
|
# собрать в сообщение все данные про объекты
|
|
|
|
# собрать в сообщение все данные про объекты
|
|
|
|
self.state_pub_msg.location_id = []
|
|
|
|
self.state_pub_msg.location_id = []
|
|
|
|
self.state_pub_msg.x = []
|
|
|
|
self.state_pub_msg.x = []
|
|
|
|
@ -242,6 +235,14 @@ class GenLocationsOnMeshNode(Node):
|
|
|
|
# опубликовать их
|
|
|
|
# опубликовать их
|
|
|
|
self.state_pub.publish(self.state_pub_msg)
|
|
|
|
self.state_pub.publish(self.state_pub_msg)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def publish_real_coords_markers(self):
|
|
|
|
|
|
|
|
'''опубликовать данные в правосторонней системе координат реального мира'''
|
|
|
|
|
|
|
|
curr_timestamp = self.get_clock().now().to_msg()
|
|
|
|
|
|
|
|
for m in self.markers_dict.values():
|
|
|
|
|
|
|
|
m.header.stamp = curr_timestamp
|
|
|
|
|
|
|
|
self.markers_msg.markers = list(self.markers_dict.values())
|
|
|
|
|
|
|
|
self.markers_pub.publish(self.markers_msg)
|
|
|
|
|
|
|
|
|
|
|
|
def _load_data(self):
|
|
|
|
def _load_data(self):
|
|
|
|
'''загрузка мэша и его предобработка'''
|
|
|
|
'''загрузка мэша и его предобработка'''
|
|
|
|
# сначала пытаемся загрузить кэшированный вариант
|
|
|
|
# сначала пытаемся загрузить кэшированный вариант
|
|
|
|
@ -274,21 +275,56 @@ class GenLocationsOnMeshNode(Node):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_location_cb(self, request, response):
|
|
|
|
def generate_location_cb(self, request, response):
|
|
|
|
#self.get_logger().info('Incoming request GEN')
|
|
|
|
'''callback for generation service'''
|
|
|
|
ind = gen_new_point(self.the_piece,
|
|
|
|
ind = self.gen_new_point()
|
|
|
|
self.trs,
|
|
|
|
|
|
|
|
self.vs,
|
|
|
|
|
|
|
|
self.existing_points, 0.01, 0.1)
|
|
|
|
|
|
|
|
response.location_id = ind
|
|
|
|
response.location_id = ind
|
|
|
|
response.x = self.existing_points[ind][0]
|
|
|
|
response.x = self.existing_points[ind][0]
|
|
|
|
response.y = self.existing_points[ind][1]
|
|
|
|
response.y = self.existing_points[ind][1]
|
|
|
|
response.z = self.existing_points[ind][2]
|
|
|
|
response.z = self.existing_points[ind][2]
|
|
|
|
return response
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def gen_new_point(self):
|
|
|
|
|
|
|
|
'''create point, return its index'''
|
|
|
|
|
|
|
|
max_z_coord = self.get_parameter('max_z_coord').get_parameter_value().double_value
|
|
|
|
|
|
|
|
min_distance_between_points = self.get_parameter('min_distance_between_points').get_parameter_value().double_value
|
|
|
|
|
|
|
|
height_upon_surface = self.get_parameter('height_upon_surface').get_parameter_value().double_value
|
|
|
|
|
|
|
|
num_generation_trials = self.get_parameter('num_generation_trials').get_parameter_value().integer_value
|
|
|
|
|
|
|
|
ind = gen_new_point(self.the_piece,
|
|
|
|
|
|
|
|
self.trs,
|
|
|
|
|
|
|
|
self.vs,
|
|
|
|
|
|
|
|
self.existing_points,
|
|
|
|
|
|
|
|
min_distance_between_points,
|
|
|
|
|
|
|
|
height_upon_surface,
|
|
|
|
|
|
|
|
max_z_coord,
|
|
|
|
|
|
|
|
num_generation_trials)
|
|
|
|
|
|
|
|
# create marker for the new point
|
|
|
|
|
|
|
|
m = Marker()
|
|
|
|
|
|
|
|
m.header.frame_id = 'map'
|
|
|
|
|
|
|
|
m.id = ind
|
|
|
|
|
|
|
|
m.type = Marker.SPHERE
|
|
|
|
|
|
|
|
m.action = Marker.ADD
|
|
|
|
|
|
|
|
m.pose.position.x = self.existing_points[ind][0]
|
|
|
|
|
|
|
|
m.pose.position.y = self.existing_points[ind][1]
|
|
|
|
|
|
|
|
m.pose.position.z = self.existing_points[ind][2]
|
|
|
|
|
|
|
|
m.pose.orientation.w = 1.
|
|
|
|
|
|
|
|
m.scale.x = 1.
|
|
|
|
|
|
|
|
m.scale.y = 1.
|
|
|
|
|
|
|
|
m.scale.z = 1.
|
|
|
|
|
|
|
|
m.color.r = 1.
|
|
|
|
|
|
|
|
m.color.a = 1.
|
|
|
|
|
|
|
|
self.markers_dict[ind] = m
|
|
|
|
|
|
|
|
return ind
|
|
|
|
|
|
|
|
|
|
|
|
def remove_location_cb(self, request, response):
|
|
|
|
def remove_location_cb(self, request, response):
|
|
|
|
#self.get_logger().info('Incoming request RM')
|
|
|
|
#self.get_logger().info('Incoming request RM')
|
|
|
|
if request.location_id in self.existing_points:
|
|
|
|
if request.location_id in self.existing_points:
|
|
|
|
|
|
|
|
self.dropped_points[request.location_id] = self.existing_points[request.location_id]
|
|
|
|
del self.existing_points[request.location_id]
|
|
|
|
del self.existing_points[request.location_id]
|
|
|
|
|
|
|
|
# update marker
|
|
|
|
|
|
|
|
m = self.markers_dict[request.location_id]
|
|
|
|
|
|
|
|
m.color.r = 0.
|
|
|
|
|
|
|
|
m.color.g = 0.5
|
|
|
|
|
|
|
|
m.color.b = 1.
|
|
|
|
response.success = True
|
|
|
|
response.success = True
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
response.success = False
|
|
|
|
response.success = False
|
|
|
|
|