Tuesday, February 19, 2013

Detecting speed bumps with accelerometer

Somebody came in from the internet some months ago and asked whether speed bumps (also called sleeping policemen) can be detected with an Android phone. You know, speed bumps like this:

I was cautious because there's a lot of traps here. Obviously the detected signal will differ depending on the form factor of the speed bump, the type of the car and even the way the phone is fixed to the car (or the lack of fixing). But I was also curious and as car-related phone applications are very fashionable today, I took the challenge. Meanwhile the guy who brought up the problem disappeared so I feel free to share what I achieved during the last one and half months.

The solution that I produced is far from perfect. First and foremost, I did not make any effort to target other phones than my trusty Nexus S. Phones which have sampling frequency of around 50 Hz in SENSOR_DELAY_FASTEST mode will work fine, significantly different sampling frequencies are not supported. It is more important, however, that I was not able to create a foolproof algorithm for the problem.

Initially I thought that some sort of rotation could be measured when the front of the car is lifted by the speed bump but I was not able to detect this rotation from the sensor signal. The car generates all sorts of vibrations and it is not easy to extract this relatively small rotation from the noisy background. So I went back to the acceleration spike which is generated when the car hits the bump and I used just the acceleration's absolute value as described in this presentation. The trouble is that this spike is pretty reminiscent of a class of other spikes like knocks, etc. For example here is a beautiful double street bump somewhere in Budapest.

One would think that signals like these could be easily detected. Now comes, however, a bumpy road with potholes, also typical in Budapest.

There are no street bumps in the second signal but the potholes generate "knocks" that are hard to distinguish from the "knocks" caused by street bumps.

There is no perfect solution to this problem, at least I could not find any. Eventually I obtained the best result by calculating the cross-correlation between the acceleration signal and a pre-recorded speed bump signal. I re-sampled this representative signal for +/- 10% of its initial frequency and calculated the cross-correlation with all the three variants (initial, +10% frequency, -10% frequency). Then I used a sliding window to calculate the power of the cross-correlation signal. This is the pre-recorded sample I used for cross-correlation:

Cross-correlating then calculating the power in a sliding window yields this signal for the double speed bump (different colors show the power of the 3 variants of the re-sampled signal):

And this is the result of the same calculation for the bumpy road:






Using a limit of about 150, the two signals can be separated and no fake bumps are detected even on the bumpy road.

Click here to download the example program.

There are a lot of problems with this approach. First, speed bumps come in all shapes and sizes and this method can detect speed bumps that are similar to the one used to generate the reference signal. Then there is the problem of the car itself. I did not have the chance to test with a lot of different cars but I bet the different suspension systems will yield drastically different signals in different car types. Anyway, I thought somebody may find this post and this post can start some thinking.






Tuesday, June 19, 2012

Universal orientation, gravity and motion acceleration sensor

We have seen a number of fusion possibilities for 2 sensors.


Time has come to put all of these together and to take a step toward the Holy Grail of sensor processing. We want a sensor that measures gravity, motion acceleration and orientation reliably, no matter what the circumstances are. If we achieve this, then we have a good basis for the much researched in-door navigation problem because the linear acceleration may be used for step counting while the orientation can be used to calculate the vector of movement. Errors will accumulate but if we have occasional reference points like WiFi beacons, reasonably good results can be achieved.


So what prevents us realizing this vision? We already obtained a pretty reliable motion acceleration estimation from the accelerometer-gyroscope fusion. The orientation is the thing we don't have. Using the compass-accelerometer fusion we can eliminate the tilt problem. If we throw in the gravity calculation from the accelerometer-gyroscope fusion and use the gravity estimation instead of the raw accelerometer data for the compass tilt compensation then we have also compensated the motion acceleration. The only thing we don't have is the effect of external magnetic fields which may fool the compass and can be pretty nasty in-door in the presence of household appliances, large transformators or other electric machinery. That we will compensate with a compass-gyroscope fusion.


The idea of the compensation of the external magnetic field using the gyroscope is very similar to the compensation of the motion acceleration. If we assume that no external magnetic field is present (beside the Earth's magnetic field), we just use the compass data (and then post-compensate against tilt by the gravity vector which needs accelerometer-gyroscope fusion). If we suspect that there may be external magnetic field present, we use the gyroscope rotation data to rotate a previous, trusted compass vector (that is supposed to measure only the Earth's magnetic field) and use that as compass estimation. The difference between this compass estimation and the measured compass value is the estimation for the external magnetic field.


The trick is the detection whether an external magnetic field may be present. In this prototype the same trick was used as with the accelerometer: if the length of the compass vector is too long or too short compared to the reference measurement, then we have an external magnetic field to compensate.

Here is the summary of the sensor fusions used in this prototype:


  • Accelerometer-gyroscope fusion provides gravity and motion acceleration.
  • Compass-gravity fusion provides compass tilt compensation. The gravity is already a derived measurement coming from the accelerometer-gyroscope fusion.
  • Compass-gyroscope fusion provides orientation and external magnetic field.
Click here to download the example program.

