Lab 3.3: Arduino and Android

Overview

In this lab, we’ll learn how to connect Arduino hardware to Android powered devices. We’ll implement a simple project where the phone will send commands to Arduino ADK board and receive data from it. Here is what we’ll do:

  1. Writing the Arduino program (sketch) that will turn ON/OFF the LED based on the command received from the phone. It’ll also continuously send the sensor readings to the phone where it can be viewed in real-time.
  2. Developing the Android application that will send the ON/OFF command to the ADK as well as display received sensor readings in real time.

Arduino Sketch

Start developing the sketch by including the necessary header files and define the required constants:

Next you need to initialize an AndroidAccessory object with some descriptive strings which define your created accessory. The fields are self-explanatory. The most important parameters are Manufacturer, Model, and Version. They will be used in the Android application to verify that you are communicating with the correct ADK board.

Again note that you need to remember manufacturer, model and version as you’ll need to define these in you’re Android app so that the your app is notified when your accessory is connected.

Next define the setup() function. The setup() function begins serial communications with the device and then calls pinMode() method to initialize the input and output pins. It configures the specified pin to behave either as an INPUT or an OUTPUT. Arduino pins default to INPUT so the mode doesn’t need to be explicitly set but its usually a good idea to do it anyway so that your code is clear and understandable. The acc.powerOn() set the object into an active state.

After creating and executing the setup() function, which is responsible for initializing the initial values, the loop() function runs repeatedly and calls acc.isConnected() to check for any connected devices. If there is a connected device, it continuously updates the input and output streams going to and from the board and application. If nothing is connected, it continuously checks for a device to be connected. The full loop() function is given below:

The Arduino sketch calls acc.read() and acc.write() methods depending on whether data is received from Android device or sent to the Android device. For instance, moving the joystick on the ADK shield sends the joystick readings to the Android device. Similarly, moving sliders on the android application or pressing a button is read by the Arduino sketch and changes the state of the accessory, such as lighting up LED light etc.

Installing the firmware to the ADK board

To install the firmware to the ADK board:

  • Connect the LED to the port specified in the sketch.
  • Connect the ADK Main Board to PC through USB.
  • Set the Board type in Arduino IDE to Arduino Mega 2560 or Mega ADK.
  • Select the correct serial port. On Ubuntu, the correct port is ‘/dev/ttyACM0‘ for Mega ADK and ‘/dev/ttyUSB0‘ for Seeduino ADK.
  • Compile the your Sketch and upload to Main Board

The board is ready to communicate with your Android-powered device. Next, we’ll develop an Android app to make the Android device ready.

 

Android App

When you create your Android app, there’s a few steps you need to take so that it can communicate with ADK.

First create a new Android project with the default settings;

Now open build.gradle (Module: app) file from your project. Locate the android section.

Change compileSdkVersion as shown below:

You can also use Google Inc.:Google APIs:23 if installed.

Locate the dependencies section.

Remove the line for the compatibility library (containing appcompat). After that the section should look like this.

Save and close.

The default app theme is not available from the core API. So we need to fix that. Open res/values/styles.xml. The style tag will look something like this:

Change the parent to a theme that is available from the core SDK. For example:

Also, remove all item tags inside style tag as shown above. Save and close the file.

In MainActivity.java, extend your activity classes from Activity instead of ActionBarActivity or AppCompatActivity. Press Alt+Enter on Activity once you have made the changes to add import android.app.Activity at the top of the file. See the example below:

Change:

to:

You will have to do the same if you have additional activities that extends ActionBarActivity and AppCompatActivity

Finally, perform a Build | Clean Project and a Build | Rebuild Project to sort out the current build errors.

Now create/change the following files in your project.

 

Manifest File

