Skip to content

Commit ebf5435

Browse files
authored
Fix the flakey rviz_rendering tests (#1026)
* Fix memory leak in effort_visual.cpp. When shutting down, we were forgetting to free the effort_arrow and effort_circle memory. Switch to using unique pointers there, which will take care of this for us. * Make sure to initialize ScrewVisual member variables. Otherwise you can run into situations where the user forgets to call one of the 'set' methods, and we now access uninitialized memory. * Make sure to set the frame orientation and position in effort visual. As the API currently stands, it is very easy to access uninitialized memory by forgetting to call setFramePosition() and setFrameOrientation() before calling setEffort(). Fix at least this bit in the tests, and clean things up a little so this is easier to read. * Change EffortVisual constructor to take width and scale. That way we ensure that these will always be set. * Revamp adding things to the EffortVisual class during setEffort. This is in an attempt to make sure we don't access uninitialized memory. It is a little complicated because it is possible for the user to have set some of the information before the setEffort() call, and we don't want to forget that. So when setEffort() is called, we use the already set values if they are available. If they aren't, we use the identity. On disable, we only erase the effort_arrow and effort_circle, again so we don't forget information the user may have otherwise provided us. With all of this in place, it isn't possible to call setEffort anymore and access uninitialized memory. Signed-off-by: Chris Lalancette <[email protected]>
1 parent 657b9ea commit ebf5435

File tree

6 files changed

+57
-36
lines changed

6 files changed

+57
-36
lines changed

rviz_default_plugins/src/rviz_default_plugins/displays/effort/effort_display.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,13 @@ void EffortDisplay::processMessage(sensor_msgs::msg::JointState::ConstSharedPtr
291291
std::shared_ptr<rviz_rendering::EffortVisual> visual;
292292
if (visuals_.size() == static_cast<size_t>(history_length_property_->getInt())) {
293293
visual = visuals_.front();
294+
visual->setWidth(width_property_->getFloat());
295+
visual->setScale(scale_property_->getFloat());
294296
} else {
295297
visual = std::make_shared<rviz_rendering::EffortVisual>(
296-
context_->getSceneManager(), scene_node_);
298+
context_->getSceneManager(), scene_node_,
299+
width_property_->getFloat(), scale_property_->getFloat());
297300
}
298-
visual->setWidth(width_property_->getFloat());
299-
visual->setScale(scale_property_->getFloat());
300301

301302
if (visuals_.size() >= static_cast<size_t>(history_length_property_->getInt())) {
302303
visuals_.pop_front();

rviz_rendering/include/rviz_rendering/objects/effort_visual.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#define RVIZ_RENDERING__OBJECTS__EFFORT_VISUAL_HPP_
3232

3333
#include <map>
34+
#include <memory>
3435
#include <string>
3536

3637
#include <OgreSceneNode.h>
@@ -47,7 +48,8 @@ class EffortVisual
4748
{
4849
public:
4950
RVIZ_RENDERING_PUBLIC
50-
EffortVisual(Ogre::SceneManager * scene_manager, Ogre::SceneNode * parent_node);
51+
EffortVisual(
52+
Ogre::SceneManager * scene_manager, Ogre::SceneNode * parent_node, float width, float scale);
5153

5254
// set rainbow color
5355
RVIZ_RENDERING_PUBLIC
@@ -72,8 +74,8 @@ class EffortVisual
7274

7375
private:
7476
// The object implementing the effort circle
75-
std::map<std::string, rviz_rendering::BillboardLine *> effort_circle_;
76-
std::map<std::string, rviz_rendering::Arrow *> effort_arrow_;
77+
std::map<std::string, std::unique_ptr<rviz_rendering::BillboardLine>> effort_circle_;
78+
std::map<std::string, std::unique_ptr<rviz_rendering::Arrow>> effort_arrow_;
7779
std::map<std::string, bool> effort_enabled_;
7880

7981
Ogre::SceneManager * scene_manager_;

rviz_rendering/src/rviz_rendering/objects/effort_visual.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,17 @@
2727
* POSSIBILITY OF SUCH DAMAGE.
2828
*/
2929

30-
#define _USE_MATH_DEFINES
30+
#define _USE_MATH_DEFINES
3131
#include "rviz_rendering/objects/effort_visual.hpp"
3232

3333
#include <algorithm>
3434
#include <cmath>
3535

3636
namespace rviz_rendering
3737
{
38-
EffortVisual::EffortVisual(Ogre::SceneManager * scene_manager, Ogre::SceneNode * parent_node)
39-
: scene_manager_(scene_manager), parent_node_(parent_node)
38+
EffortVisual::EffortVisual(
39+
Ogre::SceneManager * scene_manager, Ogre::SceneNode * parent_node, float width, float scale)
40+
: scene_manager_(scene_manager), parent_node_(parent_node), width_(width), scale_(scale)
4041
{
4142
}
4243

@@ -71,15 +72,31 @@ void EffortVisual::setEffort(const std::string & joint_name, double effort, doub
7172
bool enabled = effort_enabled_.insert(std::make_pair(joint_name, true)).first->second;
7273

7374
// enable or disable draw
74-
if (effort_circle_.find(joint_name) != effort_circle_.end() && !enabled) { // enable->disable
75-
delete (effort_circle_[joint_name]);
76-
delete (effort_arrow_[joint_name]);
77-
effort_circle_.erase(joint_name);
78-
effort_arrow_.erase(joint_name);
79-
}
80-
if (effort_circle_.find(joint_name) == effort_circle_.end() && enabled) { // disable -> enable
81-
effort_circle_[joint_name] = new rviz_rendering::BillboardLine(scene_manager_, parent_node_);
82-
effort_arrow_[joint_name] = new rviz_rendering::Arrow(scene_manager_, parent_node_);
75+
if (enabled) {
76+
if (effort_circle_.count(joint_name) == 0) {
77+
effort_circle_[joint_name] =
78+
std::make_unique<rviz_rendering::BillboardLine>(scene_manager_, parent_node_);
79+
}
80+
if (effort_arrow_.count(joint_name) == 0) {
81+
effort_arrow_[joint_name] =
82+
std::make_unique<rviz_rendering::Arrow>(scene_manager_, parent_node_);
83+
}
84+
if (position_.count(joint_name) == 0) {
85+
position_[joint_name] = Ogre::Vector3(0.0f, 0.0f, 0.0f);
86+
}
87+
if (orientation_.count(joint_name) == 0) {
88+
orientation_[joint_name] = Ogre::Quaternion();
89+
}
90+
} else {
91+
if (effort_circle_.count(joint_name) != 0) {
92+
effort_circle_.erase(joint_name);
93+
}
94+
if (effort_arrow_.count(joint_name) != 0) {
95+
effort_arrow_.erase(joint_name);
96+
}
97+
// Note that we specifically do not erase the position_ and orientation_ here, as the user
98+
// may have set them via setFrame{Position,Orientation} below and we don't want to
99+
// forget that information.
83100
}
84101

85102
if (!enabled) {

rviz_rendering/src/rviz_rendering/objects/screw_visual.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,16 @@
4242
namespace rviz_rendering
4343
{
4444
ScrewVisual::ScrewVisual(Ogre::SceneManager * scene_manager, Ogre::SceneNode * parent_node)
45+
: linear_scale_(0.0f), angular_scale_(0.0f), width_(0.0f), hide_small_values_(true),
46+
scene_manager_(scene_manager)
4547
{
46-
scene_manager_ = scene_manager;
47-
4848
// Ogre::SceneNode s form a tree, with each node storing the transform (position and orientation)
4949
// of itself relative to its parent. Ogre does the math of combining those transforms
5050
// for rendering. Here we create a node to store the pose of the screw's header
5151
// frame relative to the RViz fixed frame.
5252
frame_node_ = parent_node->createChildSceneNode();
5353
linear_node_ = frame_node_->createChildSceneNode();
5454
angular_node_ = frame_node_->createChildSceneNode();
55-
hide_small_values_ = true;
5655

5756
// We create the arrow object within the frame node so that we can
5857
// set its position and direction relative to its header frame.

rviz_rendering/test/rviz_rendering/objects/effort_visual_test.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,24 +73,25 @@ class EffortVisualTestFixture : public ::testing::Test
7373
std::shared_ptr<rviz_rendering::OgreTestingEnvironment> testing_environment_;
7474
};
7575

76-
Ogre::SceneNode * findForceArrow(Ogre::SceneNode * scene_node)
76+
static Ogre::SceneNode * findForceArrow(Ogre::SceneNode * scene_node)
7777
{
78-
auto arrows = rviz_rendering::findAllArrows(scene_node);
79-
auto billboard_line = rviz_rendering::findOneBillboardChain(scene_node);
80-
for (const auto & arrow : arrows) {
78+
std::vector<Ogre::SceneNode *> arrows = rviz_rendering::findAllArrows(scene_node);
79+
Ogre::BillboardChain * billboard_line = rviz_rendering::findOneBillboardChain(scene_node);
80+
for (Ogre::SceneNode * arrow : arrows) {
8181
if (billboard_line->getParentSceneNode()->getParent() == arrow->getParent()) {
8282
return arrow;
8383
}
8484
}
8585
return nullptr;
8686
}
8787

88-
8988
TEST_F(EffortVisualTestFixture, setEffort_sets_force_arrow_correctly) {
9089
auto scene_manager = Ogre::Root::getSingletonPtr()->createSceneManager();
9190
auto root_node = scene_manager->getRootSceneNode();
9291

93-
auto effort_visual = std::make_shared<rviz_rendering::EffortVisual>(scene_manager, root_node);
92+
auto effort_visual = std::make_shared<rviz_rendering::EffortVisual>(
93+
scene_manager, root_node, 0.0f, 0.0f);
94+
ASSERT_NE(nullptr, effort_visual);
9495

9596
Ogre::ColourValue color;
9697
effort_visual->getRainbowColor(0, color);
@@ -99,10 +100,11 @@ TEST_F(EffortVisualTestFixture, setEffort_sets_force_arrow_correctly) {
99100
effort_visual->getRainbowColor(1, color);
100101
EXPECT_THAT(color, ColorEq(Ogre::ColourValue(1, 0, 0, 1)));
101102

103+
effort_visual->setFramePosition("joint1", Ogre::Vector3(0, 0, 0));
104+
effort_visual->setFrameOrientation("joint1", Ogre::Quaternion());
102105
effort_visual->setEffort("joint1", 1, 10);
103106

104-
effort_visual->setFramePosition("joint1", Ogre::Vector3());
105-
auto arrows = rviz_rendering::findAllArrows(root_node);
107+
std::vector<Ogre::SceneNode *> arrows = rviz_rendering::findAllArrows(root_node);
106108
EXPECT_THAT(arrows, SizeIs(1u));
107109
EXPECT_THAT(
108110
arrows[0]->convertWorldToLocalPosition(Ogre::Vector3(0, 0, 0)),
@@ -124,14 +126,14 @@ TEST_F(EffortVisualTestFixture, setEffort_hides_force_arrow_for_larger_width_tha
124126
auto scene_manager = Ogre::Root::getSingletonPtr()->createSceneManager();
125127
auto root_node = scene_manager->getRootSceneNode();
126128

127-
auto effort_visual = std::make_shared<rviz_rendering::EffortVisual>(scene_manager, root_node);
129+
auto effort_visual = std::make_shared<rviz_rendering::EffortVisual>(
130+
scene_manager, root_node, 5.0f, 0.7f);
131+
ASSERT_NE(nullptr, effort_visual);
128132

129-
Ogre::Vector3 pos1(1, 2, 3);
133+
effort_visual->setFramePosition("joint1", Ogre::Vector3(0, 0, 0));
134+
effort_visual->setFrameOrientation("joint1", Ogre::Quaternion());
130135
effort_visual->setEffort("joint1", 1, 10);
131136

132-
effort_visual->setScale(0.7f);
133-
effort_visual->setWidth(5);
134-
135137
auto arrows = rviz_rendering::findAllArrows(root_node);
136138
EXPECT_THAT(arrows, SizeIs(1u));
137139
auto force_arrow = findForceArrow(root_node);

rviz_rendering/test/rviz_rendering/objects/screw_visual_test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ TEST_F(ScrewVisualTestFixture, setScrew_sets_linear_arrow_correctly) {
100100
auto root_node = scene_manager->getRootSceneNode();
101101

102102
auto screw_visual = std::make_shared<rviz_rendering::ScrewVisual>(scene_manager, root_node);
103-
EXPECT_NE(nullptr, screw_visual);
103+
ASSERT_NE(nullptr, screw_visual);
104104

105-
auto arrows = rviz_rendering::findAllArrows(root_node);
105+
std::vector<Ogre::SceneNode *> arrows = rviz_rendering::findAllArrows(root_node);
106106
EXPECT_THAT(arrows, SizeIs(3u));
107107
auto linear_arrow = findLinearArrow(root_node);
108108
auto angular_arrow = findAngularArrow(root_node);

0 commit comments

Comments
 (0)