nueog

[Android Studio][ROS] ROS bridge를 이용한 안드로이드 앱 통신(1) 본문

카테고리 없음

[Android Studio][ROS] ROS bridge를 이용한 안드로이드 앱 통신(1)

nueog 2024. 4. 8. 16:57
반응형

ROS를 사용하는 로봇 보드에서 안드로이드 앱으로 로봇 데이터를 통신하는 기능을 수행했다.

 

받을 데이터들은 다음과 같았다.

1) 위치 데이터(출발, 도착지, 현재 데이터)

2) 배터리 데이터(SOC데이터)

 

서버를 통해 안드로이드와 소켓 통신으로 진행하기로 결정했다!

 

먼저 연동할 것은 ROS bridge, Socket 통신이었다.

 

이번 게시물에서는 ROS Bridge를 연동한 Javascript 코드에 대해서 설명하겠다!

 

ROS brige 기능은 웹 페이지를 열어서 javascript로 진행을 하였다. 코드는 다음과 같다.

 

전체 코드

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://static.robotwebtools.org/EventEmitter2/current/eventemitter2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/roslibjs/1.1.0/roslib.js"></script>
<script src="/socket.io/socket.io.min.js"></script>

<script>
  //socket 관련
  var socket = io();
  
  // Connecting to ROS
  // -----------------
  var ros = new ROSLIB.Ros();

  // If there is an error on the backend, an 'error' emit will be emitted.
  ros.on('error', function(error) {
    document.getElementById('connecting').style.display = 'none';
    document.getElementById('connected').style.display = 'none';
    document.getElementById('closed').style.display = 'none';
    document.getElementById('error').style.display = 'inline';
    console.log(error);
  });

  // Find out exactly when we made a connection.
  ros.on('connection', function() {
    console.log('Connection made!');
    document.getElementById('connecting').style.display = 'none';
    document.getElementById('error').style.display = 'none';
    document.getElementById('closed').style.display = 'none';
    document.getElementById('connected').style.display = 'inline';
  });

  ros.on('close', function() {
    console.log('Connection closed.');
    document.getElementById('connecting').style.display = 'none';
    document.getElementById('connected').style.display = 'none';
    document.getElementById('closed').style.display = 'inline';
  });

  // Create a connection to the rosbridge WebSocket server.
  ros.connect('ws://[ROS 서버 주소]');

  //

  

  // Publishing a Topic
  // ------------------

  // First, we create a Topic object with details of the topic's name and message type.
  var cmdVel = new ROSLIB.Topic({
    ros : ros,
    name : '/cmd_vel',
    messageType : 'geometry_msgs/Twist'
  });

  var gpsVel = new ROSLIB.Topic({
    ros : ros,
    name : '/gps_data',
    messageType : 'sensor_msgs/NavSatFix'
  });

  // Then we create the payload to be published. The object we pass in to ros.Message matches the
  // fields defined in the geometry_msgs/Twist.msg definition.

  var twist = new ROSLIB.Message({
    linear : {
      x : 0.1,
      y : 0.2,
      z : 0.3
    },
    angular : {
      x : -0.1,
      y : -0.2,
      z : -0.3
    }
  });

  var route = new ROSLIB.Message({
    header : {
        seq : 1
    },
    latitude : 37.339920,
    longitude : 126.339920
  });

  urlSearch = new URLSearchParams(location.search);
  test1 = urlSearch.get('test')

  cmdVel.publish(twist);
  gpsVel.publish(route);
  console.log(route)

  //Subscribing to a Topic
  //----------------------

  // Like when publishing a topic, we first create a Topic object with details of the topic's name
  // and message type. Note that we can call publish or subscribe on the same topic object.
  var listener = new ROSLIB.Topic({
    ros : ros,
    name : '/listener',
    messageType : 'std_msgs/String'
  });

  // Then we add a callback to be called every time a message is published on this topic.
  listener.subscribe(function(message) {
    console.log('Received message on ' + listener.name + ': ' + message.data);

    // If desired, we can unsubscribe from the topic as well.
    listener.unsubscribe();
  });

  var imu_e2box = new ROSLIB.Topic({
    ros : ros,
    name : '/imu_e2box',
    messageType : 'sensor_msgs/Imu'
  });

  // Then we add a callback to be called every time a message is published on this topic.
  imu_e2box.subscribe(function(message) { 
    console.log('Received message on (test) ' + message.orientation.x);
    socket.emit('message', message.orientation.x);

    //console.log('Received message on (test2) ' + imu_e2box.orientation.x + ': ' + message.data); //출력은 imumsg에서 orientation x,y,z,w 받으면 될 것 같음

    // If desired, we can unsubscribe from the topic as well.
    imu_e2box.unsubscribe();
  });

  // Calling a service
  // -----------------

  // First, we create a Service client with details of the service's name and service type.
  var addTwoIntsClient = new ROSLIB.Service({
    ros : ros,
    name : '/add_two_ints',
    serviceType : 'rospy_tutorials/AddTwoInts'
  });

  // Then we create a Service Request. The object we pass in to ROSLIB.ServiceRequest matches the
  // fields defined in the rospy_tutorials AddTwoInts.srv file.
  var request = new ROSLIB.ServiceRequest({
    a : 1,
    b : 2
  });

  // Finally, we call the /add_two_ints service and get back the results in the callback. The result
  // is a ROSLIB.ServiceResponse object.
  addTwoIntsClient.callService(request, function(result) {
    console.log('Result for service call on ' + addTwoIntsClient.name + ': ' + result.sum);
  });

  // Advertising a Service
  // ---------------------

  // The Service object does double duty for both calling and advertising services
  var setBoolServer = new ROSLIB.Service({
    ros : ros,
    name : '/set_bool',
    serviceType : 'std_srvs/SetBool'
  });

  // Use the advertise() method to indicate that we want to provide this service
  setBoolServer.advertise(function(request, response) {
    console.log('Received service request on ' + setBoolServer.name + ': ' + request.data);
    response['success'] = true;
    response['message'] = 'Set successfully';
    return true;
  });

  // Setting a param value
  // ---------------------

  ros.getParams(function(params) {
    console.log(params);
  });

  // First, we create a Param object with the name of the param.
  var maxVelX = new ROSLIB.Param({
    ros : ros,
    name : 'max_vel_y'
  });

  //Then we set the value of the param, which is sent to the ROS Parameter Server.
  maxVelX.set(0.8);
  maxVelX.get(function(value) {
    console.log('MAX VAL: ' + value);
  });

  // Getting a param value
  // ---------------------

  var favoriteColor = new ROSLIB.Param({
    ros : ros,
    name : 'favorite_color'
  });

  favoriteColor.set('red');
  favoriteColor.get(function(value) {
    console.log('My robot\'s favorite color is ' + value);
  });