AndroidManifest.xml is the central registry for your application. Details about activities, services, permissions, mandatory device features, and many others have to be defined inside this file. You need your application to be notified when your accessory is attached. To achieve this, include the following <intent-filter> and <meta-data> element pair inside the main activity tag of the Manifest file. The important thing in the activity node is the intent-filter. The intent-filter defines how the activity can be launched by the system and how it can be triggered.

Also, add  the following <uses-library> element inside the application tag of the Manifest file to include the USB accessory library in your Android application.

It can be seen that we included the file “@xml/accessory_filter” as a resource in the meta-data element. This file references an XML resource file that includes the manufacturer, model and version you defined earlier in your Arduino sketch. This way, the Android device knows which Android app the board should connect to when the ADK board is attached to the Android device. The file, however, does not exist yet. You need to create an accessory_filter.xml resource file in the res/xml/ directory. You might need to first create the folder xml inside the res directory of your application. Add the following code to the file:

Please note that manufacturer, model, version have the same values that we defined previously in the Arduino sketch.

Now, when you connect your accessory to the device android will send an intent to open an appropriate application. The best part is that more than one application can respond to a given intent so multiple apps could optionally respond for the same accessory.

Creating the Layout

The layout will include a Text View  (for displaying sensor readings) and a Toggle Button (for sending ON/OFF commands to the ADK). The Layout has already been created for you so that you can focus on the actual functionality.

 

The Main Java File

Implementing the communication part in Android requires a bit more work than on the Arduino side. We’ll extend the main java file step-by-step. First. First import the required libraries.

 

Also declare the following inside your main activity class

 

 

First let’s have a look at the variable declarations you need to make.

private static final String TAG = MainActivity.class.getSimpleName();

The constant TAG is an identifier for the current class and is used only for logging purposes in Android. If you have a look at the logcat view in Eclipse while a device or an emulator is running, you will see that logged messages are associated to a TAG, which simplifies reading the log output.

private PendingIntent mPermissionIntent;
private static final String ACTION_USB_PERMISSION = “com.android.example.USB_PERMISSION”;
private boolean mPermissionRequestPending;

Establishing a connection to an external device has to be permitted by the user. When the user is granting the rights to connect to your ADK board, the PendingIntent will broadcast the ACTION_USB_PERMISSION with a flag reflecting whether the user confirmed or denied the access. The Boolean variable mPermissionRequestPending is only used to not show the permission dialog again if the user interaction is still pending.

private UsbManager mUsbManager;
private UsbAccessory mAccessory;
private ParcelFileDescriptor mFileDescriptor;
private FileInputStream mInputStream;
private FileOutputStream mOutputStream;

The UsbManager is a system service that manages all interaction with the USB port of the device. It is used to enumerate the connected devices and to request and check the permission to connect to an accessory. The UsbManager is also responsible for opening the connection to the external device. The UsbAccessory is a reference to the connected accessory. The ParcelFileDescriptor is obtained when the connection to the accessory is established. It is used to get access to the input- and outputstream of the accessory.

private static final byte COMMAND_SENSOR = 0xF;
private static final byte COMMAND_LED = 0x2;
private static final byte LED_ON = 0x1;
private static final byte LED_OFF = 0x0;

COMMAND_SENSOR, and COMMAND_LED are the same constants as the ones used in the Arduino sketch.
The are used to make it easier to expand the app to include more sensors and other devices.

private TextView textView;
private ToggleButton ledToggleButton;

The only user-visible UI elements are the textView and ledToggleButton. textView displays the transmitted message from the ADK board, while ledToggleButton is used to send ON/OFF led commands to the ADK board.

 

That’s all about the variables you’ll need to declare. Now we will add the lifecycle methods of the activity.

 

