ros tutorial

Acciones en ROS (Parte 2)

Ros_melodic

En la primera parte de esta entrada creamos el servidor, en la segunda parte vamos a crear el cliente de nuestra acción y vamos a ejecutarla. Si quieres ver el código de la entrada anterior consulta nuestro GitHub. Y si quieres puedes ver la info de la wiki

ruleta_acciones_ROS
Diagrama de aprendizaje

Creando el cliente de la acción

Dentro de la carpeta src de nuestro paquete, crearemos un archivo llamado cliente.cpp en el que alojaremos el servidor de nuestra acción.

Recuerda que estamos haciendo uso de la librería actionlib y del mensaje creado por nosotros mismos para realizar la acción. Además del servidor definido en la entrada anterior

El código es el siguiente, recuerda que puedes acceder a él en nuestro GitHub

#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>

#include <entrada_acciones_mensajes/ContadorAction.h>
#include <entrada_acciones_mensajes/ContadorGoal.h>
#include <entrada_acciones_mensajes/ContadorResult.h>
#include <entrada_acciones_mensajes/ContadorFeedback.h>

class ContadorCliente{

    protected:
	ros::NodeHandle _nh;
	actionlib::SimpleActionClient<entrada_acciones_mensajes::ContadorAction> _ac;

	public:
	ContadorCliente():
		_ac("/contador", true)
	{
		ROS_INFO("Wait for the action server to start...");
		_ac.waitForServer();
		ROS_INFO("Server is now up.");
	}

    void sendGoal() {
		entrada_acciones_mensajes::ContadorGoal goal;
		goal.objetivo = 12;
		_ac.sendGoal(goal, 
			boost::bind(&ContadorCliente::doneCb, this, _1, _2),
			boost::bind(&ContadorCliente::activeCb, this),
			boost::bind(&ContadorCliente::feedbackCb, this, _1));
		ROS_INFO("Goal has been sent.");

		// Uncomment to cancel the goal after 2 seconds
		//ros::Duration(2.0).sleep();
		//_ac.cancelGoal();
	}

	void doneCb(const actionlib::SimpleClientGoalState& state,
			const entrada_acciones_mensajes::ContadorResultConstPtr &result) 
	{
		ROS_INFO("Finished in state: %s", 
			state.toString().c_str());
		ROS_INFO("Count result: %d", (int)result->contador);
	}

	void activeCb() {
		ROS_INFO("Goal just went active");
	}

	void feedbackCb(const entrada_acciones_mensajes::ContadorFeedbackConstPtr &feedback) 
	{
		ROS_INFO("Feedback received. Percentage: %lf", 
			feedback->proporcion);
	}


};

int main (int argc, char **argv) {
	ros::init(argc, argv, "count_until_client");
	ContadorCliente cliente;
	cliente.sendGoal();
	ros::spin();
}

Con #include <ros/ros.h> cargamos la librería interna de ROS para C++.Luego cargamos la librería actionlib que nos ayudará a crear el cliente de nuestra acción.

Incluimos también el mensaje creado por nosotros

#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>

#include <entrada_acciones_mensajes/ContadorAction.h>
#include <entrada_acciones_mensajes/ContadorGoal.h>
#include <entrada_acciones_mensajes/ContadorResult.h>
#include <entrada_acciones_mensajes/ContadorFeedback.h>

Al igual que para el servidor creamos un clase, en este caso llamada ContadorCliente

actionlib::SimpleActionClient<entrada_acciones_mensajes::ContadorAction> _ac;

Creamos un cliente para nuestra acción _ac y le decimos que el mensaje a usar es del tipo  <entrada_acciones_mensajes::ContadorAction>

Ahora en el constructor de la clase se le pasa el nombre de la accion y se pone al cliente en estado de espera hasta que el servidor de la acción este activo.

_ac.waitForServer();

Creamos la función sendGoal(), función en la que definimos el goal que posteriormente se le pasará al servidor. además dentro de esta acción mandamos este valor de goal a través del cliente _ac

_ac.sendGoal(goal, 

Y en función del estado de nuestra acción, es decir si está acabada ejecutaremos una callback determinada (doneCb), si está activa ejecutaremos activeCb, si está ejecutaándose mostraremos el feedback (feedbackCb) etc..

boost::bind(&ContadorCliente::doneCb, this, _1, _2),
			boost::bind(&ContadorCliente::activeCb, this),
			boost::bind(&ContadorCliente::feedbackCb, this, _1));

Ahora definimos cada función Cb por separado, aquí la función doneCb

void doneCb(const actionlib::SimpleClientGoalState& state,
			const entrada_acciones_mensajes::ContadorResultConstPtr &result) 
	{
		ROS_INFO("Finished in state: %s", 
			state.toString().c_str());
		ROS_INFO("Count result: %d", (int)result->contador);
	}

Aquí la función activeCb

void activeCb() {
		ROS_INFO("Goal just went active");
	}

Y por último la función feedbackCb encargada de obtener el valor del feedback que gestiona el servidor de la acción.

void activeCb() {
		ROS_INFO("Goal just went active");
	}

Ahora y tal y como hemos hecho con el servidor en la entrada anterior, debemos modificar el archivo CmakeLists.txt de nuestro paquete, pero como ya lo hemos echo antes, sólo nos falta añadir el ejecutable y las librerías.

add_executable(contador_cliente src/cliente.cpp)
target_link_libraries(contador_cliente ${catkin_LIBRARIES})

De acuerdo, ya tenemos nuestra acción montada, no te olvides de escribir catkin_make en una terminal para construir correctamente el paquete.

 

Si ahora escribiésemos primero

$roscore

Y luego:

$rosrun entrada_acciones contador_servidor

Y ahora en otra terminal distinta ejecutamos el cliente de la acción que le pasará el goal al servidor:

$rosrun entrada_acciones contador_cliente

Resultando en la terminal:

consola_ROS

Es decir, nuestra acción se ha ejecutado gracias a que el cliente de la acción le ha pasado un objetivo o goal al servidor de la acción. Este servidor al comprobar que la acción ni está acabada, ni se ha mandado cancelar, va a devolver el feedback al cliente. Y este cliente nos va a pasar el valor del feedback por pantalla.

En cuanto se llega al valor objetivo el servidor finaliza la acción.

Si ahora una vez que hemos ejecutado la acción y vemos los topics que hay por pantalla

rostopic

Así vemos que en realidad hemos publicado 5 topics, pero la librería actionlib nos está ayudando y hace que nos olvidemos de ello facilitándonos mucho la vida.

Pues bien hasta aquí la entrada de acciones de ROS. Pronto empezaremos a aplicar estos conocimientos en un caso práctico.

Hasta la próxima!!!!!

Subscríbete a nuestro blog

ROS_custom_message

10 ROS Custom Message

ROS Custom Message Fundamentos de ROS Accede a otros posts En tutoriales anteriores a la hora de la comunicación pub/sub, siempre hemos usado mensajes predefinidos

Read More »

This website uses cookies to ensure you get the best experience on our website. By continuing to browse on this website, you accept the use of cookies for the above purposes.