Skip to content

Commit 696d75f

Browse files
committed
Add MeshVertexCostsSparse message to efficiently update only changed
vertex costs
1 parent 7b4f25a commit 696d75f

8 files changed

Lines changed: 304 additions & 8 deletions

File tree

mesh_msgs/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ rosidl_generate_interfaces(${PROJECT_NAME}
2929
"msg/MeshVertexColorsStamped.msg"
3030
"msg/MeshVertexCosts.msg"
3131
"msg/MeshVertexCostsStamped.msg"
32+
"msg/MeshVertexCostsSparse.msg"
33+
"msg/MeshVertexCostsSparseStamped.msg"
3234
"msg/MeshTexture.msg"
3335
"msg/MeshTriangleIndices.msg"
3436
"msg/VectorField.msg"
@@ -49,4 +51,4 @@ rosidl_generate_interfaces(${PROJECT_NAME}
4951
)
5052

5153
ament_export_dependencies(rosidl_default_runtime)
52-
ament_package()
54+
ament_package()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# MeshVertexCostsSparse
2+
# Holds costs for a subset of the mesh vertices
3+
4+
# The vertex indices
5+
uint32[] vertices
6+
7+
# The cost per vertex
8+
float32[] costs
9+
10+
# The default value for all other vertices
11+
float32 default_value
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Mesh Attribute Message
2+
std_msgs/Header header
3+
string uuid
4+
string type
5+
mesh_msgs/MeshVertexCostsSparse mesh_vertex_costs

mesh_msgs_conversions/include/mesh_msgs_conversions/conversions.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include "mesh_msgs/msg/mesh_vertex_colors.hpp"
6363
#include "mesh_msgs/msg/mesh_vertex_colors_stamped.hpp"
6464
#include "mesh_msgs/msg/mesh_vertex_costs_stamped.hpp"
65+
#include "mesh_msgs/msg/mesh_vertex_costs_sparse_stamped.hpp"
6566
#include "mesh_msgs/msg/mesh_vertex_tex_coords.hpp"
6667
#include "mesh_msgs/msg/mesh_material.hpp"
6768
#include "mesh_msgs/msg/mesh_texture.hpp"
@@ -224,6 +225,31 @@ inline const mesh_msgs::msg::MeshVertexCosts toVertexCosts(
224225
return costs_msg;
225226
}
226227

228+
inline const mesh_msgs::msg::MeshVertexCostsSparse toVertexCostsSparse(
229+
const lvr2::VertexMap<float>& costs,
230+
const float default_value
231+
)
232+
{
233+
mesh_msgs::msg::MeshVertexCostsSparse costs_msg;
234+
costs_msg.vertices.resize(costs.numValues());
235+
costs_msg.costs.resize(costs.numValues());
236+
costs_msg.default_value = default_value;
237+
238+
std::transform(costs.begin(), costs.end(), costs_msg.vertices.begin(),
239+
[](const lvr2::VertexHandle& v)
240+
{
241+
return v.idx();
242+
}
243+
);
244+
std::transform(costs_msg.vertices.begin(), costs_msg.vertices.end(), costs_msg.costs.begin(),
245+
[&costs](const uint32_t idx)
246+
{
247+
return costs[lvr2::VertexHandle(idx)];
248+
}
249+
);
250+
return costs_msg;
251+
}
252+
227253
inline const mesh_msgs::msg::MeshVertexCostsStamped toVertexCostsStamped(
228254
const lvr2::VertexMap<float>& costs,
229255
const size_t num_values,
@@ -243,6 +269,24 @@ inline const mesh_msgs::msg::MeshVertexCostsStamped toVertexCostsStamped(
243269
return mesh_msg;
244270
}
245271

272+
inline const mesh_msgs::msg::MeshVertexCostsSparseStamped toVertexCostsSparseStamped(
273+
const lvr2::VertexMap<float>& costs,
274+
const float default_value,
275+
const std::string& name,
276+
const std::string& frame_id,
277+
const std::string& uuid,
278+
const rclcpp::Time& stamp = rclcpp::Time()
279+
)
280+
{
281+
mesh_msgs::msg::MeshVertexCostsSparseStamped msg;
282+
msg.mesh_vertex_costs = toVertexCostsSparse(costs, default_value);
283+
msg.uuid = uuid;
284+
msg.type = name;
285+
msg.header.frame_id = frame_id;
286+
msg.header.stamp = stamp;
287+
return msg;
288+
}
289+
246290
inline const mesh_msgs::msg::MeshVertexCosts toVertexCosts(
247291
const lvr2::DenseVertexMap<float>& costs)
248292
{

rviz_mesh_tools_plugins/include/rviz_mesh_tools_plugins/MeshDisplay.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@
101101
#include <mesh_msgs/srv/get_texture.hpp>
102102
#include <mesh_msgs/srv/get_uui_ds.hpp>
103103

104+
#include <mesh_msgs/msg/mesh_vertex_costs_sparse_stamped.hpp>
105+
104106
#endif // Q_MOC_RUN
105107

106108
#include "rclcpp/rclcpp.hpp"
@@ -308,6 +310,11 @@ private Q_SLOTS:
308310
*/
309311
void updateVertexCostsSubscription();
310312

313+
/**
314+
* @brief Updates the subscribed vertex costs update topic.
315+
*/
316+
void updateVertexCostsUpdateSubscription();
317+
311318
/**
312319
* @brief Updates the vertex color service.
313320
*/
@@ -363,6 +370,12 @@ private Q_SLOTS:
363370
*/
364371
void vertexCostsCallback(const mesh_msgs::msg::MeshVertexCostsStamped::ConstSharedPtr& costsStamped);
365372

373+
/**
374+
* @brief Handler for incoming vertex cost update messages. Validate data and update the cost layer
375+
* @param costsStamped The vertex costs
376+
*/
377+
void vertexCostsUpdateCallback(const mesh_msgs::msg::MeshVertexCostsSparseStamped::ConstSharedPtr& update);
378+
366379
/**
367380
* @brief Requests vertex colors from the specified service
368381
* @param uuid Mesh UUID
@@ -413,6 +426,8 @@ private Q_SLOTS:
413426
message_filters::Subscriber<mesh_msgs::msg::MeshVertexColorsStamped> m_vertexColorsSubscriber;
414427
/// Subscriber for vertex costs
415428
message_filters::Subscriber<mesh_msgs::msg::MeshVertexCostsStamped> m_vertexCostsSubscriber;
429+
/// Subscriber for vertex cost updates
430+
message_filters::Subscriber<mesh_msgs::msg::MeshVertexCostsSparseStamped> m_vertexCostUpdateSubscriber;
416431

417432
/// TF2 message filter for incoming mesh data. Ensures we only process meshes for which a suitable TF is available
418433
tf2_ros::RVizMessageFilterPtr<mesh_msgs::msg::MeshGeometryStamped> m_tfMeshFilter;
@@ -421,6 +436,8 @@ private Q_SLOTS:
421436
std::shared_ptr<message_filters::Cache<mesh_msgs::msg::MeshVertexColorsStamped>> m_colorsMsgCache;
422437
/// Cache for vertex costs, useful for when cost information arrives before the mesh geometry
423438
std::shared_ptr<message_filters::Cache<mesh_msgs::msg::MeshVertexCostsStamped>> m_costsMsgCache;
439+
/// Cache for vertex costs updates
440+
std::shared_ptr<message_filters::Cache<mesh_msgs::msg::MeshVertexCostsSparseStamped>> m_costsUpdateMsgCache;
424441

425442
/// Counter for the received messages
426443
uint32_t m_messagesReceived;
@@ -476,6 +493,11 @@ private Q_SLOTS:
476493
rviz_common::properties::QosProfileProperty* m_vertexCostsTopicQos;
477494
rclcpp::QoS m_vertexCostsQos;
478495

496+
/// Properties to handle topic vor vertex cost updates
497+
rviz_common::properties::RosTopicProperty* m_vertexCostUpdateTopic;
498+
rviz_common::properties::QosProfileProperty* m_vertexCostUpdateTopicQos;
499+
rclcpp::QoS m_vertexCostUpdateQos;
500+
479501
/// Property to select different types of vertex cost maps to be shown
480502
rviz_common::properties::EnumProperty* m_selectVertexCostMap;
481503

rviz_mesh_tools_plugins/include/rviz_mesh_tools_plugins/MeshVisual.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,23 @@ class MeshVisual
166166
*/
167167
bool setVertexCosts(const std::vector<float>& vertexCosts, int costColorType, float minCost, float maxCost);
168168

169+
/**
170+
* @brief Update a subset of the vertex costs
171+
*
172+
* @param vertices Vector containing the vertex indices to update
173+
* @param costs Vector containing the vertex cost information
174+
* @param costColorType colorization method (0 = rainbow; 1 = red-green)
175+
* @param minCost minimum value for colorization
176+
* @param maxCost maximum value for colorization
177+
*/
178+
bool updateVertexCosts(
179+
const std::vector<uint32_t>& vertices,
180+
const std::vector<float>& costs,
181+
int costColorType,
182+
float minCost,
183+
float maxCost
184+
);
185+
169186
/**
170187
* @brief Extracts data from the ros-messages and creates a textured mesh.
171188
*

rviz_mesh_tools_plugins/src/MeshDisplay.cpp

Lines changed: 140 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,10 @@ namespace rviz_mesh_tools_plugins
102102
MeshDisplay::MeshDisplay()
103103
: rviz_common::Display()
104104
, m_ignoreMsgs(false)
105-
, m_meshQos(rclcpp::SystemDefaultsQoS())
106-
, m_vertexColorsQos(rclcpp::SystemDefaultsQoS())
107-
, m_vertexCostsQos(rclcpp::SystemDefaultsQoS())
105+
, m_meshQos(rclcpp::QoS(1).transient_local())
106+
, m_vertexColorsQos(rclcpp::QoS(5))
107+
, m_vertexCostsQos(rclcpp::QoS(5))
108+
, m_vertexCostUpdateQos(rclcpp::QoS(10))
108109
{
109110
// mesh topic
110111
m_meshTopic = new rviz_common::properties::RosTopicProperty(
@@ -181,12 +182,21 @@ MeshDisplay::MeshDisplay()
181182

182183

183184
m_vertexCostsTopic = new rviz_common::properties::RosTopicProperty(
184-
"Vertex Costs Topic", "",
185+
"Costs Topic", "",
185186
QString::fromStdString(rosidl_generator_traits::name<mesh_msgs::msg::MeshVertexCostsStamped>()),
186187
"Vertex cost topic to subscribe to.", m_displayType, SLOT(updateVertexCostsSubscription()), this);
187188

188189
m_vertexCostsTopicQos = new rviz_common::properties::QosProfileProperty(m_vertexCostsTopic, m_vertexCostsQos);
189190

191+
m_vertexCostUpdateTopic = new rviz_common::properties::RosTopicProperty(
192+
"Update Topic", "",
193+
QString::fromStdString(
194+
rosidl_generator_traits::name<mesh_msgs::msg::MeshVertexCostsSparseStamped>()
195+
),
196+
"Vertex cost update topic to subscribe to.", m_displayType, SLOT(updateVertexCostsUpdateSubscription()), this
197+
);
198+
m_vertexCostUpdateTopicQos = new rviz_common::properties::QosProfileProperty(m_vertexCostUpdateTopic, m_vertexCostUpdateQos);
199+
190200
m_selectVertexCostMap = new rviz_common::properties::EnumProperty("Vertex Costs Type", "-- None --",
191201
"Select the type of vertex cost map to be displayed. New types "
192202
"will appear here when a new message arrives.",
@@ -775,14 +785,50 @@ void MeshDisplay::updateVertexCostsSubscription()
775785
auto node = context_->getRosNodeAbstraction().lock()->get_raw_node();
776786
m_vertexCostsSubscriber.subscribe(node, m_vertexCostsTopic->getTopicStd(), m_vertexCostsQos.get_rmw_qos_profile());
777787

778-
m_costsMsgCache = std::make_shared<message_filters::Cache<mesh_msgs::msg::MeshVertexCostsStamped>>(m_vertexCostsSubscriber, 1);
788+
// TODO: What is a good cache size? Could it be configurable by the user? Also it is not possible to clear the message cache after we processed the messages?
789+
m_costsMsgCache = std::make_shared<message_filters::Cache<mesh_msgs::msg::MeshVertexCostsStamped>>(m_vertexCostsSubscriber, 10);
779790
m_costsMsgCache->registerCallback(std::bind(&MeshDisplay::vertexCostsCallback, this, _1));
791+
792+
// Update update topic
793+
const std::string update_topic = m_vertexCostsTopic->getTopicStd() + "/updates";
794+
m_vertexCostUpdateTopic->setStdString(update_topic);
780795
} else {
781796
setStatus(rviz_common::properties::StatusProperty::Warn, "Topic", QString("Error subscribing: Empty cost topic name"));
782797
}
783798
}
784799
}
785800

801+
void MeshDisplay::updateVertexCostsUpdateSubscription()
802+
{
803+
if (m_vertexCostUpdateTopic->getHidden())
804+
{
805+
return;
806+
}
807+
808+
if (m_vertexCostUpdateTopic->getTopic().isEmpty())
809+
{
810+
return;
811+
}
812+
813+
// Update the subscription
814+
auto node_abstraction = context_->getRosNodeAbstraction().lock();
815+
if (nullptr == node_abstraction)
816+
{
817+
RCLCPP_ERROR(
818+
rclcpp::get_logger("rviz_mesh_tools_plugins"),
819+
"[MeshDisplay::updateVertexCostsUpdateSubscription] Could not get the ROS Node abstraction instance from RViz context!"
820+
);
821+
return;
822+
}
823+
824+
// Update the subscription
825+
rclcpp::Node::SharedPtr node = node_abstraction->get_raw_node();
826+
m_vertexCostUpdateSubscriber.subscribe(node, m_vertexCostUpdateTopic->getTopicStd(), m_vertexCostUpdateQos.get_rmw_qos_profile());
827+
// Update the cache
828+
m_costsUpdateMsgCache = std::make_shared<message_filters::Cache<mesh_msgs::msg::MeshVertexCostsSparseStamped>>(m_vertexCostUpdateSubscriber, 10);
829+
m_costsUpdateMsgCache->registerCallback(std::bind(&MeshDisplay::vertexCostsUpdateCallback, this, _1));
830+
}
831+
786832
void MeshDisplay::updateMaterialAndTextureServices()
787833
{
788834
if (m_ignoreMsgs)
@@ -984,6 +1030,7 @@ void MeshDisplay::meshGeometryCallback(
9841030
m_messagesReceived++;
9851031
setStatus(rviz_common::properties::StatusProperty::Ok, "Topic", QString::number(m_messagesReceived) + " messages received");
9861032
processMessage(*meshMsg);
1033+
const rclcpp::Time now = context_->getClock()->now();
9871034

9881035
// check for cached color and cost msgs that might have arrived earlier:
9891036
if (m_colorsMsgCache) {
@@ -999,8 +1046,8 @@ void MeshDisplay::meshGeometryCallback(
9991046
}
10001047
}
10011048
if (m_costsMsgCache) {
1002-
const auto costMsgs = m_costsMsgCache->getInterval(meshMsg->header.stamp, meshMsg->header.stamp); // get msgs where header.stamp match exactly (this should usually be only one msg)
1003-
RCLCPP_DEBUG_STREAM(rclcpp::get_logger("rviz_mesh_tools_plugins"), "Got " << costMsgs.size() << " cost msgs from cache with header.stamp=" << rclcpp::Time(meshMsg->header.stamp).seconds());
1049+
const auto costMsgs = m_costsMsgCache->getInterval(meshMsg->header.stamp, now);
1050+
RCLCPP_DEBUG_STREAM(rclcpp::get_logger("rviz_mesh_tools_plugins"), "Got " << costMsgs.size() << " cost msgs from cache");
10041051
for (const mesh_msgs::msg::MeshVertexCostsStamped::ConstSharedPtr& costMsg : costMsgs) {
10051052
if (costMsg->uuid == meshMsg->uuid) {
10061053
RCLCPP_DEBUG_STREAM(rclcpp::get_logger("rviz_mesh_tools_plugins"), "Found cached cost msg with matching UUID, applying its information now");
@@ -1044,6 +1091,92 @@ void MeshDisplay::vertexCostsCallback(
10441091
updateVertexCosts();
10451092
}
10461093

1094+
void MeshDisplay::vertexCostsUpdateCallback(
1095+
const mesh_msgs::msg::MeshVertexCostsSparseStamped::ConstSharedPtr& update
1096+
)
1097+
{
1098+
if (update->uuid.compare(m_lastUuid) != 0)
1099+
{
1100+
RCLCPP_WARN(rclcpp::get_logger("rviz_mesh_tools_plugins"), "Received vertex costs update, but its UUID does not match the latest mesh geometry UUID. Not updating costs.");
1101+
return;
1102+
}
1103+
1104+
if (update->mesh_vertex_costs.vertices.empty() || update->mesh_vertex_costs.costs.empty())
1105+
{
1106+
RCLCPP_WARN(rclcpp::get_logger("rviz_mesh_tools_plugins"), "Received an empty vertex costs update.");
1107+
return;
1108+
}
1109+
1110+
// Vertex cost have to be applied to the cached layer
1111+
auto result = m_costCache.find(update->type);
1112+
// Unknown layer
1113+
if (result == m_costCache.end())
1114+
{
1115+
//TODO: We could create an empty layer
1116+
return;
1117+
}
1118+
1119+
// Update data in the cache
1120+
const auto& data = update->mesh_vertex_costs;
1121+
for (size_t i = 0; i < data.vertices.size(); i++)
1122+
{
1123+
result->second[data.vertices[i]] = data.costs[i];
1124+
}
1125+
1126+
// Update the mesh if we updated the current visual
1127+
if (update->type == m_selectVertexCostMap->getStdString())
1128+
{
1129+
if (m_costUseCustomLimits->getBool())
1130+
{
1131+
if (m_costCache.count(m_selectVertexCostMap->getStdString()) != 0)
1132+
{
1133+
std::shared_ptr<MeshVisual> visual = getLatestVisual();
1134+
if (visual)
1135+
{
1136+
visual->updateVertexCosts(
1137+
data.vertices,
1138+
data.costs,
1139+
m_costColorType->getOptionInt(),
1140+
m_costLowerLimit->getFloat(),
1141+
m_costUpperLimit->getFloat()
1142+
);
1143+
}
1144+
}
1145+
}
1146+
else
1147+
{
1148+
if (m_costCache.count(m_selectVertexCostMap->getStdString()) != 0)
1149+
{
1150+
// The correct way is the get the limits from the whole layer
1151+
// TODO: Cache this with the layer itself
1152+
float maxCost = std::numeric_limits<float>::min();
1153+
float minCost = std::numeric_limits<float>::max();
1154+
for (float cost : result->second)
1155+
{
1156+
if (std::isfinite(cost) && cost > maxCost)
1157+
maxCost = cost;
1158+
if (std::isfinite(cost) && cost < minCost)
1159+
minCost = cost;
1160+
}
1161+
1162+
1163+
std::shared_ptr<MeshVisual> visual = getLatestVisual();
1164+
if (visual)
1165+
{
1166+
visual->updateVertexCosts(
1167+
data.vertices,
1168+
data.costs,
1169+
m_costColorType->getOptionInt(),
1170+
minCost,
1171+
maxCost
1172+
);
1173+
}
1174+
}
1175+
}
1176+
updateMeshMaterial();
1177+
}
1178+
}
1179+
10471180
void MeshDisplay::requestVertexColors(std::string uuid)
10481181
{
10491182
if (m_ignoreMsgs)

0 commit comments

Comments
 (0)