Librviz Tutorial

The RViz plugin API and library API are preliminary in Fuerte. We welcome feedback about how to make them more powerful and easier to program with. We expect the APIs to change (possibly significantly) between Fuerte and Groovy.

Overview

RViz is not just a visualizer application, it is also a library! Much of RViz’s functionality can be accessed within your own application by linking against librviz.so (or whatever your OS likes to call it).

This tutorial shows a very simple example of creating a 3D visualizer widget (rviz::RenderPanel), programmatically creating a new Grid display within it, then using Qt slider controls to adjust a couple of the grid’s properties. The app is called “myviz”.

The source code for this tutorial is in the librviz_tutorial package. You can check out the source directly or (if you use Ubuntu) you can just apt-get install the pre-compiled Debian package like so:

sudo apt-get install ros-fuerte-visualization-tutorials

The running application looks like this:

_images/myviz.png

The Code

The code for myviz is in these files: src/main.cpp, src/myviz.h, and src/myviz.cpp.

main.cpp

The full text of main.cpp is here: src/main.cpp

The main() for this “myviz” example is very simple, it just initializes ROS, creates a QApplication, creates the top-level widget (of type “MyViz”), shows it, and runs the Qt event loop.

#include <QApplication>
#include <ros/ros.h>
#include "myviz.h"

int main(int argc, char **argv)
{
  if( !ros::isInitialized() )
  {
    ros::init( argc, argv, "myviz", ros::init_options::AnonymousName );
  }

  QApplication app( argc, argv );

  MyViz* myviz = new MyViz();
  myviz->show();

  app.exec();

  delete myviz;
}

myviz.h

The full text of myviz.h is here: src/myviz.h

Class “MyViz” implements the top level widget for this example.

class MyViz: public QWidget
{
Q_OBJECT
public:
  MyViz( QWidget* parent = 0 );
  virtual ~MyViz();

private Q_SLOTS:
  void setThickness( int thickness_percent );
  void setCellSize( int cell_size_percent );

private:
  rviz::VisualizationManager* manager_;
  rviz::RenderPanel* render_panel_;
  rviz::GridDisplay* grid_;
};

myviz.cpp

The full text of myviz.cpp is here: src/myviz.cpp

Constructor for MyViz. This does most of the work of the class.

MyViz::MyViz( QWidget* parent )
  : QWidget( parent )
{

Construct and lay out labels and slider controls.

QLabel* thickness_label = new QLabel( "Line Thickness" );
QSlider* thickness_slider = new QSlider( Qt::Horizontal );
thickness_slider->setMinimum( 1 );
thickness_slider->setMaximum( 100 );
QLabel* cell_size_label = new QLabel( "Cell Size" );
QSlider* cell_size_slider = new QSlider( Qt::Horizontal );
cell_size_slider->setMinimum( 1 );
cell_size_slider->setMaximum( 100 );
QGridLayout* controls_layout = new QGridLayout();
controls_layout->addWidget( thickness_label, 0, 0 );
controls_layout->addWidget( thickness_slider, 0, 1 );
controls_layout->addWidget( cell_size_label, 1, 0 );
controls_layout->addWidget( cell_size_slider, 1, 1 );

Construct and lay out render panel.

render_panel_ = new rviz::RenderPanel();
QVBoxLayout* main_layout = new QVBoxLayout;
main_layout->addLayout( controls_layout );
main_layout->addWidget( render_panel_ );

Set the top-level layout for this MyViz widget.

setLayout( main_layout );

Make signal/slot connections.

connect( thickness_slider, SIGNAL( valueChanged( int )), this, SLOT( setThickness( int )));
connect( cell_size_slider, SIGNAL( valueChanged( int )), this, SLOT( setCellSize( int )));

Next we initialize the main RViz classes.

The VisualizationManager is the container for Display objects, holds the main Ogre scene, holds the ViewController, etc. It is very central and we will probably need one in every usage of librviz.

manager_ = new rviz::VisualizationManager( render_panel_ );
render_panel_->initialize( manager_->getSceneManager(), manager_ );
manager_->initialize();
manager_->startUpdate();

Create a Grid display.

rviz::DisplayWrapper* wrapper = manager_->createDisplay( "rviz/Grid", "adjustable grid", true );
ROS_ASSERT( wrapper != NULL );

Unwrap it.

rviz::Display* display = wrapper->getDisplay();
ROS_ASSERT( display != NULL );

Downcast it to the type we think we know it is.

(This is one part I would like to improve in the future. For this to work currently, we need to link against the plugin library containing GridDisplay (libdefault_plugin.so) in addition to linking against librviz.so. This pretty much negates the benefits of the plugin architecture.)

grid_ = dynamic_cast<rviz::GridDisplay*>( display );
ROS_ASSERT( grid_ != NULL );

Configure the GridDisplay the way we like it.

grid_->setStyle( rviz::Grid::Billboards ); // Fat lines.
grid_->setColor( rviz::Color( 1.0f, 1.0f, 0.0f )); // I like yellow.

Initialize the slider values.

  thickness_slider->setValue( 25 );
  cell_size_slider->setValue( 10 );
}

Destructor for MyViz. The complexity here is something I would like to avoid in future versions.

Removing all the displays first is not technically required for this example, but if we used a PropertyTreeWidget it would be required, so it is a good idea.

It would be required because Display objects own Properties, and Properties own children of PropertyTreeWidget (PropertyWidgetItems). PropertyTreeWidget notices when PropertyWidgetItems are destroyed, but Properties don’t notice when PropertyWidgetItems are destroyed, so must destroy from the Display (and thus Property) side first.

The render_panel_ is a child widget of MyViz and so would be deleted naturally by the QWidget destructor, but that would be after we deleted manager_. Instead we must delete render_panel_ before manager_ because ~VisualizationManager() destroys ogre SceneManager which destroys all attached SceneNodes. RenderPanel indirectly holds pointers to SceneNodes which it destroys. RenderPanel doesn’t know when Ogre destroys its SceneNodes, so RenderPanel would cause a segfault during its destructor.

MyViz::~MyViz()
{
  if( manager_ != NULL )
  {
    manager_->removeAllDisplays();
  }
  delete render_panel_;
  delete manager_;
}

This function is a Qt slot connected to a QSlider’s valueChanged() signal. It calls a property setter function on the GridDisplay, setLineWidth().

void MyViz::setThickness( int thickness_percent )
{
  if( grid_ != NULL )
  {
    grid_->setLineWidth( thickness_percent / 100.0f );
  }
}

This function is a Qt slot connected to a QSlider’s valueChanged() signal. It calls a property setter function on the GridDisplay, setCellSize().

void MyViz::setCellSize( int cell_size_percent )
{
  if( grid_ != NULL )
  {
    grid_->setCellSize( cell_size_percent / 10.0f );
  }
}

Building

The full text of CMakeLists.txt is here: CMakeLists.txt

Running

Just type:

rosrun librviz_tutorial myviz

I want to reiterate here the warning at the top of this page, which is that the APIs will change between Fuerte and Groovy. I would love for people to try out these APIs and submit bugs describing problems with them, so the next version can be much better.

Table Of Contents

This Page