The example program starts with a complex stationary and dynamic calibration process. When stationary, it measures the reference gravity and magnetic field values. In this stage it is very important that the device is not subject to motion acceleration or external magnetic field (beside the Earth's magnetic field). In the dynamic calibration phase we calculate the bias of the compass. We do this by instructing the user to rotate the device and measuring compass vectors in each special position. These are supposed to be points on a sphere. Once we collected the measurement points, we calculate the center of the sphere by solving a set of linear equations. The Jama package was incorporated into the example program for matrix manipulations.

Once the calibration is finished, the algorithm outlined above is executed. The measurement data is visualized in a 2D coordinate system - the z coordinate is not drawn. This is just my laziness, I did not take the effort to implement a 3D visualization engine. It is important to note, however, that the motion acceleration (yellow) and the external magnetic field (cyan) vectors are really 3D, they are just not drawn as such. The white vector is the final orientation compensated against tilt, motion acceleration and external magnetic field.




The prototype does have limitations. While it survives pretty nicely short-term disturbances from external magnetic fields (try with a small magnet), in longer term (e.g. after 5-10 minutes) it gets properly lost. For example when riding the Budapest underground there are strong and varying magnetic fields generated by the train's traction motors during the entire journey. If the compensation algorithm picks up a wrong reference vector, it may get lost for the rest of the journey until it is able to pick up the Earth's undisturbed magnetic field.

Saturday, May 12, 2012

Landmark

My name as a Tunis landmark.

  
 I will talk about accelerometer and gyroscope sensor integration tomorrow at Droidcon Tunis.


Thursday, April 12, 2012

3D transition animation between Activities

I have got a question in this post on the Sfonge site whether it is possible to create a 3D transition effect between two Activities. There is a sample program that does it among the API Demos but this program plays the transition effect between two views of the same Activity. The adaptation to do the same between two activities is not very complicated but has some tricks, that's why I decided to publish this example program.

Click here to access the example program.

First and foremost, I unashamedly stole the custom 3D animation from the API Demos application, that's what you find in Rotate3dAnimation.java. It is invoked in the landing Activity (Activity3dTransitionActivity) when the user initates transition to the second Activity (Screen2Activity) using the menu. The trick here is to attach an animation listener to the 3D animation object, start the animation in the outgoing Activity and only invoke startActivity() when the animation finishes. Note the overridePendingTransition( 0,0 ) invocation; this ensures that the system itself will not play any activity transition animation.

The incoming Screen2Activity seems simple but there is hidden gem here too. Observe that the top layout of the activity (in screen2.xml) is not a stock LinearLayout but a descendant (aexp.activity3dtransition.AnimatedLinearLayout). Overriding onMeasure() in this subclass makes sure that the incoming animation is started only after the elements of the layout (a single TextView here) have been laid out.

Sunday, April 1, 2012

Stabilizing compass with the accelerometer

Let's explore sensor fusion possibilities of the compass and the accelerometer a bit further. In the previous post we used the compass to calculate the gravity vector when the accelerometer is subject to motion acceleration too. Now let's support the compass with the accelerometer and create a stabilized compass.

As we discussed before, the Earth's magnetic field is a 3D vector which has two components: the horizontal element that points to toward the magnetic North (this is what we use for compass) and the magnetic inclination that has variable degree but points mostly down on the Northern Hemisphere. Now if the magnetic sensor is not parallel to the Earth's surface, the z component (pointing downward) of the Earth's magnetic vector is projected into the x and y axes of the phone's magnetic sensor causing the compass to rotate when the device is tilted. Try for example this great and popular compass application. Point the compass toward the North then tilt the device left and right. You will see that the compass rotates even though the longer axis of the device (the y axis in Android API) still points toward the North Pole.

This is a major problem in normal compasses that have only magnetic sensor, that's why complex mechanical systems are used to keep the compass horizontal e.g. on ships. Fortunately our Android phones have accelerometer beside the magnetic sensor and we can use that accelerometer to figure out of the device's tilt. Note that this time we assume that we don't have motion acceleration present. If we have and the phone is also equipped with gyroscope then we can additionally compensate the motion acceleration with the gyroscope as we discussed previously. This time, however, we play it simple and we assume that the accelerometer measures only the gravity acceleration and points toward the center of the Earth.

The example program can be downloaded from here.

The application is a variation of our previous example where we used the compass to compensate the motion acceleration. The compass calibration logic is the same. After the calibration the data is visualized differently. The red arrow points toward the North as calculated from the x and y components of the magnetic sensor and that's what most of the compass applications out there measures. The white arrow shows the North by the tilt-compensated compass. As the magnetic sensor and the accelerometer measures in the same coordinate system (the device's coordinate system), both vectors are subject to the same roll and pitch. The tilt-compensation algorithm calculates the rotation axis and angle between the gravity vector as measured by the accelerometer and the z (downward) axis. Then it rotates the magnetic vector measured by the magnetic sensor by the same axis and angle.


Tuesday, March 27, 2012

4-level expandable list views

A while ago I got a question if 3-level expandable list views can be implemented in Android. Android does not explicitly support it but the flexibility of Android UI widget framework provides a relatively simple implementation option: second-level expandable list views are to be inserted into the first-level expandable list view as child views. There was a blog post with an example program and everybody was happy. Even then I made a note that I don't agree with the approach from the UI point of view because the display becomes unnecessarily messy.

Now there was a comment at that blog post whether 4-level lists are possible. Of course they are possible, it is just not a good UI design. But I guess, you better try it yourself if you don't believe me. The principle is the same (expandable lists embedded as children of higher-level expandable lists), it is just much more complex to make sure that everything is recalculated correctly for every event. In order to follow the operation, I left a good amount of debugging code in the project.

Click here to access the example program.