</script>
</head>

<body>
  <h1>Simple roslib Example</h1>
  <p>Run the following commands in the terminal then refresh this page. Check the JavaScript
    console for the output.</p>
  <ol>
    <li><tt>roscore</tt></li>
    <li><tt>rostopic pub /listener std_msgs/String "Hello, World"</tt></li>
    <li><tt>rostopic echo /cmd_vel</tt></li>
    <li><tt>rosrun rospy_tutorials add_two_ints_server</tt></li>
    <li><tt>roslaunch rosbridge_server rosbridge_websocket.launch</tt></li>
  </ol>
  <div id="statusIndicator">
    <p id="connecting">
      Connecting to rosbridge...
    </p>
    <p id="connected" style="color:#00D600; display:none">
      Connected
    </p>
    <p id="error" style="color:#FF0000; display:none">
      Error in the backend!
    </p>
    <p id="closed" style="display:none">
      Connection closed.
    </p>
  </div>
</body>
</html>

 

 

코드설명

 

1. 변수 설정

 

중간에 new ROSLIB.Topic 변수가 나오는데, 여기서 받아올 데이터의 형식을 ROS에서 제공하는 형식으로 설정해준다.

  var cmdVel = new ROSLIB.Topic({
    ros : ros,
    name : '/cmd_vel',
    messageType : 'geometry_msgs/Twist'
  });

위의 코드는 로봇의 twist값을 받아오는 변수값이다.

var gpsVel = new ROSLIB.Topic({
    ros : ros,
    name : '/gps_data',
    messageType : 'sensor_msgs/NavSatFix'
  });

위의 코드는 로봇의 gps data를 받아오는 NavSatFix 형식의 위치 데이터 변수값이다.

 

이런식으로 ROS에서 제공하는 데이터 형식을 찾아 적용해주면 된다.

  var ros = new ROSLIB.Ros();

  // If there is an error on the backend, an 'error' emit will be emitted.
  ros.on('error', function(error) {
    console.log(error);
  });

  // Find out exactly when we made a connection.
  ros.on('connection', function() {
    console.log('Connection made!');
  });

  ros.on('close', function() {
    console.log('Connection closed.');
  });

다음으로 ros와 error, connection, close 되었을 때 설정을 해준다.

 

ros.connect('ws://[ROS 서버주소]');

WS:// 를 붙이고 ROS 서버주소로 Connect를 해준다.

 

  var route = new ROSLIB.Message({
    header : {
        seq : 1
    },
    latitude : 37.309920,
    longitude : 126.339910
  });

  gpsVel.publish(route);

다음으로 내가 로봇쪽에 publish를 할 때이다. 위에서 만든 위치 데이터 형식인 gpsVel 에 route 변수값을 넣어서 ros측에 publish를 해준다.

 

 

반응형