ambient_sound_display.cpp
Go to the documentation of this file.
1 #include <OGRE/OgreSceneNode.h>
2 #include <OGRE/OgreSceneManager.h>
3 
5 
8 #include <rviz/properties/property_manager.h>
9 #include <rviz/frame_manager.h>
10 
11 #include "ambient_sound_visual.h"
12 
13 #include "ambient_sound_display.h"
14 
15 namespace jsk_rviz_plugins
16 {
17 
18  // BEGIN_TUTORIAL
19  // The constructor must have no arguments, so we can't give the
20  // constructor the parameters it needs to fully initialize.
22  : Display()
23  , scene_node_( NULL )
24  , messages_received_( 0 )
25  , color_( .8, .2, .8 ) // Default color is bright purple.
26  , alpha_( 1.0 ) // Default alpha is completely opaque.
27  , width_(0.1)
28  , scale_(0.1)
29  {
30  }/*}}}*/
31 
32  // After the parent rviz::Display::initialize() does its own setup, it
33  // calls the subclass's onInitialize() function. This is where we
34  // instantiate all the workings of the class.
36  {
37  // Make an Ogre::SceneNode to contain all our visuals.
38  scene_node_ = scene_manager_->getRootSceneNode()->createChildSceneNode();
39 
40  // Set the default history length and resize the ``visuals_`` array.
41  setHistoryLength( 1 );
42 
43  // A tf::MessageFilter listens to ROS messages and calls our
44  // callback with them when they can be matched up with valid tf
45  // transform data.
46  tf_filter_ =
47  new tf::MessageFilter<jsk_hark_msgs::HarkPower>( *vis_manager_->getTFClient(),
48  "", 100, update_nh_ );
51  this, _1 ));
52 
53  // FrameManager has some built-in functions to set the status of a
54  // Display based on callbacks from a tf::MessageFilter. These work
55  // fine for this simple display.
56  vis_manager_->getFrameManager()
57  ->registerFilterForTransformStatusCheck( tf_filter_, this );
58  }/*}}}*/
59 
61  {
62  unsubscribe();
63  clear();
64  for( size_t i = 0; i < visuals_.size(); i++ )
65  {
66  delete visuals_[ i ];
67  }
68 
69  delete tf_filter_;
70  }/*}}}*/
71 
72  // Clear the visuals by deleting their objects.
74  {
75  for( size_t i = 0; i < visuals_.size(); i++ )
76  {
77  delete visuals_[ i ];
78  visuals_[ i ] = NULL;
79  }
80  tf_filter_->clear();
82  setStatus( rviz::status_levels::Warn, "Topic", "No messages received" );
83  }/*}}}*/
84 
85  void AmbientSoundDisplay::setTopic( const std::string& topic )/*{{{*/
86  {
87  unsubscribe();
88  clear();
89  topic_ = topic;
90  subscribe();
91 
92  // Broadcast the fact that the variable has changed.
93  propertyChanged( topic_property_ );
94 
95  // Make sure rviz renders the next time it gets a chance.
96  causeRender();
97  }/*}}}*/
98 
99  void AmbientSoundDisplay::setColor( const rviz::Color& color )/*{{{*/
100  {
101  color_ = color;
102 
103  propertyChanged( color_property_ );
105  causeRender();
106  }/*}}}*/
107 
109  {
110  alpha_ = alpha;
111 
112  propertyChanged( alpha_property_ );
114  causeRender();
115  }/*}}}*/
116 
117  void AmbientSoundDisplay::setWidth( float width )/*{{{*/
118  {
119  width_ = width;
120 
121  propertyChanged( width_property_ );
123  causeRender();
124  }/*}}}*/
125 
127  {
128  scale_ = scale;
129 
130  propertyChanged( scale_property_ );
132  causeRender();
133  }
134  /*}}}*/
135 
136  void AmbientSoundDisplay::setBias( float bias )/*{{{*/
137  {
138  bias_ = bias;
139 
140  propertyChanged( bias_property_ );
142  causeRender();
143  }/*}}}*/
144 
145  void AmbientSoundDisplay::setGrad( float grad )/*{{{*/
146  {
147  grad_ = grad;
148 
149  propertyChanged( grad_property_ );
151  causeRender();
152  }/*}}}*/
153 
154  // Set the current color and alpha values for each visual.
156  {
157  for( size_t i = 0; i < visuals_.size(); i++ )
158  {
159  if( visuals_[ i ] )
160  {
161  visuals_[ i ]->setColor( color_.r_, color_.g_, color_.b_, alpha_ );
162  }
163  }
164  }/*}}}*/
165 
166  // Set the number of past visuals to show.
167  void AmbientSoundDisplay::setHistoryLength( int length )/*{{{*/
168  {
169  // Don't let people enter invalid values.
170  if( length < 1 )
171  {
172  length = 1;
173  }
174  // If the length is not changing, we don't need to do anything.
175  if( history_length_ == length )
176  {
177  return;
178  }
179 
180  // Set the actual variable.
181  history_length_ = length;
182  propertyChanged( history_length_property_ );
183 
184  // Create a new array of visual pointers, all NULL.
185  std::vector<AmbientSoundVisual*> new_visuals( history_length_, (AmbientSoundVisual*)0 );
186 
187  // Copy the contents from the old array to the new.
188  // (Number to copy is the minimum of the 2 vector lengths).
189  size_t copy_len =
190  (new_visuals.size() > visuals_.size()) ?
191  visuals_.size() : new_visuals.size();
192  for( size_t i = 0; i < copy_len; i++ )
193  {
194  int new_index = (messages_received_ - i) % new_visuals.size();
195  int old_index = (messages_received_ - i) % visuals_.size();
196  new_visuals[ new_index ] = visuals_[ old_index ];
197  visuals_[ old_index ] = NULL;
198  }
199 
200  // Delete any remaining old visuals
201  for( size_t i = 0; i < visuals_.size(); i++ ) {
202  delete visuals_[ i ];
203  }
204 
205  // We don't need to create any new visuals here, they are created as
206  // needed when messages are received.
207 
208  // Put the new vector into the member variable version and let the
209  // old one go out of scope.
210  visuals_.swap( new_visuals );
211  }/*}}}*/
212 
214  {
215  // If we are not actually enabled, don't do it.
216  if ( !isEnabled() )
217  {
218  return;
219  }
220 
221  // Try to subscribe to the current topic name (in ``topic_``). Make
222  // sure to catch exceptions and set the status to a descriptive
223  // error message.
224  try
225  {
227  setStatus( rviz::status_levels::Ok, "Topic", "OK" );
228  }
229  catch( ros::Exception& e )
230  {
231  setStatus( rviz::status_levels::Error, "Topic",
232  std::string( "Error subscribing: " ) + e.what() );
233  }
234  }/*}}}*/
235 
237  {
238  sub_.unsubscribe();
239  }/*}}}*/
240 
242  {
243  subscribe();
244  }/*}}}*/
245 
247  {
248  unsubscribe();
249  clear();
250  }/*}}}*/
251 
252  // When the "Fixed Frame" changes, we need to update our
253  // tf::MessageFilter and erase existing visuals.
255  {
257  clear();
258  }/*}}}*/
259 
260  // This is our callback to handle an incoming message.
261  void AmbientSoundDisplay::incomingMessage( const jsk_hark_msgs::HarkPower::ConstPtr& msg )/*{{{*/
262  {
264 
265  // Each display can have multiple status lines. This one is called
266  // "Topic" and says how many messages have been received in this case.
267  std::stringstream ss;
268  ss << messages_received_ << " messages received";
269  setStatus( rviz::status_levels::Ok, "Topic", ss.str() );
270 
271  // Here we call the rviz::FrameManager to get the transform from the
272  // fixed frame to the frame in the header of this Imu message. If
273  // it fails, we can't do anything else so we return.
274  Ogre::Quaternion orientation;
275  Ogre::Vector3 position;
276  if( !vis_manager_->getFrameManager()->getTransform( msg->header.frame_id,
277  msg->header.stamp,
278  position, orientation ))
279  {
280  ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'",
281  msg->header.frame_id.c_str(), fixed_frame_.c_str() );
282  return;
283  }
284 
285  // We are keeping a circular buffer of visual pointers. This gets
286  // the next one, or creates and stores it if it was missing.
287  AmbientSoundVisual* visual = visuals_[ messages_received_ % history_length_ ];
288  if( visual == NULL )
289  {
290  visual = new AmbientSoundVisual( vis_manager_->getSceneManager(), scene_node_ );
291  visuals_[ messages_received_ % history_length_ ] = visual;
292  }
293 
294  // Now set or update the contents of the chosen visual.
295  visual->setFramePosition( position );
296  visual->setFrameOrientation( orientation );
297  visual->setColor( color_.r_, color_.g_, color_.b_, alpha_ );
298  visual->setWidth( width_ );
299  visual->setScale( scale_ );
300  visual->setBias ( bias_ );
301  visual->setGrad ( grad_ );
302  visual->setMessage( msg );
303  }/*}}}*/
304 
305  // Override rviz::Display's reset() function to add a call to clear().
307  {
308  Display::reset();
309  clear();
310  }/*}}}*/
311 
312  // Override createProperties() to build and configure a Property
313  // object for each user-editable property. ``property_manager_``,
314  // ``property_prefix_``, and ``parent_category_`` are all initialized before
315  // this is called.
317  {
319  property_manager_->createProperty<rviz::ROSTopicStringProperty>( "Topic",
320  property_prefix_,
321  boost::bind( &AmbientSoundDisplay::getTopic, this ),
322  boost::bind( &AmbientSoundDisplay::setTopic, this, _1 ),
323  parent_category_,
324  this );
325  setPropertyHelpText( topic_property_, "jsk_hark_msgs::HarkPower topic to subscribe to." );
326  rviz::ROSTopicStringPropertyPtr topic_prop = topic_property_.lock();
327  topic_prop->setMessageType( ros::message_traits::datatype<jsk_hark_msgs::HarkPower>() );
328 
330  property_manager_->createProperty<rviz::ColorProperty>( "Color",
331  property_prefix_,
332  boost::bind( &AmbientSoundDisplay::getColor, this ),
333  boost::bind( &AmbientSoundDisplay::setColor, this, _1 ),
334  parent_category_,
335  this );
336  setPropertyHelpText( color_property_, "Color to draw the acceleration arrows." );
337 
339  property_manager_->createProperty<rviz::FloatProperty>( "Alpha",
340  property_prefix_,
341  boost::bind( &AmbientSoundDisplay::getAlpha, this ),
342  boost::bind( &AmbientSoundDisplay::setAlpha, this, _1 ),
343  parent_category_,
344  this );
345  setPropertyHelpText( alpha_property_, "0 is fully transparent, 1.0 is fully opaque." );
346 
348  property_manager_->createProperty<rviz::IntProperty>( "History Length",
349  property_prefix_,
350  boost::bind( &AmbientSoundDisplay::getHistoryLength, this ),
351  boost::bind( &AmbientSoundDisplay::setHistoryLength, this, _1 ),
352  parent_category_,
353  this );
354  setPropertyHelpText( history_length_property_, "Number of prior measurements to display." );
355 
356  width_property_ =
357  property_manager_->createProperty<rviz::FloatProperty>( "Width",
358  property_prefix_,
359  boost::bind( &AmbientSoundDisplay::getWidth, this ),
360  boost::bind( &AmbientSoundDisplay::setWidth, this, _1 ),
361  parent_category_,
362  this );
363  setPropertyHelpText( width_property_, "Width of line" );
364 
365  scale_property_ =
366  property_manager_->createProperty<rviz::FloatProperty>( "Scale",
367  property_prefix_,
368  boost::bind( &AmbientSoundDisplay::getScale, this ),
369  boost::bind( &AmbientSoundDisplay::setScale, this, _1 ),
370  parent_category_,
371  this );
372  setPropertyHelpText( scale_property_, "Scale of line" );
373 
374  grad_property_ =
375  property_manager_->createProperty<rviz::FloatProperty>( "Grad",
376  property_prefix_,
377  boost::bind( &AmbientSoundDisplay::getGrad, this ),
378  boost::bind( &AmbientSoundDisplay::setGrad, this, _1 ),
379  parent_category_,
380  this );
381  setPropertyHelpText( grad_property_, "Graduation" );
382 
383  bias_property_ =
384  property_manager_->createProperty<rviz::FloatProperty>( "Bias",
385  property_prefix_,
386  boost::bind( &AmbientSoundDisplay::getBias, this ),
387  boost::bind( &AmbientSoundDisplay::setBias, this, _1 ),
388  parent_category_,
389  this );
390  setPropertyHelpText( bias_property_, "Bias to subtract" );
391  }/*}}}*/
392 
393 } // end namespace jsk_rviz_plugin
394 
395 // Tell pluginlib about this class. It is important to do this in
396 // global scope, outside our package's namespace.
399 
#define NULL
void setTopic(const std::string &topic)
void connectInput(F &f)
rviz::ROSTopicStringPropertyWPtr topic_property_
void setFramePosition(const Ogre::Vector3 &position)
void setColor(const rviz::Color &color)
PLUGINLIB_EXPORT_CLASS(jsk_rviz_plugins::PictogramArrayDisplay, rviz::Display)
void incomingMessage(const jsk_hark_msgs::HarkPower::ConstPtr &msg)
ros::NodeHandle update_nh_
tf::MessageFilter< jsk_hark_msgs::HarkPower > * tf_filter_
void setFrameOrientation(const Ogre::Quaternion &orientation)
bool isEnabled() const
QString fixed_frame_
virtual void reset()
void setColor(float r, float g, float b, float a)
std::vector< AmbientSoundVisual * > visuals_
Ogre::SceneManager * scene_manager_
void subscribe(ros::NodeHandle &nh, const std::string &topic, uint32_t queue_size, const ros::TransportHints &transport_hints=ros::TransportHints(), ros::CallbackQueueInterface *callback_queue=0)
void setTargetFrame(const std::string &target_frame)
void setMessage(const jsk_hark_msgs::HarkPower::ConstPtr &msg)
virtual void setStatus(StatusProperty::Level level, const QString &name, const QString &text)
message_filters::Subscriber< jsk_hark_msgs::HarkPower > sub_
Connection registerCallback(const C &callback)
#define ROS_DEBUG(...)


jsk_rviz_plugins
Author(s): Kei Okada , Yohei Kakiuchi , Shohei Fujii , Ryohei Ueda
autogenerated on Sat Mar 20 2021 03:03:18