The first lifecycle callback method of each activity class is the onCreate method. This method is usually the place where you make your basic initializations. Here a reference to the USB system service is obtained so that you can call its methods later on. Then a PendingIntent with the ACTION_USB_PERMISSION parameter is defined. You will need it when you request the user’s permission to connect to a USB device. The intent filter you see here is used in conjunction with a broadcast receiver to make sure that the application only listens to certain broadcasts. The filter defines that it reacts on the ACTION_USB_PERMISSION action you defined as a constant in the beginning and on the  ACTION_USB_ACCESSORY_DETACHED action, for when the ADK accessory is disconnected. The registerReceiver method registers the broadcast receiver with the described intent filter at the system. So when a broadcast is sent by the system, the broadcast receiver will be notified and can take the relevant action. The last thing you need to do in the onCreate method is set up your UI elements and use the setContentView method to load your layout.

You have completed the creation phase of the Activity. Now you get to the next important lifecycle phase, the onResume lifecycle hook. The onResume method is called each time your activity returns from its paused state. When you leave your activity to start a new one or to return to your device’s home screen, your activity will be set into a pause state rather than to be killed. This is done by the system to preserve time and memory allocation in case the activity is shown again shortly. In the paused state the activity is no longer visible to the user. If the activity should be shown again it is only returned from its paused state and set into a resumed state rather than fully initialized again. When this happens, the onResume
lifecycle method is called. The onResume method should not be responsible for doing major initializations. In this case it should rather check if you are still able to communicate with the accessory. That’s exactly what you are doing here.

If the input- and outputstream is still active you are good to go for communication and can return prematurely from the onResume method. Otherwise, you have to get a reference of the accessory from the UsbManager. If you already have the user’s permission to communicate with the device you can open and reassign the input- and outputstreams. This part is implemented in an own method called openAccessory, which we’ll talk about shortly. The last two lifecycle methods are onPause method and the onDestroy methods. onPause takes the activity to the paused state and onDestroy kills the activity and unregisters Broadcast Listeners.

 

That concludes the lifecycle methods. Now, we’ll implementation communication part which is a bit tricky.

The first thing you see here is the implementation of a BroadcastReceiver. A BroadcastReceiver is a component that receives and handles broadcasts which can be sent by the system or other applications. You know now that you need to register and unregister a broadcast receiver in the respective lifecycle methods, but now let’s see how the broadcast receiver should be implemented.

The broadcast receiver is implemented as an anonymous inner class for the type BroadcastReceiver. The only method you’ll have to overwrite is the onReceive method which is called by the system if this broadcast receiver is registered and matches the provided intent-filter. Remember that two actions are defined in the intent-filter. You will have to check which action occurred when the broadcast receiver is called. If you receive the action describing that a permission request has been answered you’ll have to check if the user granted permission to communicate with your accessory. If so, you can open the communication channels of the accessory. The second action which could have triggered the broadcast receiver is the notification that the accessory has been detached from the Android device. In that case, you need to clean up and close your communication channels. As you can see, the BroadcastReceiver calls the openAccessory method and the closeAccessory method to open and close the communication channels to the accessory. Let’s have a look at those methods next.

In the openAccessory method you delegate to the USB service method, which is also called openAccessory, to obtain a FileDescriptor for your accessory. The FileDescriptor manages the inputand outputstream which you will use to communicate with your device. Once the streams have been assigned you will also start a separate thread which will do the actual receiving and sending of messages (described later). If you don’t have the permission to connect to your accessory yet and you are not in a pending state for the user’s permission, you must request permission for your accessory by calling the requestPermission method on the USB service. The requestPermission method has two parameters, the accessory for which you request the permission and a pending intent. This pending intent is the mPermissionIntent you defined in the onCreate method and it’s responsible for sending a broadcast with the ACTION_USB_PERMISSION as soon as the user grants or denies permission to communicate with the accessory. As you may remember, you registered a broadcast receiver in the onCreate method as well, which has an intent-filter for that exact same action. Once the broadcast is sent, the broadcast receiver will react on it. The closeAccessory method is responsible for closing all remaining open connections to the accessory. All it does is close the accessory’s FileDescriptor. The system will handle all underlying OS resources associated with its streams.

