You are here

Non-invasive measurement of distances with Arduino Yun [Part 2]

We will see how to develop an application (Android App) that allows measurement of distances using device (ideal for distances difficult to measure such as height of a ceiling, or useful as an assistant to parking car).

To be used is required to have Arduino Yun and a small ultrasonic sensor. App communicates with AndroidYun through REST services provided by board and auto-configured within the application.

MaxSonar MB1010 Ultrasonic Sensor

 

0001331_mb1010-lv-maxsonar-ez1-high-performance-ultrasonic-rangefinder_300

 

 

Attach n°1 shown characteristics and the pins used by the sensor.

 

Given Arduino 5V supply and the value between 0 and 1023 of analog pins managed of the board, the output value (programmatically managed by app) measured in cm will be:

CvS = (2,54 [cm/inch]) / (Vout Sensor [V/inch]) * (5/1023) =  2,54 /(5/512)*(5/1023) = 1,271 where 5/512 is scaling factor of sensor (output analog value of Pin AN).

 

Below the UML (class diagram) of android project and the main codes of the classes.

 

class1

Manifest on Android App

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
 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.lombardo.distancemt"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.lombardo.distancemt.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.lombardo.distancemt.StartActivity" />
        <activity android:name="com.lombardo.distancemt.OptionsActivity" />
        <activity android:name="com.lombardo.distancemt.InfoActivity" />
        <service android:name="com.lombardo.distancemt.AndroidYunGetService" >
        </service>
    </application>
</manifest>

AndroidYunGetService

The class must be extended the abstract class android.app.Service. The Service development guidelines are here : http://developer.android.com/reference/android/app/Service.html The most important method on this class is onStartCommand().

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package com.lombardo.distancemt;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
 
import org.json.JSONException;
import org.json.JSONObject;
 
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
 
public class AndroidYunGetService extends Service {
 
	public static final String DEBUG_TAG = "AndroidYunGetService";
	protected static final String ACTION_START = "YUN.START"; // Action // to //
																// start
	protected static final String URL_PATH = "YUN.URL_PATH"; // Example
																// "http://"+ARDUINO_IP_ADDRESS+"/data/get/D13"
	protected static final String NAME_RESULT_EVENT = "YUN.GET_RESULT_EVENT";
	protected static final String RESULT_VALUE = "YUN.RESULT_VALUE";
	protected static final String KEY_RETURN = "value";// to sketch
 
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}
 
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
 
	}
 
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
	}
 
	/**
	 * 
	 */
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
 
		String action = intent.getAction();
 
		Log.i(DEBUG_TAG, "Received action of " + action);
 
		if (action == null) {
			Log.i(DEBUG_TAG, "Starting service with no action\n Probably from a crash");
		} else {
 
			if (action.equals(ACTION_START)) {
 
				final String urlPath = intent.getStringExtra(URL_PATH);
 
				//
				new Thread() {
 
					public void run() {
 
						Log.i(DEBUG_TAG, "Received ACTION_START");
 
						// Begin Downtime to not charge cpu
 
						try {
 
							Thread.sleep(150);
 
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
 
						// End Downtime to not charge cpu
 
						String json_string = readURL(urlPath);
 
						JSONObject jsonMain = null;
 
						String value = null;
 
						try {
 
							jsonMain = new JSONObject(json_string);
 
							value = jsonMain.get(KEY_RETURN).toString();
 
							Log.i(DEBUG_TAG, "Value forn json: " + value);
 
							publishResults(value);
 
						} catch (JSONException ej) {
							Log.i(DEBUG_TAG, ej.getMessage());
						}
 
					}
				}.start();
 
			}
		}
 
		return START_REDELIVER_INTENT;
	}
 
	/**
	 * readURL
	 * 
	 * @param value
	 * @return
	 */
	private String readURL(String value) {
		URL url;
		StringBuilder builder = new StringBuilder();
		try {
			url = new URL(value);
			URLConnection yc = url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
			String inputLine;
			while ((inputLine = in.readLine()) != null) {
				builder.append(inputLine);
			}
			in.close();
		} catch (MalformedURLException e) {
			e.printStackTrace();
			Log.i(DEBUG_TAG, e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
			Log.i(DEBUG_TAG, e.getMessage());
		}
		return builder.toString();
	}
 
	/**
	 * publishResults
	 * 
	 * @param result
	 */
	private void publishResults(String result) {
 
		Intent intent = new Intent(NAME_RESULT_EVENT);
		intent.putExtra(RESULT_VALUE, result);
		LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
	}
 
}

