-1

Im using Gazebo 9 and ROS melodic for some UUV Simulation. I created a ROS Service that pass the IMU sensors values from the Server to Client. Now I would like to use this service as a sensor feedback to the controller every time I control the UUV( means every time I press the joystick). Here are the Server and Client Node and the .srv files first

Server

#include "ros/ros.h"
#include <sensor_msgs/Imu.h>
#include "imu_service/ImuValue.h"

ros::ServiceServer service;
double current_x_orientation_s;
double get_imu_orientation_x;

bool get_val(imu_service::ImuValue::Request  &req, imu_service::ImuValue::Response &res)
{
    
    ROS_INFO("sending back response");    
    res.current_x_orientation_s = get_imu_orientation_x;
    //.. same for the other IMU values
        
}

void imuCallback(const  sensor_msgs::ImuConstPtr& msg)
{
  
     current_x_orientation_s= msg->orientation.x;
     get_imu_orientation_x=current_x_orientation_s;
     // ..same for other IMU values
           
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "imu_status_server");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("/thrbot/imu", 10, imuCallback);
  service = n.advertiseService("imu_status_server", get_val);
  ROS_INFO("Starting server...");
  ros::spin();
  return 0;
}

the Client is here

#include "ros/ros.h"
#include "ros_services/ImuValue.h"
#include <cstdlib>
#include <sensor_msgs/Joy.h>

ros::ServiceClient client;


void joystick_callback(const sensor_msgs::Joy::ConstPtr& joy)
{
  auto button_pressed = joy->buttons[0]; // 0 is the 'A' button on a wired xbox 360 controller
  if(button_pressed){
    ros_services::ImuValue srv;
    client.call(srv); 
    std::cout << "Got accel x: " << srv.response.current_x_orientation_s << std::endl;
  }
}


int main(int argc, char **argv)
{
        ros::init(argc,argv,"imu_client_node");
        ros::NodeHandle n;
        ros::NodeHandle nh_;
        ros::Subscriber joy_sub_ = nh_.subscribe<sensor_msgs::Joy>("joy", 10, joystick_callback);
    client = n.serviceClient<ros_services::ImuValue>("imu_status_server");
    ros_services::ImuValue srv;
    client.call(srv);       
    std::cout << "Got accel x: " << srv.response.current_x_orientation_s << std::endl;

        if (client.call(srv))
      {
        ROS_INFO("Sum: %ld", (long int)srv.response.current_x_orientation_s);
      }
      else
      {
        ROS_ERROR("Failed to call service add_two_ints");
        return 1;
      }

  return 0;
}

the srv file

float64 current_x_orientation_c
---
float64 current_x_orientation_s
bool success

And the control launch file is here

<launch>
<arg name="namespace" default="thrbot"/>
<arg name="joy_id" default="0"/>
<arg name="axis_x" default="4"/>
<arg name="axis_y" default="3"/>
<arg name="axis_z" default="1"/>
<arg name="axis_yaw" default="0"/>

<arg name="gui_on" default="true"/>

<include file="$(find thrbot_control)/launch/start_thruster_manager.launch">
    <arg name="uuv_name" value="$(arg namespace)"/>
</include>

 <node name="joy_node" pkg="joy" type="joy_node">
 </node>

<group ns="$(arg namespace)">
    <rosparam file="$(find thrbot_control)/config/inertial.yaml" command="load"/>
    <rosparam file="$(find thrbot_control)/config/vel_pid_control.yaml" command="load"/>

    <node pkg="uuv_control_cascaded_pid" type="AccelerationControl.py" name="acceleration_control"
        output="screen">
        <param name="tf_prefix" type="string" value="$(arg namespace)/" />
    </node>

    <node pkg="uuv_control_cascaded_pid" type="VelocityControl.py" name="velocity_control"
        output="screen">
        <remap from="odom" to="pose_gt"/>
    </node>
</group>

<include file="$(find uuv_teleop)/launch/uuv_teleop.launch">
    <arg name="uuv_name" value="$(arg namespace)"/>
    <arg name="joy_id" value="$(arg joy_id)"/>
    <arg name="output_topic" value="cmd_vel"/>
    <arg name="message_type" value="twist"/>
    <arg name="axis_yaw" value="$(arg axis_yaw)"/>
    <arg name="axis_x" value="$(arg axis_x)"/>
    <arg name="axis_y" value="$(arg axis_y)"/>
    <arg name="axis_z" value="$(arg axis_z)"/>
    <arg name="gain_yaw" default="0.1"/>
    <arg name="gain_x" default="0.2"/>
    <arg name="gain_y" default="0.2"/>
    <arg name="gain_z" default="0.2"/>
    
    <!--arg name="gain_yaw" default="0.1"/> -->
    <!--arg name="gain_x" default="0.2"/>  -->
    <!--arg name="gain_y" default="0.2"/> -->
    <!--arg name="gain_z" default="0.2"/> -->