Now that we have finally opened a connection to the accessory, we can send and receive data between Android and Arduino.

 

Once you have established a connection to the accessory, you can begin with the actual sending and receiving of messages. As can bee seen, a separate thread was started in the openAccessory  method which is responsible for the message handling.

Thread thread = new Thread(null, commRunnable, TAG);
thread.start();

The Runnable object, which is passed to the thread, is also an anonymous inner class you have to implement. Its run method will be executed as long as you have an active inputstream from your accessory.

In each iteration step, the content of the inputstream is read into a byte array. If the first byte depicts that you received a message of the type COMMAND_SENSOR, we construct the integer value from the received bytes and display it to the user. Note that you are still in a separate thread. The system only allows UI updates to happen on the UI thread. To update the text of your TextView UI element you use the convenience method runOnUiThread, which executes the given Runnable object on the system UI thread.

That’s all for the receiving part of the message handling. Another one is to send commands to the board back to the board.  You can see that an OnCheckedChangeListener is assigned to the ledToggleButton which implements a callback method that is triggered every time the button is pressed. The ToggleButton is a special stateful implementation of a Button, which means that it knows if it is checked or unchecked. The
implementation of the OnCheckedChangeListener is done in an anonymous inner class. The only method that has to be implemented is the onCheckedChange method which has two parameters: the button that triggered the event and a Boolean flag indicating the new state of the button.

After validating that the correct button triggered the event, you can start sending the command to the ADK board to toggle the LED. This is done by calling sendLedSwitchCommand with the state the LED should be switched to. You may wonder what this AsyncTask is all about. The event callback method is executed on the UI thread. If you were to just send the message there you would do the outputstream operations in the UI
thread as well. This generally works but it is a bad practice. Longer operations may block the UI which is very frustrating for the user. To avoid those situations you can do several things: open another Thread, utilize the Android Handler mechanism or, as done in this case, use an AsyncTask for concurrency.
UI thread is running to serve the user. Here only the doInBackground method is implemented because it is all you need. Additionally, the AsyncTask has callback methods that are running on the UI thread to visualize the progress of a background operation or to update the UI elements when it is finished. The sendLedSwitchCommand method builds the message data structure, which is then sent via the outputstream to the accessory.

FINALLY!!! You have finished implementing both sides of the communication. Now upload the Arduino sketch to your ADK board and deploy the Android application onto your device. If you connect your Android device to your ADK board, you should see that your Android application is started automatically and that it will print the messages sent by the ADK board. Also, now you should be able to control the LED through the Toggle Button in your App’s UI.

 

Running the application

FINALLY!!! You have finished implementing both sides of the communication.  The Android application we just created runs on your Android-powered device and communicates with the ADK board. The ADK board receives commands such as lighting up the board’s LEDs or sends sensor data from the board. Now do the following:

  1. Upload the Arduino sketch to your ADK board and deploy the Android application onto your device.
  2. Connect the ADK board to your phone. Ensure that the USB port on the accessory is connected to your computer . When connected, accept the prompt that asks for whether or not to open the Android application to connect to the accessory. If the prompt does not show up, connect and reconnect the accessory or press reset the button on the ADK board.
  3. Test your application and verify that it’s working as it should.

 

Lab Exercise 3.3

You probably noticed that we included a Seek Bar in our activity layout but didn’t implement it. Extend the lab exercise by implementing the Seek Bar as follows:

  • Connect a second LED to the ADK board. Whenever the increase or decrease the progress of the seek bar, the LED brightness should also increase/decrease proportionally.

[Hints]

  • You will need to create a listener for the seek bar just like we did for Toggle Button.
  • You will need to create a function similar to sendLedSwitchCommand to send seek bar progress value to ADK.
  • On the Arduino side, you will need to use analogWrite for proportional brightness. You also might need to use the Arduino map() function to map the received seek bar progress value to 0-255 range.