The LocalBroadcastManager development guidelines are here : http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html

MainActivity

Screenshot_2014-02-09-11-59-51

It’s a entry point activity that trigger the three use cases of apps: Start, Options and Info.

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
77
78
79
80
81
82
83
package com.lombardo.distancemt;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
 
/**
 * 
 * @author mlombardo
 *
 */
public class MainActivity extends Activity implements OnClickListener {
 
	private static final String TAG = "MainActivity";
 
	private static final String startActivity = "com.lombardo.distancemt.StartActivity";
	private static final String optionsActivity = "com.lombardo.distancemt.OptionsActivity";
	private static final String infoActivity = "com.lombardo.distancemt.InfoActivity";
 
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
 
		super.onCreate(savedInstanceState);
 
		setContentView(R.layout.activity_main);
		findViewById(R.id.btnOptions).setOnClickListener(this);
		findViewById(R.id.btnStart).setOnClickListener(this);
		findViewById(R.id.btnInfo).setOnClickListener(this);
 
	}
 
	@Override
	public void onClick(View view) {
		switch (view.getId()) {
 
		case R.id.btnOptions:
 
			Log.v(TAG, "Tapped Options");
 
			startTargetActivity(optionsActivity);
 
			break;
 
		case R.id.btnStart:
 
			Log.v(TAG, "Tapped start");
			startTargetActivity(startActivity);
 
			break;
		case R.id.btnInfo:
 
			Log.v(TAG, "Tapped Info");
			startTargetActivity(infoActivity);
 
			break;
 
		default:
			// Unknown id.
		}
	}
 
	/**
	 * startTargetActivity
	 * 
	 * @param target
	 */
	private void startTargetActivity(String target) {
		try {
			Class<?> cls = Class.forName(target);
			Intent i = new Intent(getApplicationContext(), cls);
			i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
			i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			getApplicationContext().startActivity(i);
		} catch (ClassNotFoundException ef) {
			Log.e(this.getClass().getName(), ef.getMessage());
		}
	}
 
}

StartActivity

Activities that manages information measured by Arduino and displays it real-time to user. To do this the class uses SharedPreferences to store  option values like pin and scaling factor (hold in DistanceContextManager class). Graphic of meter is managed by an object that extends View class of Android called Distancemeter. Also the AlarmManager provides every 0,5 seconds alignment with Arduino Board.

Screenshot_2014-02-09-12-00-07

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package com.lombardo.distancemt;
 
import java.math.BigDecimal;
 
import java.util.Calendar;
 
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
 
public class StartActivity extends Activity {
	private static final String TAG = "StartActivity";
 
	private Distancemeter distancemeter;
 
	private String ARDUINO_IP_ADDRESS = "http://192.168.240.1/";
 
	private String GET_JSON_PREFIX = "data/get/";
 
	private String convertValue;
	private String pinValue;
 