</include>

Any help?

Bob9710
  • 205
  • 3
  • 15
  • Is there a specific joystick you're using. Also are you running the ros joystick package to get input into ros? http://wiki.ros.org/joy – BTables Sep 14 '21 at 15:47
  • its a normal 360 console usb joystick. There is nothing specific on the joystick – Bob9710 Sep 14 '21 at 15:53
  • and there is no ros joystick package. actually the robot can be control by keyboard as well. There is a launch file for keyboard but of course with joystick is more comfortable. – Bob9710 Sep 14 '21 at 15:54
  • Right. If I'm understanding the question correctly you want to basically hit a button on the joystick and have it call the service and return the value? – BTables Sep 14 '21 at 15:58
  • exactly. Yes that's what I want – Bob9710 Sep 14 '21 at 17:28

1 Answers1

1

Since you want to use a joystick input to trigger events in ros I would say to use the joy package and just add it to your launch file like so:

  <node name="joy_node" pkg="joy" type="joy_node">
  </node>

Then you just need to setup a subscriber in your client to handle joystick input and call the service appropriately like so

joy_sub_ = nh_.subscribe<sensor_msgs::Joy>("joy", 10, joystick_callback, this);

and the callback

void joystick_callback(const sensor_msgs::Joy::ConstPtr& joy)
{
  auto button_pressed = joy->buttons[0]; // 0 is the 'A' button on a wired xbox 360 controller
  if(button_pressed){
    imu_service::ImuValue srv;
    client.call(srv); 
    std::cout << "Got accel x: " << srv.response.current_x_orientation_s << std::endl;
  }
}

Note that the above code assumes client is a global variable.

BTables
  • 4,413
  • 2
  • 11
  • 30
  • ok. Thanks. Will try. One question. How can I run multiple services with one joystick click?Like Wonna call in same time IMUService, SonarService and etc. – Bob9710 Sep 15 '21 at 07:27
  • You would just need to create multiple service objects. In this case it would be `srv`. You'll only need one copy of `client` in this case. It will be used to call the service on all of the different objects. – BTables Sep 15 '21 at 12:48
  • sorry how to create multiple service objects? You mean in the srv folder I will have for example IMUService.srv , SonarService.srv, PressureService.srv files right ? and in CMakeLists.txt will have something like this add_service_files( FILES ImuValue.srv SonarValue.srv ) – Bob9710 Sep 15 '21 at 12:54
  • and what you mean by copy of the client? – Bob9710 Sep 15 '21 at 12:55
  • No a service object is a normal c++ object, in this case `srv`. If you wanted another you would do `imu_service::ImuValue srv2;`. If you have other service *types* you would need to create another message for that; i.e. SonarService.srv. What I meant about the client is that you only need one instance of that object. Here, it's `client`, so you do not need to create a new object of that. – BTables Sep 15 '21 at 13:11
  • means I only need one Client node. One Client cpp that can handle all services I need(IMU, Pressure, Sonar..) and give response for all of them? – Bob9710 Sep 15 '21 at 13:33
  • Not exactly. One instance of `ros::ServiceClient` can handle calling all of your services for a single type since it's a templated class. You would need a client for every `srv` type. – BTables Sep 15 '21 at 18:15
  • so one click on the joystick will call all the services at once right? – Bob9710 Sep 15 '21 at 19:43
  • If you set them all to be called from the joystick callback, yes. – BTables Sep 15 '21 at 19:47
  • so only is in the joystick teleoperation launch file. Right? The joy_sub_ and the joystick_callback are in the client service cpp node, right? – Bob9710 Sep 16 '21 at 07:07
  • How to be set them all to be called from the joystick callback, when each service client (IMU, Sonar etc... ) has own client service node cpp – Bob9710 Sep 16 '21 at 07:08
  • I tried to run one service with joystick and nothing happened. I modified the launch and the client code according your suggestions. The code edit in the question. Please can you look and let me know why nothing happened? – Bob9710 Sep 16 '21 at 07:41