Difference between revisions of "David-PFC-ROS3"

From robotica.unileon.es
Jump to: navigation, search
m
m
 
(5 intermediate revisions by one other user not shown)
Line 1: Line 1:
 
* '''Project Name:''' TFM-ROS03
 
* '''Project Name:''' TFM-ROS03
 +
* '''Author:''' David Llamas Abad
 +
* '''Academic Year:''' 2012-2013
 +
* '''Degree:''' Undergraduate
 +
* '''Tags:''' Turtlebot, Kinect, Augmented Reality, Robotics
 +
* '''Technologies:''' ROS, c++
 +
* '''Status:''' Finished
 +
 +
=Instalación de ROS=
 +
 +
Lo primero que se necesita es un ordenador con el sistema operativo [http://www.ubuntu.com ubuntu] instalado, ya que es el único soportado de forma oficial por [http://www.ros.org ROS]. Otras distribuciones de GNU/Linux y otros sistemas operativos como Windows también soportan a ROS pero solo de forma experimental.
 +
 +
La versión de [http://www.ros.org ROS] instalada por mi, es la versión "fuerte".
 +
Para instalar [http://www.ros.org ROS] y las herramientas para el robot [http://www.turtlebot.com turtlebot] se han de seguir los siguientes pasos:
 +
 +
 +
  • Primero se deben actualizar los repositorios y los paquetes del sistema.
 +
    sudo apt-get update
 +
    sudo apt-get upgrade
 +
 +
  • sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu precise main" >
 +
    /etc/apt/sources.list.d/ros-latest.list'
 +
 +
  • wget http://packages.ros.org/ros.key -O - | sudo apt-key add -
  
* '''Authors:''' David Llamas
+
  • sudo apt-get update
  
* '''Web of Authors:''':
+
  • sudo apt-get install ros-fuerte-desktop-full
  
* '''Academic Year:''' 2012-2013
+
  • sudo apt-get install ros-fuerte-turtlebot
  
* '''Degree:''' Bachelor
+
  • sudo apt-get install ros-fuerte-turtlebot-apps
  
* '''SVN Repositories:''' WIP
+
  • sudo apt-get install ros-fuerte-turtlebot-viz
  
* '''Tags:''' Turtlebot, Kinect, Augmented Reality, Robotics
+
  • sudo apt-get install ros-fuerte-turtlebot-simulator
  
* '''Technology:''' ROS, c++
+
  • echo "source /opt/ros/fuerte/setup.bash" >> ~/.bashrc
  
* '''State:''' WIP
+
  • sudo apt-get install python-setuptools python-pip
  
== '''Instalación de ROS''' ==
+
  • sudo pip install -U rosinstall vcstools rosdep
  
Lo primero que se necesita es un ordenador con el sistema operativo [http://www.ubuntu.com ubuntu] instalado, ya que es el único soportado por [http://www.ros.org ROS]. Los demás sistemas para los que esta disponible son solo experimentales.
+
  • sudo apt-get install chrony
  
La versión de [http://www.ros.org ROS] instalada por mi, es la versión "fuerte".
+
  • sudo ntpdate ntp.ubuntu.com
Para instalar [http://www.ros.org ROS] y las herramientas para el robot [http://www.turtlebot.com turtlebot] se pueden seguir las instrucciones que están disponibles [http://swarmlab.unimaas.nl/autonomous-systems/installation/ aquí].
 
  
 
Es importante, después de la instalación de los paquetes necesarios, configurar nuestro "workspace". Este será el sitio donde se guardarán todos nuestros programas escritos para ejecutar en nuestro robot.
 
Es importante, después de la instalación de los paquetes necesarios, configurar nuestro "workspace". Este será el sitio donde se guardarán todos nuestros programas escritos para ejecutar en nuestro robot.
 +
 
Para ello debemos crear una carpeta "ros_worspace" en nuestra carpeta personal y configurar las variables de entorno.
 
Para ello debemos crear una carpeta "ros_worspace" en nuestra carpeta personal y configurar las variables de entorno.
  
Line 36: Line 59:
 
'''Nota:'''En mi caso tuve problemas con la instalación de [http://www.ros.org ROS] y las variables de entorno no estaban bien definidas, problema que se soluciono usando enlaces simbólicos. De todas formas fue algo excepcional ya que en otro ordenador no tuve ningún problema.
 
'''Nota:'''En mi caso tuve problemas con la instalación de [http://www.ros.org ROS] y las variables de entorno no estaban bien definidas, problema que se soluciono usando enlaces simbólicos. De todas formas fue algo excepcional ya que en otro ordenador no tuve ningún problema.
  
 
+
=Instalación de Qt Creator=
 
 
== '''Instalación de Qt Creator''' ==
 
  
 
Para el pequeño proyecto que voy a realizar, que consiste en modificar el programa Myra para añadir en la ventana principal un botón que nos lance a otra ventana secundaria desde la cual poder teleoperar el robot "Turtlebot".
 
Para el pequeño proyecto que voy a realizar, que consiste en modificar el programa Myra para añadir en la ventana principal un botón que nos lance a otra ventana secundaria desde la cual poder teleoperar el robot "Turtlebot".
Line 51: Line 72:
 
Cuando iniciemos un proyecto con Qt Creator, tendremos que modificar el archivo "nombre de proyecto".pro para que las rutas donde busca los componentes de Opencv sean los correctos.
 
Cuando iniciemos un proyecto con Qt Creator, tendremos que modificar el archivo "nombre de proyecto".pro para que las rutas donde busca los componentes de Opencv sean los correctos.
  
Tambien necesitaremos instalar Aruco, que es usado para la relidad aumentada. Para ello se pueden seguir la instrucciones de la [http://www.uco.es/investiga/grupos/ava/node/26 pagina].
+
Tambien necesitaremos instalar Aruco, que es usado para la realidad aumentada. Para ello se pueden seguir la instrucciones de la [http://www.uco.es/investiga/grupos/ava/node/26 pagina].
 +
 
 +
=Aplicación de prueba=
 +
 
 +
Hemos creado un paquete de ROS, con la peculiaridad de que este paquete ya viene con una interfaz simple creada en Qt, la cual podremos modificar como más nos guste. También cuenta con una clase llamada "QNode" donde se podremos crear los nodos de ROS que necesitemos.
 +
 
 +
Para crear este paquete utilizamos el comando:
 +
 
 +
  • roscreate-qt-pkg
 +
 
 +
 
 +
El código de la clase "main_window", que es la interfaz gráfica, es el siguiente:
 +
 
 +
<syntaxhighlight lang="cpp" enclose="div">
 +
/**
 +
* @file /src/main_window.cpp
 +
*
 +
* @brief Implementation for the qt gui.
 +
*
 +
* @date February 2011
 +
**/
 +
/*****************************************************************************
 +
** Includes
 +
*****************************************************************************/
 +
 
 +
#include <QtGui>
 +
#include <QMessageBox>
 +
#include <iostream>
 +
#include <QString>
 +
#include "../include/qtTurtlebot/main_window.hpp"
 +
#include "../include/qtTurtlebot/turtlebotTeleop.h"
 +
 
 +
#include <ros/ros.h>
 +
#include <geometry_msgs/Twist.h>
 +
#include <signal.h>
 +
#include <termios.h>
 +
#include <stdio.h>
 +
#include "boost/thread/mutex.hpp"
 +
#include "boost/thread/thread.hpp"
 +
 
 +
/*****************************************************************************
 +
** Namespaces
 +
*****************************************************************************/
 +
 
 +
namespace qtTurtlebot {
 +
 
 +
using namespace Qt;
 +
 
 +
/*****************************************************************************
 +
** Implementation [MainWindow]
 +
*****************************************************************************/
 +
 
 +
MainWindow::MainWindow(int argc, char** argv, QWidget *parent)
 +
: QMainWindow(parent)
 +
, qnode(argc,argv)
 +
{
 +
ui.setupUi(this); // Calling this incidentally connects all ui's triggers to on_...() callbacks in this class.
 +
    QObject::connect(ui.actionAbout_Qt, SIGNAL(triggered(bool)), qApp, SLOT(aboutQt())); // qApp is a global variable for the application
 +
 
 +
    ReadSettings();
 +
setWindowIcon(QIcon(":/images/icon.png"));
 +
ui.tab_manager->setCurrentIndex(0); // ensure the first tab is showing - qt-designer should have this already hardwired, but often loses it (settings?).
 +
    QObject::connect(&qnode, SIGNAL(rosShutdown()), this, SLOT(close()));
 +
 
 +
/*********************
 +
** Logging
 +
**********************/
 +
ui.view_logging->setModel(qnode.loggingModel());
 +
    QObject::connect(&qnode, SIGNAL(loggingUpdated()), this, SLOT(updateLoggingView()));
 +
 
 +
    /*********************
 +
    ** Auto Start
 +
    **********************/
 +
    if ( ui.checkbox_remember_settings->isChecked() ) {
 +
        on_button_connect_clicked(true);
 +
    }
 +
 
 +
    //Conectando la señal de los botones a los slots apropiados
 +
    QObject::connect(ui.botonArriba, SIGNAL(clicked()),this, SLOT(botonArriba()));
 +
    QObject::connect(ui.botonDerecha, SIGNAL(clicked()),this, SLOT(botonDerecha()));
 +
    QObject::connect(ui.botonAbajo, SIGNAL(clicked()),this, SLOT(botonAbajo()));
 +
    QObject::connect(ui.botonIzquierda, SIGNAL(clicked()),this, SLOT(botonIzquierda()));
 +
 
 +
}
 +
 
 +
MainWindow::~MainWindow() {}
 +
 
 +
/*****************************************************************************
 +
** Implementation [Slots]
 +
*****************************************************************************/
 +
 
 +
 
 +
void MainWindow::showNoMasterMessage() {
 +
QMessageBox msgBox;
 +
msgBox.setText("Couldn't find the ros master.");
 +
msgBox.exec();
 +
    close();
 +
}
 +
 
 +
/*
 +
* These triggers whenever the button is clicked, regardless of whether it
 +
* is already checked or not.
 +
*/
 +
 
 +
void MainWindow::on_button_connect_clicked(bool check ) {
 +
if ( ui.checkbox_use_environment->isChecked() ) {
 +
if ( !qnode.init() ) {
 +
showNoMasterMessage();
 +
} else {
 +
ui.button_connect->setEnabled(false);
 +
}
 +
} else {
 +
if ( ! qnode.init(ui.line_edit_master->text().toStdString(),
 +
  ui.line_edit_host->text().toStdString()) ) {
 +
showNoMasterMessage();
 +
} else {
 +
ui.button_connect->setEnabled(false);
 +
ui.line_edit_master->setReadOnly(true);
 +
ui.line_edit_host->setReadOnly(true);
 +
ui.line_edit_topic->setReadOnly(true);
 +
}
 +
}
 +
}
 +
 
 +
 
 +
void MainWindow::on_checkbox_use_environment_stateChanged(int state) {
 +
bool enabled;
 +
if ( state == 0 ) {
 +
enabled = true;
 +
} else {
 +
enabled = false;
 +
}
 +
ui.line_edit_master->setEnabled(enabled);
 +
ui.line_edit_host->setEnabled(enabled);
 +
//ui.line_edit_topic->setEnabled(enabled);
 +
}
 +
 
 +
/*****************************************************************************
 +
** Implemenation [Slots][manually connected]
 +
*****************************************************************************/
 +
 
 +
/**
 +
* This function is signalled by the underlying model. When the model changes,
 +
* this will drop the cursor down to the last line in the QListview to ensure
 +
* the user can always see the latest log message.
 +
*/
 +
void MainWindow::updateLoggingView() {
 +
        ui.view_logging->scrollToBottom();
 +
}
 +
 
 +
/*****************************************************************************
 +
** Implementation [Menu]
 +
*****************************************************************************/
 +
 
 +
void MainWindow::on_actionAbout_triggered() {
 +
    QMessageBox::about(this, tr("About ..."),tr("<h2>PACKAGE_NAME Test Program 0.10</h2><p>Copyright Yujin Robot</p><p>This package needs an about description.</p>"));
 +
}
 +
 
 +
 
 +
 
 +
 
 +
void MainWindow::handleButton(){
 +
    QMessageBox::about(this, tr("MENSAJE  ..."),tr("<h2>WARNING</h2><p>Copyright Yujin Robot</p><p>This package needs an about description.</p>"));
 +
}
 +
 
 +
void MainWindow::botonAbajo(){
 +
    qnode.publicar(0,-1.0);
 +
}
 +
 
 +
void MainWindow::botonArriba(){
 +
    qnode.publicar(0,1.0);
 +
}
 +
 
 +
void MainWindow::botonDerecha(){
 +
    qnode.publicar(-1.0,0);
 +
}
 +
 
 +
void MainWindow::botonIzquierda(){
 +
    qnode.publicar(1.0,0);
 +
}
 +
 
 +
/*****************************************************************************
 +
** Implementation [Configuration]
 +
*****************************************************************************/
 +
 
 +
void MainWindow::ReadSettings() {
 +
    QSettings settings("Qt-Ros Package", "qtTurtlebot");
 +
    restoreGeometry(settings.value("geometry").toByteArray());
 +
    restoreState(settings.value("windowState").toByteArray());
 +
    QString master_url = settings.value("master_url",QString("http://192.168.1.2:11311/")).toString();
 +
    QString host_url = settings.value("host_url", QString("192.168.1.3")).toString();
 +
    //QString topic_name = settings.value("topic_name", QString("/chatter")).toString();
 +
    ui.line_edit_master->setText(master_url);
 +
    ui.line_edit_host->setText(host_url);
 +
    //ui.line_edit_topic->setText(topic_name);
 +
    bool remember = settings.value("remember_settings", false).toBool();
 +
    ui.checkbox_remember_settings->setChecked(remember);
 +
    bool checked = settings.value("use_environment_variables", false).toBool();
 +
    ui.checkbox_use_environment->setChecked(checked);
 +
    if ( checked ) {
 +
    ui.line_edit_master->setEnabled(false);
 +
    ui.line_edit_host->setEnabled(false);
 +
    //ui.line_edit_topic->setEnabled(false);
 +
    }
 +
}
 +
 
 +
void MainWindow::WriteSettings() {
 +
    QSettings settings("Qt-Ros Package", "qtTurtlebot");
 +
    settings.setValue("master_url",ui.line_edit_master->text());
 +
    settings.setValue("host_url",ui.line_edit_host->text());
 +
    //settings.setValue("topic_name",ui.line_edit_topic->text());
 +
    settings.setValue("use_environment_variables",QVariant(ui.checkbox_use_environment->isChecked()));
 +
    settings.setValue("geometry", saveGeometry());
 +
    settings.setValue("windowState", saveState());
 +
    settings.setValue("remember_settings",QVariant(ui.checkbox_remember_settings->isChecked()));
 +
 
 +
}
 +
 
 +
void MainWindow::closeEvent(QCloseEvent *event)
 +
{
 +
WriteSettings();
 +
QMainWindow::closeEvent(event);
 +
}
 +
 
 +
}  // namespace qtTurtlebot
 +
 
 +
</syntaxhighlight>
 +
 
 +
 
 +
Y este es el código de la clase "qnode", que es la clase donde se crean los nodos de ROS y desde la cual se establecen las comunicaciones con el robot:
 +
 
 +
<syntaxhighlight lang="cpp" enclose="div">
 +
/**
 +
* @file /src/qnode.cpp
 +
*
 +
* @brief Ros communication central!
 +
*
 +
* @date February 2011
 +
**/
 +
 
 +
/*****************************************************************************
 +
** Includes
 +
*****************************************************************************/
 +
 
 +
#include <ros/ros.h>
 +
#include <ros/network.h>
 +
#include <string>
 +
#include <std_msgs/String.h>
 +
#include <sstream>
 +
#include "../include/qtTurtlebot/qnode.hpp"
 +
 
 +
/*****************************************************************************
 +
** Namespaces
 +
*****************************************************************************/
 +
 
 +
namespace qtTurtlebot {
 +
 
 +
/*****************************************************************************
 +
** Implementation
 +
*****************************************************************************/
 +
 
 +
QNode::QNode(int argc, char** argv ) :
 +
init_argc(argc),
 +
init_argv(argv)
 +
{}
 +
 
 +
QNode::~QNode() {
 +
if(ros::isStarted()) {
 +
  ros::shutdown(); // explicitly needed since we use ros::start();
 +
  ros::waitForShutdown();
 +
}
 +
wait();
 +
}
 +
 
 +
bool QNode::init() {
 +
ros::init(init_argc,init_argv,"qtTurtlebot");
 +
if ( ! ros::master::check() ) {
 +
    return false;
 +
}
 +
ros::start(); // explicitly needed since our nodehandle is going out of scope.
 +
ros::NodeHandle n, nh_, ph_;
 +
 
 +
// Add your ros communications here.
 +
 
 +
//Inicializando variables de turtlebotTeleop
 +
//ph_ = "~";
 +
linear_ = 0;
 +
angular_ = 0;
 +
l_scale_ = 1.0;
 +
a_scale_ = 1.0;
 +
 
 +
ph_.param("scale_angular", a_scale_, a_scale_);
 +
ph_.param("scale_linear", l_scale_, l_scale_);
 +
 
 +
vel_pub_ = nh_.advertise<geometry_msgs::Twist>("cmd_vel", 1);
 +
 
 +
//Resto del main de turtlebotTeleop
 +
//signal(SIGINT,quit);
 +
 
 +
//boost::thread my_thread(boost::bind(&QNode::keyLoop, &QNode));
 +
 
 +
//ros::Timer timer = n.createTimer(ros::Duration(0.1), boost::bind(&QNode::watchdog, &QNode));
 +
 
 +
//my_thread.interrupt() ;
 +
//my_thread.join() ;
 +
 
 +
start();
 +
return true;
 +
}
 +
 
 +
bool QNode::init(const std::string &master_url, const std::string &host_url) {
 +
std::map<std::string,std::string> remappings;
 +
remappings["__master"] = master_url;
 +
remappings["__hostname"] = host_url;
 +
ros::init(remappings,"qtTurtlebot");
 +
if ( ! ros::master::check() ) {
 +
    return false;
 +
}
 +
ros::start(); // explicitly needed since our nodehandle is going out of scope.
 +
ros::NodeHandle n, nh_, ph_;
 +
// Add your ros communications here.
 +
 
 +
//Inicializando variables de turtlebotTeleop
 +
//ph_ = "_";
 +
linear_ = 0;
 +
angular_ = 0;
 +
l_scale_ = 1.0;
 +
a_scale_ = 1.0;
 +
 
 +
ph_.param("scale_angular", a_scale_, a_scale_);
 +
ph_.param("scale_linear", l_scale_, l_scale_);
 +
 
 +
vel_pub_ = nh_.advertise<geometry_msgs::Twist>("cmd_vel", 1);
 +
 
 +
//Resto del main de turtlebotTeleop
 +
//signal(SIGINT,quit);
 +
 
 +
//boost::thread my_thread(boost::bind(&QNode::keyLoop, &QNode));
 +
 
 +
//ros::Timer timer = n.createTimer(ros::Duration(0.1), boost::bind(&QNode::watchdog, &QNode));
 +
 
 +
//my_thread.interrupt() ;
 +
//my_thread.join() ;
 +
 
 +
start();
 +
return true;
 +
}
 +
 
 +
void QNode::run() {
 +
ros::Rate loop_rate(1);
 +
//int count = 0;
 +
while ( ros::ok() ) {
 +
 
 +
  // std_msgs::String msg;
 +
  // std::stringstream ss;
 +
  // ss << "hello world " << count;
 +
    //msg.data = ss.str();
 +
    //chatter_publisher.publish(msg);
 +
    //log(Info,std::string("I sent: ")+msg.data);
 +
    ros::spinOnce();
 +
    loop_rate.sleep();
 +
    //++count;
 +
}
 +
std::cout << "Ros shutdown, proceeding to close the gui." << std::endl;
 +
Q_EMIT rosShutdown(); // used to signal the gui for a shutdown (useful to roslaunch)
 +
}
 +
 
 +
 
 +
void QNode::log( const LogLevel &level, const std::string &msg) {
 +
logging_model.insertRows(logging_model.rowCount(),1);
 +
std::stringstream logging_model_msg;
 +
switch ( level ) {
 +
    case(Debug) : {
 +
            ROS_DEBUG_STREAM(msg);
 +
            logging_model_msg << "[DEBUG] [" << ros::Time::now() << "]: " << msg;
 +
            break;
 +
    }
 +
    case(Info) : {
 +
            ROS_INFO_STREAM(msg);
 +
            logging_model_msg << "[INFO] [" << ros::Time::now() << "]: " << msg;
 +
            break;
 +
    }
 +
    case(Warn) : {
 +
            ROS_WARN_STREAM(msg);
 +
            logging_model_msg << "[INFO] [" << ros::Time::now() << "]: " << msg;
 +
            break;
 +
    }
 +
    case(Error) : {
 +
            ROS_ERROR_STREAM(msg);
 +
            logging_model_msg << "[ERROR] [" << ros::Time::now() << "]: " << msg;
 +
            break;
 +
    }
 +
    case(Fatal) : {
 +
            ROS_FATAL_STREAM(msg);
 +
            logging_model_msg << "[FATAL] [" << ros::Time::now() << "]: " << msg;
 +
            break;
 +
    }
 +
}
 +
QVariant new_row(QString(logging_model_msg.str().c_str()));
 +
logging_model.setData(logging_model.index(logging_model.rowCount()-1),new_row);
 +
Q_EMIT loggingUpdated(); // used to readjust the scrollbar
 +
}
 +
 
 +
void QNode::publicar(double angular, double linear){
 +
    publish(angular, linear);
 +
}
 +
 
 +
void QNode::publish(double angular, double linear)
 +
{
 +
    geometry_msgs::Twist vel;
 +
    vel.angular.z = a_scale_*angular;
 +
    vel.linear.x = l_scale_*linear;
 +
 
 +
    vel_pub_.publish(vel);
 +
 
 +
 
 +
  return;
 +
}
 +
 
 +
 
 +
}  // namespace qtTurtlebot
 +
</syntaxhighlight>
 +
 
 +
 
 +
Con la creación de este programa de prueba se ha conseguido crear un interfaz desde la cual se puede controlar el movimiento del robot Turtlebot.

Latest revision as of 09:21, 25 June 2014

  • Project Name: TFM-ROS03
  • Author: David Llamas Abad
  • Academic Year: 2012-2013
  • Degree: Undergraduate
  • Tags: Turtlebot, Kinect, Augmented Reality, Robotics
  • Technologies: ROS, c++
  • Status: Finished

Instalación de ROS

Lo primero que se necesita es un ordenador con el sistema operativo ubuntu instalado, ya que es el único soportado de forma oficial por ROS. Otras distribuciones de GNU/Linux y otros sistemas operativos como Windows también soportan a ROS pero solo de forma experimental.

La versión de ROS instalada por mi, es la versión "fuerte". Para instalar ROS y las herramientas para el robot turtlebot se han de seguir los siguientes pasos:


 • Primero se deben actualizar los repositorios y los paquetes del sistema.
   sudo apt-get update
   sudo apt-get upgrade
 • sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu precise main" >
   /etc/apt/sources.list.d/ros-latest.list'
 • wget http://packages.ros.org/ros.key -O - | sudo apt-key add -
 • sudo apt-get update
 • sudo apt-get install ros-fuerte-desktop-full
 • sudo apt-get install ros-fuerte-turtlebot
 • sudo apt-get install ros-fuerte-turtlebot-apps
 • sudo apt-get install ros-fuerte-turtlebot-viz
 • sudo apt-get install ros-fuerte-turtlebot-simulator
 • echo "source /opt/ros/fuerte/setup.bash" >> ~/.bashrc
 • sudo apt-get install python-setuptools python-pip
 • sudo pip install -U rosinstall vcstools rosdep
 • sudo apt-get install chrony
 • sudo ntpdate ntp.ubuntu.com

Es importante, después de la instalación de los paquetes necesarios, configurar nuestro "workspace". Este será el sitio donde se guardarán todos nuestros programas escritos para ejecutar en nuestro robot.

Para ello debemos crear una carpeta "ros_worspace" en nuestra carpeta personal y configurar las variables de entorno.

cd 
mkdir ros_workspace
echo "ROS_PACKAGE_PATH=~/ros:$ROS_PACKAGE_PATH" >> ~/.bashrc
echo "ROS_WORKSPACE=~/ros" >> ~/.bashrc

Nota:En mi caso tuve problemas con la instalación de ROS y las variables de entorno no estaban bien definidas, problema que se soluciono usando enlaces simbólicos. De todas formas fue algo excepcional ya que en otro ordenador no tuve ningún problema.

Instalación de Qt Creator

Para el pequeño proyecto que voy a realizar, que consiste en modificar el programa Myra para añadir en la ventana principal un botón que nos lance a otra ventana secundaria desde la cual poder teleoperar el robot "Turtlebot".

El primer paso es instalar Qt Creator, que es el IDE que voy a utilizar para desarrollar este proyecto.

sudo aptitude install qtcreator

Necesitamos tener instalado Opencv, nosotros ya lo tenemos instalado pero dentro de la instalación de ROs, asi que las rutas estaran cambiadas. Cuando iniciemos un proyecto con Qt Creator, tendremos que modificar el archivo "nombre de proyecto".pro para que las rutas donde busca los componentes de Opencv sean los correctos.

Tambien necesitaremos instalar Aruco, que es usado para la realidad aumentada. Para ello se pueden seguir la instrucciones de la pagina.

Aplicación de prueba

Hemos creado un paquete de ROS, con la peculiaridad de que este paquete ya viene con una interfaz simple creada en Qt, la cual podremos modificar como más nos guste. También cuenta con una clase llamada "QNode" donde se podremos crear los nodos de ROS que necesitemos.

Para crear este paquete utilizamos el comando:

 • roscreate-qt-pkg


El código de la clase "main_window", que es la interfaz gráfica, es el siguiente:

/**
 * @file /src/main_window.cpp
 *
 * @brief Implementation for the qt gui.
 *
 * @date February 2011
 **/
/*****************************************************************************
** Includes
*****************************************************************************/

#include <QtGui>
#include <QMessageBox>
#include <iostream>
#include <QString>
#include "../include/qtTurtlebot/main_window.hpp"
#include "../include/qtTurtlebot/turtlebotTeleop.h"

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <signal.h>
#include <termios.h>
#include <stdio.h>
#include "boost/thread/mutex.hpp"
#include "boost/thread/thread.hpp"

/*****************************************************************************
** Namespaces
*****************************************************************************/

namespace qtTurtlebot {

using namespace Qt;

/*****************************************************************************
** Implementation [MainWindow]
*****************************************************************************/

MainWindow::MainWindow(int argc, char** argv, QWidget *parent)
	: QMainWindow(parent)
	, qnode(argc,argv)
{
	ui.setupUi(this); // Calling this incidentally connects all ui's triggers to on_...() callbacks in this class.
    QObject::connect(ui.actionAbout_Qt, SIGNAL(triggered(bool)), qApp, SLOT(aboutQt())); // qApp is a global variable for the application

    ReadSettings();
	setWindowIcon(QIcon(":/images/icon.png"));
	ui.tab_manager->setCurrentIndex(0); // ensure the first tab is showing - qt-designer should have this already hardwired, but often loses it (settings?).
    QObject::connect(&qnode, SIGNAL(rosShutdown()), this, SLOT(close()));

	/*********************
	** Logging
	**********************/
	ui.view_logging->setModel(qnode.loggingModel());
    QObject::connect(&qnode, SIGNAL(loggingUpdated()), this, SLOT(updateLoggingView()));

    /*********************
    ** Auto Start
    **********************/
    if ( ui.checkbox_remember_settings->isChecked() ) {
        on_button_connect_clicked(true);
    }

    //Conectando la señal de los botones a los slots apropiados
    QObject::connect(ui.botonArriba, SIGNAL(clicked()),this, SLOT(botonArriba()));
    QObject::connect(ui.botonDerecha, SIGNAL(clicked()),this, SLOT(botonDerecha()));
    QObject::connect(ui.botonAbajo, SIGNAL(clicked()),this, SLOT(botonAbajo()));
    QObject::connect(ui.botonIzquierda, SIGNAL(clicked()),this, SLOT(botonIzquierda()));

}

MainWindow::~MainWindow() {}

/*****************************************************************************
** Implementation [Slots]
*****************************************************************************/


void MainWindow::showNoMasterMessage() {
	QMessageBox msgBox;
	msgBox.setText("Couldn't find the ros master.");
	msgBox.exec();
    close();
}

/*
 * These triggers whenever the button is clicked, regardless of whether it
 * is already checked or not.
 */

void MainWindow::on_button_connect_clicked(bool check ) {
	if ( ui.checkbox_use_environment->isChecked() ) {
		if ( !qnode.init() ) {
			showNoMasterMessage();
		} else {
			ui.button_connect->setEnabled(false);
		}
	} else {
		if ( ! qnode.init(ui.line_edit_master->text().toStdString(),
				   ui.line_edit_host->text().toStdString()) ) {
			showNoMasterMessage();
		} else {
			ui.button_connect->setEnabled(false);
			ui.line_edit_master->setReadOnly(true);
			ui.line_edit_host->setReadOnly(true);
			ui.line_edit_topic->setReadOnly(true);
		}
	}
}


void MainWindow::on_checkbox_use_environment_stateChanged(int state) {
	bool enabled;
	if ( state == 0 ) {
		enabled = true;
	} else {
		enabled = false;
	}
	ui.line_edit_master->setEnabled(enabled);
	ui.line_edit_host->setEnabled(enabled);
	//ui.line_edit_topic->setEnabled(enabled);
}

/*****************************************************************************
** Implemenation [Slots][manually connected]
*****************************************************************************/

/**
 * This function is signalled by the underlying model. When the model changes,
 * this will drop the cursor down to the last line in the QListview to ensure
 * the user can always see the latest log message.
 */
void MainWindow::updateLoggingView() {
        ui.view_logging->scrollToBottom();
}

/*****************************************************************************
** Implementation [Menu]
*****************************************************************************/

void MainWindow::on_actionAbout_triggered() {
    QMessageBox::about(this, tr("About ..."),tr("<h2>PACKAGE_NAME Test Program 0.10</h2><p>Copyright Yujin Robot</p><p>This package needs an about description.</p>"));
}




void MainWindow::handleButton(){
    QMessageBox::about(this, tr("MENSAJE  ..."),tr("<h2>WARNING</h2><p>Copyright Yujin Robot</p><p>This package needs an about description.</p>"));
}

void MainWindow::botonAbajo(){
    qnode.publicar(0,-1.0);
}

void MainWindow::botonArriba(){
    qnode.publicar(0,1.0);
}

void MainWindow::botonDerecha(){
    qnode.publicar(-1.0,0);
}

void MainWindow::botonIzquierda(){
    qnode.publicar(1.0,0);
}

/*****************************************************************************
** Implementation [Configuration]
*****************************************************************************/

void MainWindow::ReadSettings() {
    QSettings settings("Qt-Ros Package", "qtTurtlebot");
    restoreGeometry(settings.value("geometry").toByteArray());
    restoreState(settings.value("windowState").toByteArray());
    QString master_url = settings.value("master_url",QString("http://192.168.1.2:11311/")).toString();
    QString host_url = settings.value("host_url", QString("192.168.1.3")).toString();
    //QString topic_name = settings.value("topic_name", QString("/chatter")).toString();
    ui.line_edit_master->setText(master_url);
    ui.line_edit_host->setText(host_url);
    //ui.line_edit_topic->setText(topic_name);
    bool remember = settings.value("remember_settings", false).toBool();
    ui.checkbox_remember_settings->setChecked(remember);
    bool checked = settings.value("use_environment_variables", false).toBool();
    ui.checkbox_use_environment->setChecked(checked);
    if ( checked ) {
    	ui.line_edit_master->setEnabled(false);
    	ui.line_edit_host->setEnabled(false);
    	//ui.line_edit_topic->setEnabled(false);
    }
}

void MainWindow::WriteSettings() {
    QSettings settings("Qt-Ros Package", "qtTurtlebot");
    settings.setValue("master_url",ui.line_edit_master->text());
    settings.setValue("host_url",ui.line_edit_host->text());
    //settings.setValue("topic_name",ui.line_edit_topic->text());
    settings.setValue("use_environment_variables",QVariant(ui.checkbox_use_environment->isChecked()));
    settings.setValue("geometry", saveGeometry());
    settings.setValue("windowState", saveState());
    settings.setValue("remember_settings",QVariant(ui.checkbox_remember_settings->isChecked()));

}

void MainWindow::closeEvent(QCloseEvent *event)
{
	WriteSettings();
	QMainWindow::closeEvent(event);
}

}  // namespace qtTurtlebot


Y este es el código de la clase "qnode", que es la clase donde se crean los nodos de ROS y desde la cual se establecen las comunicaciones con el robot:

/**
* @file /src/qnode.cpp
*
* @brief Ros communication central!
*
* @date February 2011
**/

/*****************************************************************************
** Includes
*****************************************************************************/

#include <ros/ros.h>
#include <ros/network.h>
#include <string>
#include <std_msgs/String.h>
#include <sstream>
#include "../include/qtTurtlebot/qnode.hpp"

/*****************************************************************************
** Namespaces
*****************************************************************************/

namespace qtTurtlebot {

/*****************************************************************************
** Implementation
*****************************************************************************/

QNode::QNode(int argc, char** argv ) :
init_argc(argc),
init_argv(argv)
{}

QNode::~QNode() {
if(ros::isStarted()) {
  ros::shutdown(); // explicitly needed since we use ros::start();
  ros::waitForShutdown();
}
wait();
}

bool QNode::init() {
ros::init(init_argc,init_argv,"qtTurtlebot");
if ( ! ros::master::check() ) {
    return false;
}
ros::start(); // explicitly needed since our nodehandle is going out of scope.
ros::NodeHandle n, nh_, ph_;

// Add your ros communications here.

//Inicializando variables de turtlebotTeleop
//ph_ = "~";
linear_ = 0;
angular_ = 0;
l_scale_ = 1.0;
a_scale_ = 1.0;

ph_.param("scale_angular", a_scale_, a_scale_);
ph_.param("scale_linear", l_scale_, l_scale_);

vel_pub_ = nh_.advertise<geometry_msgs::Twist>("cmd_vel", 1);

//Resto del main de turtlebotTeleop
//signal(SIGINT,quit);

//boost::thread my_thread(boost::bind(&QNode::keyLoop, &QNode));

//ros::Timer timer = n.createTimer(ros::Duration(0.1), boost::bind(&QNode::watchdog, &QNode));

//my_thread.interrupt() ;
//my_thread.join() ;

start();
return true;
}

bool QNode::init(const std::string &master_url, const std::string &host_url) {
std::map<std::string,std::string> remappings;
remappings["__master"] = master_url;
remappings["__hostname"] = host_url;
ros::init(remappings,"qtTurtlebot");
if ( ! ros::master::check() ) {
    return false;
}
ros::start(); // explicitly needed since our nodehandle is going out of scope.
ros::NodeHandle n, nh_, ph_;
// Add your ros communications here.

//Inicializando variables de turtlebotTeleop
//ph_ = "_";
linear_ = 0;
angular_ = 0;
l_scale_ = 1.0;
a_scale_ = 1.0;

ph_.param("scale_angular", a_scale_, a_scale_);
ph_.param("scale_linear", l_scale_, l_scale_);

vel_pub_ = nh_.advertise<geometry_msgs::Twist>("cmd_vel", 1);

//Resto del main de turtlebotTeleop
//signal(SIGINT,quit);

//boost::thread my_thread(boost::bind(&QNode::keyLoop, &QNode));

//ros::Timer timer = n.createTimer(ros::Duration(0.1), boost::bind(&QNode::watchdog, &QNode));

//my_thread.interrupt() ;
//my_thread.join() ;

start();
return true;
}

void QNode::run() {
ros::Rate loop_rate(1);
//int count = 0;
while ( ros::ok() ) {

   // std_msgs::String msg;
   // std::stringstream ss;
   // ss << "hello world " << count;
    //msg.data = ss.str();
    //chatter_publisher.publish(msg);
    //log(Info,std::string("I sent: ")+msg.data);
    ros::spinOnce();
    loop_rate.sleep();
    //++count;
}
std::cout << "Ros shutdown, proceeding to close the gui." << std::endl;
Q_EMIT rosShutdown(); // used to signal the gui for a shutdown (useful to roslaunch)
}


void QNode::log( const LogLevel &level, const std::string &msg) {
logging_model.insertRows(logging_model.rowCount(),1);
std::stringstream logging_model_msg;
switch ( level ) {
    case(Debug) : {
            ROS_DEBUG_STREAM(msg);
            logging_model_msg << "[DEBUG] [" << ros::Time::now() << "]: " << msg;
            break;
    }
    case(Info) : {
            ROS_INFO_STREAM(msg);
            logging_model_msg << "[INFO] [" << ros::Time::now() << "]: " << msg;
            break;
    }
    case(Warn) : {
            ROS_WARN_STREAM(msg);
            logging_model_msg << "[INFO] [" << ros::Time::now() << "]: " << msg;
            break;
    }
    case(Error) : {
            ROS_ERROR_STREAM(msg);
            logging_model_msg << "[ERROR] [" << ros::Time::now() << "]: " << msg;
            break;
    }
    case(Fatal) : {
            ROS_FATAL_STREAM(msg);
            logging_model_msg << "[FATAL] [" << ros::Time::now() << "]: " << msg;
            break;
    }
}
QVariant new_row(QString(logging_model_msg.str().c_str()));
logging_model.setData(logging_model.index(logging_model.rowCount()-1),new_row);
Q_EMIT loggingUpdated(); // used to readjust the scrollbar
}

void QNode::publicar(double angular, double linear){
    publish(angular, linear);
}

void QNode::publish(double angular, double linear)
{
    geometry_msgs::Twist vel;
    vel.angular.z = a_scale_*angular;
    vel.linear.x = l_scale_*linear;

    vel_pub_.publish(vel);


  return;
}


}  // namespace qtTurtlebot


Con la creación de este programa de prueba se ha conseguido crear un interfaz desde la cual se puede controlar el movimiento del robot Turtlebot.