[JAVA] ROS app development on Android

Contents of this article

I will explain the tutorial application that performs Pub-Sub communication of ROS (Robot Operating System) on Android. The Android ROS app is developed with rosjava, but I created an article because the amount of information in Japanese is less or older than roscpp and rospy.

Basically, I refer to the tutorial http://wiki.ros.org/android on ROS.org.

Prerequisite knowledge

--General knowledge of Android application development --General knowledge of ROS development

Tutorial content

Here, assuming that ROS Master is running on the ROS PC, check the operation of subscribing the published message on the smartphone on the ROS PC (+ smartphone itself).

system_android.png

Operation check environment

-** App development PC ** Used for Android application development. - Windows 7 Professional - Android Studio 3.2.1

Preparation

Detailed procedures for each item are introduced on other sites, so I will omit them.

-** App development PC ** It seems that it was necessary to build a ROS environment on the application development PC before, but now it can be developed only with Android Studio. --Install Android Studio --Install the Nexus 5X USB driver --Install API 15 or above SDK

-** Network ** Connect your smartphone and ROS PC to the same network. In my environment, the IP address is as follows. --Smartphone: 192.168.0.14 - ROS PC:192.168.0.15

App development procedure

-** Create an app with New-> New Project in Android Studio ** --Select API 15 or later for "Target Android Devices" in "Phone and Tablet" -Select "Empty Activity" for "Add an Activity to Mobile" --Other than that, it is OK by default

-** Edit build.gradle (Top level) **

build.gradle


// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

buildscript {
    apply from: "https://github.com/rosjava/android_core/raw/kinetic/buildscript.gradle"
}