	DistanceContextManager sess;
 
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_start);
		distancemeter = (Distancemeter) findViewById(R.id.Distancemeter);
 
		Intent i = new Intent(this, AndroidYunGetService.class);
		i.setAction(AndroidYunGetService.ACTION_START);
 
		sess = new DistanceContextManager(getApplicationContext());
 
		convertValue = sess.getPref().getString(DistanceContextManager.KEY_CONV_VALUE,
				String.valueOf(DistanceContextManager.defaultConvertValue()));
		pinValue = sess.getPref().getString(DistanceContextManager.KEY_PIN_VALUE, "2");
 
		String analog_read_pin = "A" + pinValue + "/";
		String URLPath = ARDUINO_IP_ADDRESS + GET_JSON_PREFIX + analog_read_pin;
		Log.d(TAG, "URLPath: " + URLPath);
		i.putExtra(AndroidYunGetService.URL_PATH, URLPath);
 
		// startService(i);
 
		Calendar cal = Calendar.getInstance();
 
		PendingIntent pintent = PendingIntent.getService(this, 0, i, 0);
 
		AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
		// Start every 0,5 seconds
		alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 500, pintent);
 
	}
 
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		Intent i = new Intent(this, AndroidYunGetService.class);
		stopService(i);
 
	}
 
	@Override
	public void onResume() {
		super.onResume();
 
		// Register mMessageReceiver to receive messages.
		LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
				new IntentFilter(AndroidYunGetService.NAME_RESULT_EVENT));
	}
 
	// handler for received Intents for the "my-event" event
	private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
 
			// Extract data included in the Intent
			String result = intent.getStringExtra(AndroidYunGetService.RESULT_VALUE);
			Log.d("mMessageReceiver", "Got message: " + result);
 
			float val = 0;
 
			try {
				val = Float.parseFloat(result);
			} catch (NumberFormatException eNum) {
				Log.d("mMessageReceiver", "Parse Error:" + result);
			}
 
			float valOut = val * Float.parseFloat(convertValue);
 
			// mProgressBar.setProgress(Double.valueOf(valOut).intValue());
			// mTextView.setText(valOut + " m");
 
			distancemeter.onDistanceChanged(valOut);
 
		}
	};
 
	@Override
	/**
	 * 
	 */
	protected void onPause() {
		// Unregister since the activity is not visible
		LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
		super.onPause();
	}
 
	/**
	 * 
	 * @param in
	 * @return
	 */
	private float convertUltrasoundResultRuntime(float in) {
 
		float valOut = 0;
		// Begin Convert
		float inch = 2.54f;
		float mb1010_factor = 0.009766f;
		float ard_ana_factor = 5f / 1023f;
		valOut = ((inch * in) / mb1010_factor) * (ard_ana_factor);
		// End Convert
 
		Log.d("convertUltrasoundResult", "Converted Value: " + valOut);
 
		float valOutRound = new BigDecimal(valOut).setScale(1, BigDecimal.ROUND_UP).floatValue();
 
		Log.d("convertUltrasoundResult", "Converted Value Round: " + valOutRound);
 
		return valOutRound;
	}
 
}

Instructions:

1) Power Arduino and open Arduino IDE

2) Perform upload of the following sketch:

#include <Bridge.h>

#include <YunServer.h>

#include <YunClient.h>

YunServer server;

int pin =2;

int value;

void setup() {

Serial.begin(9600);

Bridge.begin();

server.begin();

}

void loop() {

YunClient client = server.accept();

if (client) {

String key = ‘A’;

key += pin;

value=analogRead(2);

Bridge.put(key, String(value));

client.stop();

}

delay(50);

}

Important: the sketch is set for a connection to analog pin No. 2, but it is obviously possible to use any of pins (0 to 5) available on Arduino Yun.

3) Disconnect power from Arduino and connect ultrasonic sensor to one of the analog pins of Arduino yun, then connect power supply (5V) and GND. The application has been tested with the ultrasonic sensor MaxSonar MB1010: datasheet can be downloaded at the link

http://www.maxbotix.com/documents/MB1010_Datasheet.pdf

 

4) Power up again Arduino

 

5) Connect to wi-fi Arduino yun (SID: Yun-XXXXXXXXXXXX). All http services specified by YunMeter App vs Arduino refer to IP standard address of Arduino (192.168.240.1).

App has the  following parameters in “Option” function:

Conversion Value of Sensor (CvS)

CvS = (2,54 [cm/inch]) / (Vout Sensor [V/inch]) * (5/1023)

With MB1010 CvS = 2,54 /(5/512)*(5/1023) = 1,271

yunconf

lombamarc
I have over ten years experience in project management and software architect in complex and innovative projects for multinational ICT. I have a electronic engineer extraction with automatic specialization. For years I deal with innovation also as an active contributor to several open hardware community as Rfduino, Arduino Yun, etc ... I think that in every company there is a need to co-create ideas and innovation from every person with tools and working groups motivated and sharing and dissemination of culture at all levels. Technology and research are not enough, if there is no interaction and sharing there can be no innovation.

Leave a Reply

Top