Using Arduino with SAndroidE

Giovanni Lenzi edited this page Mar 3, 2017 · 1 revision

Introduction

In this document the steps to build an App to handle an Arduino board using the SAndroidE framework are described.

The set up is composed by the following SAndroidE compatible/described devices:

The system that will be created in this tutorial allows to handle the buttons and leds attached to Arduino's GPIOs, exploiting a SAndroidE smartphone application. The logic of the application lights up the led when the button is pressed (echo application). Both the led and the button will be connected to the same Arduino, communicating with smartphone via Bluetooth communication fournished by the BLE shield.


Requirements

  1. One Arduino UNO
  2. One BLE Shield v2.0 or later from RedBearLab
  3. A USB cable to connect Arduino to the PC
  4. A smartphone supporting Bluetooth 4.0-4.1 (aka Bluetooth Smart)
  5. A micro USB cable to deploy application to your smartphone
  6. Android Studio
  7. SAndroidE zip package: download and exctract the zip file
  8. Basic programming knowledge of Android applications

Prepare your app for SAndroidE

Some steps are common to all SAndroidE based projects. Please follow our Prepare your app for SAndroidE guide before proceeding with next steps.


Usage

Implementation consists of three steps:

  1. Devices firmware flashing (if needed); during this operation, the software necessary for the correct functioning of the involved devices (Arduino UNO and BLE Shield) is uploaded on them.
  2. Enumerating the resources provided by external devices we want to interact with (only the first time); with this operation, the files necessary to make the smartphone and the external device communicate are uploaded into the smartphone, allowing it to establish such communication.
  3. Developing an Android App which exploits the SAndrodE framework to implement the desired application logic.

Firmware flashing

First of all, if needed, upload the 'BLEControllerSketch' fournished by RedBearLab as described at http://redbearlab.com/getting-started-bleshield on Arduino. SAndroidE framework handles the the remote devices resources exploiting the description of the firmware provided by the .xml files. How to describe a new device/firmware is described [here](Support a new device).

NOTE 1: The guide that you will find at this link is somewhat outdated. In particular, if you download the "RBL_nRF8001" library from the website and continue with instructions, you will get an error message. To avoid that, upload this library on Arduino by the Sketch voice of Arduino (Sketch → Include library → Manage library, then look for RBL_nRF8001 in the menù) lib1.png lib2.png NOTE 2: Since the usage of the BT channel is exclusive, it is important to remember that the BLE controller App has to be terminated before running other Apps that require BT usage.


Enumerating resources

The resources available on each device must be enumerated: this creates a sort of pointer to access the resources by the framework. This operation is achieved by means of the BLEEMbeddedFlasher App. This App basically creates a match between every BLE device connected with the smartphone and a name that will be used in the Android code.

Now start the BLEEmbeddedFlasher app to enumerate the device resources.

addressing-resources.jpg

In order to pair the Arduino/BLEShield with the smartphone, you first need to make it discoverable, and then following the instruction in the figures below, to connect with it and giving it a unique name. In this case Arduino is discoverable as soon as it is powered up.

NOTE: If the devices is supported/described as previously described the BLE services and attributes will be shown after the connection with the remote device.

In this example the device nickname is BLE Shield (it defines the description of the kind of the device), whereas the name of the specific device is set as arduino.

enumerating-arduino.jpg

NOTE: It is important to use the same exact name here and in the App: "arduino" (first letter lower case)

The configuration procedure aims to populate the bleresources.xml with the resources; the BLEEmbeddedFlasher App automatically adds them to the file. This generated file, together with previously mentioned [Configuration Files](05-Configuration files), are necessary by the App for the next steps. In case the file already exists, because of a previous configuration procedure, such procedure is not needed.


Writing the app

App's layout

The application layout is created by editing the file res/layout/activity_main.xml.

arduino-app-dev-activity-1.jpg

The simple layout shown in figure above may be obtained by switching from Design to Text tab in Android Studio IDE and entering the following XML code:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.my.sarduino.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button not pressed"
        android:id="@+id/tvButtonState"
        android:textColor="@android:color/holo_red_dark"
        android:textSize="36sp" />

</RelativeLayout>

