|
Sermon Ohakwe (@admin) |
While an accelerometer won’t tell you your current speed, you can calculate a rough estimate by moni-toring changes in acceleration over time. In the following example, you’ll create a simple speedometer using the accelerometers to determine the current speed based on acceleration changes.
The sensitivity and responsiveness of the hardware accelerometers will limit the accuracy and effective-ness of this application, but the techniques it uses should give you a better understanding of how to use the accelerometer sensors for something more useful.
Because accelerometers measure the change in velocity in a given direction, you can establish your current speed by determining how long each acceleration value has been applied. For those mathemati-cally inclined, you’re finding the second derivative of the acceleration changes.
For example, if you accelerate at a steady rate of 1 m/s2 after 10 seconds, your speed will be 10 m/s (or 36 km/h). When your speed becomes steady, your acceleration should return to zero. In the real world, acceleration rarely stops and starts in an instant, nor does it remain constant, so you’ll need to adjust your velocity calculations as the measured acceleration changes.
Start by creating a new Speedometer project with a Speedometer Activity. Modify the main.xml layout resource to display a single, centered line of large, bold text that will be used to display your current speed.
<?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout
xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”vertical”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent” >
<TextView
android:id=”@+id/myTextView”
android:gravity=”center”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:textStyle=”bold”
android:textSize=”40sp”
android:text=”CENTER”
android:editable=”false”
android:singleLine=”true”
android:layout_margin=”10px”/>
/>
</LinearLayout>
Within the Speedometer Activity, create instance variables to store references to the TextView and the SensorManager. Also create variables to record the current acceleration, velocity, and the last update time.
SensorManager sensorManager;
TextView myTextView;
float appliedAcceleration = 0;
float currentAcceleration = 0;
float velocity = 0;
Date lastUpdate;
Create a new updateVelocity method that calculates the velocity change since the last update based on the current acceleration.
private void updateVelocity() {
Calculate how long this acceleration has been applied. Date timeNow = new Date(System.currentTimeMillis()); long timeDelta = timeNow.getTime()-lastUpdate.getTime(); lastUpdate.setTime(timeNow.getTime());
Calculate the change in velocity at the
current acceleration since the last update.
float deltaVelocity = appliedAcceleration * (timeDelta/1000); appliedAcceleration = currentAcceleration;
//Add the velocity change to the current velocity. velocity += deltaVelocity;
//Convert from meters per second to miles per hour. double mph = (Math.round(velocity / 1.6 * 3.6));
myTextView.setText(String.valueOf(mph) + “mph”);
}
Create a new SensorListener implementation that updates the current acceleration (and derived velocity) whenever a change in acceleration is detected.
Because a speedometer will most likely be used while the device is mounted vertically, with the screen face perpendicular to the ground, measure negative acceleration along the Z-axis.
private final SensorListener sensorListener = new SensorListener() {
double calibration - Double.NAN;
public void onSensorChanged(int sensor, float[] values) { double x = values[SensorManager.DATA_X];
double y = values[SensorManager.DATA_Y];
double z = values[SensorManager.DATA_Z];
double a = -1*Math.sqrt(Math.pow(x, 2) +
Math.pow(y, 2) +
Math.pow(z, 2));
if (calibration == Double.NaN)
calibration = a;
else {
updateVelocity();
currentAcceleration = (float)a;
}
}
public void onAccuracyChanged(int sensor, int accuracy) {}
};
Update the onCreate method to register your new Listener for accelerometer updates using the SensorManager. Take the opportunity to get a reference to the Text View.
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
myTextView = (TextView)findViewById(R.id.myTextView); lastUpdate = new Date(System.currentTimeMillis());
sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); sensorManager.registerListener(sensorListener,
SensorManager.SENSOR_ACCELEROMETER,
SensorManager.SENSOR_DELAY_FASTEST);
}
Create a new Timer that updates the speed based on the current acceleration every second. Because this will update a GUI element, you’ll need to create a new updateGUI method that synchronizes with the GUI thread using a Handler before updating the Text View.
Handler handler = new Handler();
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
myTextView = (TextView)findViewById(R.id.myTextView); lastUpdate = new Date(System.currentTimeMillis());
sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); sensorManager.registerListener(sensorListener,
SensorManager.SENSOR_ACCELEROMETER,
SensorManager.SENSOR_DELAY_FASTEST);
Timer updateTimer = new Timer(“velocityUpdate”); updateTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
updateGUI();
}
}, 0, 1000);
}
private void updateGUI()}
//Convert from m/s to mph
final double mph = (Math.round(100*velocity / 1.6*3.6)) / 100;
//Update the GUI
handler.post(new Runnable() {
public void run() {
myTextView.setText(String.valueOf(mph) + “mph”);
}
});
}
Once you’re finished, you’ll want to test this out. Given that keeping constant watch on your handset while, driving, cycling, or running is a Bad Idea, you should consider some further enhancements to the speedometer before you take it on the road.
Consider incorporating vibration or media player functionality to shake or beep with intensity propor-tional to your current speed, or simply log speed changes as they happen for later review.
If you’re feeling particularly adventurous, consider integrating your speedometer into a map to track your speed along a journey using different colored lines to represent your speed along the way.