android_core 0.0.0-SNAPSHOT documentation

Getting started

«  Building android_core   ::   Contents

Getting started

Before diving into ROS enabled Android application development, you should be familiar with rosjava and Android application development in general.

Creating a new Android application

Note

This is still a work in progress. There are many obvious limitations and the process will be improved in the near future.

Currently, the easiest way to create a new application is to create your own package in the android_core stack by copying one of the tutorial packages (e.g. android_tutorial_pubsub).

roscd android_core
cp -a android_tutorial_pubsub my_package

After that, modify android_core/settings.gradle to include your new package.

rosed android_core/settings.gradle
./gradlew my_package:clean my_package:debug

At this point, you may interact with your Android projects as described in the Android documentation. Please start there if the following quick start instructions are insufficient for you.

Use Apache Ant to install your new Android application:

roscd my_package
ant installd

You can also use ant to build the application. However, if you add, remove, or modify a dependency in the build.gradle file, you will need to execute the gradle wrapper as described above in order to update the Android application’s external dependencies (located in the my_package/libs directory).

Note

You may also build and run your application from Eclipse. For more information, see Building android_core.

Using RosActivity

The RosActivity class is the base class for all of your ROS enabled Android applications. Let’s consider the following example from the android_tutorial_pubsub package. In this example, we create a Publisher and a Subscriber that will exchange “Hello, World” messages.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package org.ros.android.android_tutorial_pubsub;

import android.os.Bundle;
import org.ros.android.MessageCallable;
import org.ros.android.RosActivity;
import org.ros.android.view.RosTextView;
import org.ros.node.NodeConfiguration;
import org.ros.node.NodeMainExecutor;
import org.ros.rosjava_tutorial_pubsub.Talker;

/**
 * @author damonkohler@google.com (Damon Kohler)
 */
public class MainActivity extends RosActivity {

  private RosTextView<std_msgs.String> rosTextView;
  private Talker talker;

  public MainActivity() {
    // The RosActivity constructor configures the notification title and ticker
    // messages.
    super("Pubsub Tutorial", "Pubsub Tutorial");
  }

  @SuppressWarnings("unchecked")
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    rosTextView = (RosTextView<std_msgs.String>) findViewById(R.id.text);
    rosTextView.setTopicName("chatter");
    rosTextView.setMessageType(std_msgs.String._TYPE);
    rosTextView.setMessageToStringCallable(new MessageCallable<String, std_msgs.String>() {
      @Override
      public String call(std_msgs.String message) {
        return message.getData();
      }
    });
  }

  @Override
  protected void init(NodeMainExecutor nodeMainExecutor) {
    talker = new Talker();
    NodeConfiguration nodeConfiguration = NodeConfiguration.newPrivate();
    // At this point, the user has already been prompted to either enter the URI
    // of a master to use or to start a master locally.
    nodeConfiguration.setMasterUri(getMasterUri());
    nodeMainExecutor.execute(talker, nodeConfiguration);
    // The RosTextView is also a NodeMain that must be executed in order to
    // start displaying incoming messages.
    nodeMainExecutor.execute(rosTextView, nodeConfiguration);
  }
}

On line 14, we extend RosActivity. When our activity starts, the RosActivity super class will:

On line 22 we call the super constructor with two strings that become the title and ticker message of an Android notification. The user may tap on the notification to shut down all ROS nodes associated with the application.

Lines 28-30 should look familiar to Android developers. We load the activity layout and get a reference to our RosTextView (more on that later).

On line 42 we define the abstract method RosActivity.init. This is where we kick off our NodeMains and other business logic.

And that’s it. RosActivity handles the rest of the application’s lifecycle management including:

Nodes and Views

The android_core stack provides a number of Android Views which implement NodeMain. For example, let’s look at the implementation of RosTextView. The intent of this view is to display the textual representation of published messages.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package org.ros.android.view;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
import org.ros.android.MessageCallable;
import org.ros.message.MessageListener;
import org.ros.namespace.GraphName;
import org.ros.node.ConnectedNode;
import org.ros.node.Node;
import org.ros.node.NodeMain;
import org.ros.node.topic.Subscriber;

/**
 * @author damonkohler@google.com (Damon Kohler)
 */
public class RosTextView<T> extends TextView implements NodeMain {

  private String topicName;
  private String messageType;

  public void setTopicName(String topicName) {
    this.topicName = topicName;
  }

  public void setMessageType(String messageType) {
    this.messageType = messageType;
  }

  public void setMessageToStringCallable(MessageCallable<String, T> callable) {
    this.callable = callable;
  }

  @Override
  public GraphName getDefaultNodeName() {
    return new GraphName("android_gingerbread/ros_text_view");
  }

  @Override
  public void onStart(ConnectedNode connectedNode) {
    Subscriber<T> subscriber = connectedNode.newSubscriber(topicName, messageType);
    subscriber.addMessageListener(new MessageListener<T>() {
      @Override
      public void onNewMessage(final T message) {
        if (callable != null) {
          post(new Runnable() {
            @Override
            public void run() {
              setText(callable.call(message));
            }
          });
        } else {
          post(new Runnable() {
            @Override
            public void run() {
              setText(message.toString());
            }
          });
        }
        postInvalidate();
      }
    });
  }

  @Override
  public void onShutdown(Node node) {
  }

  @Override
  public void onShutdownComplete(Node node) {
  }

  @Override
  public void onError(Node node, Throwable throwable) {
  }
}

The view is configured with a topic name, message type, and a MessageCallable. On line 40, in the NodeMain.onStart method, we create a new Subscriber for the configured topic and message type.

When a new message arrives, we either use the configured callable to transform the incoming message to a string (line 49), or we use the default toString() method if no callable was configured (line 56). We then set the text of the view to the string representation of the incoming message.

As with any other NodeMain, the RosTextView must be executed by the NodeMainExecutor. In the Using RosActivity example, we execute it in RosActivity.init and use the it to display incoming messages from the Talker node.

«  Building android_core   ::   Contents