NOTE: If you simply copy the text, the "-" (short minus) can be switched into "—" (long minus). Be careful, this could generate an error!


App's logic

The application logic is implemented in the MainActivity.java file.

Both the virtual objects called by the SAndroidE library, which handle the remote resources, and the textviews shown on the App's User Interface are declared as global variables:

TextView tvButtonState;
BLEGeneralIO arduinoButton;
BLEGeneralIO arduinoLed;

In the activity's onCreate method the SAndroidE library is initializated by means of the BLEContext.init method. It is mandatory to insert this method before any other operations related to the SAndrodE library.

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);

	BLEContext.initBLE(this);
	...

In the onCreate method both SAndroidE virtual Objects and textviews are initialized:

tvButtonState=(TextView) findViewById(R.id.tvButtonState);
arduinoLed = (BLEGeneralIO) BLEContext.findViewById("arduino_rbs_general_io_5");
arduinoButton = (BLEGeneralIO) BLEContext.findViewById("arduino_rbs_general_io_2");

NOTE: the String parameters passed to the methods, which initialize the SAndrodE Objects are the 'pointer' defined in the configuration procedure. This 'pointer' can be found in the "bleresources.xml" file.

To handle the GPIO SAndroidE library make available the BLEOnGeneralIOEventListener interface, which is passed to the SAndroidE Object by the means of the 'setOnGeneralIOEventListener' method. When the board is inited the 'onBoardInitEnded' method is triggered, thus the status of the GPIO is defined in this callback. Other methods from the BLEGeneralIO interface are overriden but left empty, because they are useful for our application.

arduinoLed.setOnGeneralIOEventListener(new BLEOnGeneralIOEventListener() {
	@Override
	public void onBoardInitEnded() {
		arduinoLed.setStatus(BLEGeneralIO.GENERAL_IO_DO);
	}

	@Override
	public void onDigitalInputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

	}

	@Override
	public void onAnalogValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
	}

	@Override
	public void onDigitalOutputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

	}

	@Override
	public void onServoValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

	}

	@Override
	public void onPWMValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

	}

	@Override
	public void onGeneralIOStatusChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

	}

	@Override
	public void onSetGeneralIOParameter(BLEGeneralIOEvent bleGeneralIOEvent) {

	}
});

and in the same way the button:

  • it is set as digital output
  • the button handling is perfomerd by the onDigitalInputValueChanged method implementation: button state is checked and the led is toggled accordingly. In order to give a feedback on the app's UI as well, the Textview change accordingly too.
arduinoButton.setOnGeneralIOEventListener(new BLEOnGeneralIOEventListener() {
	@Override
	public void onBoardInitEnded() {
		arduinoButton.setStatus(BLEGeneralIO.GENERAL_IO_DI);
	}

	@Override
	public void onDigitalInputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
		Log.d(TAG, "arduino button pressing: "+ bleGeneralIOEvent.values[1]);
		if(bleGeneralIOEvent.values[1]==1)
		{
			Log.d(TAG, "arduino led: setting HIGH");
			arduinoLed.setDigitalValueHigh(true);
			(MainActivity.this).runOnUiThread(new Runnable() {
				  @Override
				  public void run() {
					  tvButtonState.setText("Button PRESSED");
					  tvButtonState.setTextColor(Color.BLUE);
				  }
			  }
			);
		} else {
			Log.d(TAG, "arduino led: setting LOW");
			arduinoLed.setDigitalValueHigh(false);
			(MainActivity.this).runOnUiThread(new Runnable() {
			  @Override
			  public void run() {
					  tvButtonState.setText("Button not pressed");
					  tvButtonState.setTextColor(Color.RED);
				  }
			  }
			);
		}
	}

	@Override
	public void onAnalogValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

	}

	@Override
	public void onDigitalOutputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

	}

	@Override
	public void onServoValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

	}

	@Override
	public void onPWMValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

	}

	@Override
	public void onGeneralIOStatusChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

	}

	@Override
	public void onSetGeneralIOParameter(BLEGeneralIOEvent bleGeneralIOEvent) {

	}
});

Below the full MainActivity.java source code is reported: it is sufficient for you to copy it in Android Studio and save it!