subprojects {
    apply plugin: 'ros-android'

    afterEvaluate { project ->
        android {
            // Exclude a few files that are duplicated across our dependencies and
            // prevent packaging Android applications.
            packagingOptions {
                exclude "META-INF/LICENSE.txt"
                exclude "META-INF/NOTICE.txt"
            }
        }
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Here, in the original tutorial

Edit the top-level build.gradle file and replace this part:

with this:

There is a statement (I added the emphasis on replace), but in my environment I got an error when I deleted the first buildscript, so I left it as it is.

-** Edit build.gradle (app) **

build.gradle


apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "goodclues.example.myrosapplication"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation 'org.ros.android_core:android_15:[0.3,0.4)'
}

The last "implementation" is "compile" at home, but it seems to be deprecated now. ~~ Also, let's change the number 15 of "android_15" according to the API level. ~~ (← Please point out in the comments, it seems that the numbers and API level are not related. Also, it seems that the description method has changed now, so please check the tutorial for the latest information.)

-** Add permissions to AndroidManifest.xml **

<uses-permission android:name="android.permission.INTERNET" />

Permission to use the network.

-** Add activity to AndroidManifest.xml **

<activity android:name="org.ros.android.MasterChooser" />

Master Chooser is an activity to specify the URI of ROS Master. If you describe this, the setting screen will be displayed automatically when the application is started. You can also hard-code the Master URI, but see the original tutorial for how to do this.

-** Add the following to AndroidManifest.xml **

<application xmlns:tools="http://schemas.android.com/tools"
        tools:replace="android:icon"
        ...(Continued below)

I'm not sure why, but without it I'm getting an error. The final manifest file looks like this:

AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="goodclues.example.myrosapplication">

    <uses-permission android:name="android.permission.INTERNET" />

    <application xmlns:tools="http://schemas.android.com/tools"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:replace="android:icon">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <activity android:name="org.ros.android.MasterChooser" />
    </application>

-** Change the text of activity_main.xml ** --Changed the default TextView view to org.ros.android.view.RosTextView --Added id = "@ + id / text"

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <org.ros.android.view.RosTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

-** Edit MainActivity **

To use ROS, create an Activity that extends RosActivity. The sample below has a class called Talker that publishes a / chatter message and a view that subscribes to a chatter topic called RosTextView.

The Talker class internally publishes a number that is incremented every second.

MainActivity.java


/*
 * Copyright (C) 2011 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package goodclues.example.myrosapplication;

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;

/**
 * @author [email protected] (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.activity_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();

        // 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.

        // The user can easily use the selected ROS Hostname in the master chooser
        // activity.
        NodeConfiguration nodeConfiguration = NodeConfiguration.newPublic(getRosHostname());
        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);
    }
}

I borrow the sample almost as it is. However, at the head family

import org.ros.rosjava_tutorial_pubsub.Talker;

However, since an error occurred in my environment, I copied the following source and created a Talker class in my project. http://docs.ros.org/hydro/api/rosjava_core/html/Talker_8java_source.html

Operation check

Start roscore on your ROS PC.

$ roscore

Next, when you start the app, the following ROS Master connection setting screen will be displayed. (If you check Show advanced options, you will see a button to make detailed network settings and the smartphone itself a ROS Master, but I will omit it here because it is unnecessary) ros_master_setting.png

Enter the URI of the ROS Master in "Master URI". It is OK if you change the place where it is "localhost" to "192.168.0.15" set above. Next, tap CONNECT and if the connection is successful, it will transition to Main Activity.

main_activity.png

The number displayed to the right of Hello world! Is the message you are subscribing to (published by yourself).

Now, let's check if you can subscribe on ROS PC. At the terminal

$ rostopic echo /chatter

Then

data: "Hello world! X"

If the message is output at regular intervals like this, it is successful. (X is a number)

in conclusion

I explained the procedure of Android application development that realizes simple Pub-Sub communication along with the tutorial of ROS.org. This will make it easier to link the robot with a smartphone camera, etc., so please give it a try.

Recommended Posts

ROS app development on Android
Android app personal development kickoff
Notes on calling Installer on Android App
Android weather app
Android Development App_Preparation
I made a calculator app on Android
Allows Youtube autoplay on Cordova's Android app
Riot (chat app) development (settings) in Android Studio
Android application development using Unity + ARCore on Ubuntu
Android development link summary
[Android] Notes on xml
Android app Spectrum Analyzer
Android application development preparation 7/15
About Android App Components
Android development reference site
Android app development points that old-fashioned programmers stumbled upon
[2018 Preservation Version] Reverse Engineering Android App (.apk) on Mac
App development beginners tried to make an Android calculator app
Customize list view on Android
Multipart transmission library on Android
iOS engineer starts Android development
iOS app development: Timer app (2. Timer display)
Use serial communication on Android
Introduction to Android application development
Android development ~ Screen transition (intent) ~
Android app decompile ⇒ fix ⇒ recompile
iOS app development: Timer app (summary)
Make an android app. (Day 5)
Use native code on Android
Is it an Android app?
ATDD development on iOS (basic)
NoCode Glide's first app development
What Android development beginners did before releasing the app in 2 weeks
Introduction to Android App Development 1 Installing JDK and Android Studio for mac
Import device images with Android app
About the basics of Android development
Event handling with RxBus on Android
Bridge commentary on React Native Android
[Android] Get the date on Monday
[Unity] Android development environment construction procedure
Get JUnit code coverage on Android.
First Android development for busy people
Library collection useful for Android development
Complete self-study IOS app development diary
Make an android app. (First day)
Notes for Android application development beginners
Watson Assistant (formerly Conversation) on Android
Problems with android studio development series
Save ArrayList using GSON on Android
iOS App Development Skill Roadmap (Introduction)
Notes on Android (java) thread processing
[Android] Receive intent on Broadcast Reciever
iOS app development: Timer app (4. Countdown implementation)
iOS app development: Timer app (1. Timer time setting)
Build Unity development environment on docker
I made a matching app (Android app)
iOS app development: Timer app (10. Create animation)
Build Redmine on Azure App Service
Implement ripple representation on images on Android
[Android] I made a pedometer app.
Speed up location acquisition on Android