NOTE: At the line 'package com.example.my.sarduino;', you will have to insert your username, instead of 'my'.

import android.content.res.ColorStateList;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

import eu.angel.bleembedded.lib.BLEContext;
import eu.angel.bleembedded.lib.item.generalIO.BLEGeneralIO;
import eu.angel.bleembedded.lib.item.generalIO.BLEGeneralIOEvent;
import eu.angel.bleembedded.lib.item.generalIO.BLEOnGeneralIOEventListener;

public class MainActivity extends AppCompatActivity {

    protected static final String TAG = "MainActivity";

    TextView tvButtonState;
    BLEGeneralIO arduinoButton;
    BLEGeneralIO arduinoLed;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        BLEContext.initBLE(this);

        tvButtonState=(TextView) findViewById(R.id.tvButtonState);
        arduinoLed = (BLEGeneralIO) BLEContext.findViewById("arduino_rbs_general_io_5");
        arduinoButton = (BLEGeneralIO) BLEContext.findViewById("arduino_rbs_general_io_2");

        arduinoLed.setOnGeneralIOEventListener(new BLEOnGeneralIOEventListener() {
            @Override
            public void onBoardInitEnded() {
                arduinoLed.setStatus(BLEGeneralIO.GENERAL_IO_DO);
            }

            @Override
            public void onDigitalInputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

            }

            @Override
            public void onAnalogValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
            }

            @Override
            public void onDigitalOutputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

            }

            @Override
            public void onServoValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

            }

            @Override
            public void onPWMValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

            }

            @Override
            public void onGeneralIOStatusChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

            }

            @Override
            public void onSetGeneralIOParameter(BLEGeneralIOEvent bleGeneralIOEvent) {

            }
        });

        arduinoButton.setOnGeneralIOEventListener(new BLEOnGeneralIOEventListener() {
            @Override
            public void onBoardInitEnded() {
                arduinoButton.setStatus(BLEGeneralIO.GENERAL_IO_DI);
            }

            @Override
            public void onDigitalInputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
                Log.d(TAG, "arduino button pressing: "+ bleGeneralIOEvent.values[1]);
                if(bleGeneralIOEvent.values[1]==1)
                {
                    Log.d(TAG, "arduino led: setting HIGH");
                    arduinoLed.setDigitalValueHigh(true);
                    (MainActivity.this).runOnUiThread(new Runnable() {
                          @Override
                          public void run() {
                              tvButtonState.setText("Button PRESSED");
                              tvButtonState.setTextColor(Color.BLUE);
                          }
                      }
                    );
                } else {
                    Log.d(TAG, "arduino led: setting LOW");
                    arduinoLed.setDigitalValueHigh(false);
                    (MainActivity.this).runOnUiThread(new Runnable() {
                      @Override
                      public void run() {
                              tvButtonState.setText("Button not pressed");
                              tvButtonState.setTextColor(Color.RED);
                          }
                      }
                    );
                }
            }

            @Override
            public void onAnalogValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

            }

            @Override
            public void onDigitalOutputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

            }

            @Override
            public void onServoValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

            }

            @Override
            public void onPWMValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

            }

            @Override
            public void onGeneralIOStatusChanged(BLEGeneralIOEvent bleGeneralIOEvent) {

            }

            @Override
            public void onSetGeneralIOParameter(BLEGeneralIOEvent bleGeneralIOEvent) {

            }
        });

    }
}

Mount the circuit

You are almost done! One of the last passages is the mounting of the circuit, as you can see in the following picture:

NOTE: Unfortunately, we don't have the correct image for the RedBear BLE Shield, so you wont see it in the figure. Anyway, the pin are exactly the same, so it shouldn't be a problem to connect them.

schema1.png


Let's run it

Finally run the application connecting the smartphone to the PC with the USB micro cable. Clicking Run button in Android Studio and selecting the connected smartphone the application will be deployed and run on it.

NOTE: If you are not familiar with this procedure, you can find everything you need to know at this link.

In this example, pressing/releasing the remote button toggles the led state on/off.

arduino-run.jpg

NOTE: If devices do not connect at startup, please shutdown all Bluetooth applications already running, like the BleembeddedFlasher app or previously launched versions of our app.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.