Issue:-
I am developing a application which
needs a new acceleration datum every 5
millisecond.
My Approach:-
I have created a remote service
which only reads the acceleration
data from SensorManager.
I had also set the read rate to
"DELAY FASTEST" while initialize the
SensorManager.
Then i use IPC to communicate too my
main application to get these
reading.
Problem:-
If i put a log inside
onSensorChange() event i receive a
new sensor data every 20 ms time. But i need data every 5 ms.
Question ?
Is there any better method to read
the senor data faster.
Is there any way i can poll the
senor data rather that waiting for
the event handler to trigger the
event?
Please help me to find a better solution to read the data in 5 ms time or poll the acceleration data.
As I understand it, the accelerometer is very noisy and not suitable for fast operations. See the GoogleTech talk on sensor fusion at http://www.youtube.com/watch?v=C7JQ7Rpwn2k for a more authorative explanation and what you can do about it. Short explanation: Use the gyro for high speed events and the acceleromenter to correct the drift.
For people referencing this post today, while I think #robinr has a good point and is very true, that is not an answer, however stackoverflow wont let me comment on it directly.
For answers to the first question reference Native Activity. And. Android does not guarantee data rate, it only makes sure that you get the minimum (or maximum if you requesting too much).
The accelerometer is Not noisy, at least not today. Its just way too good at picking up EVERYTHING. So you need to use some filtering if you want a good accelerometer algorithm. If you have excellent filters, accelerometer is actually preferable to all else because it is usually a lower power sensor, has the highest supported frequency, and is most likely to be available when the screen is off(compared to other sensors).
The caveat to a forceful method of using native and extracting the highest frequency is that your device support will be limited. This is why Android doesn't support direct frequency settings.
In response to question 2; your going to have to throttle your sensor events manually by monitoring the timestamp.
Regarding the speed of the Android SensorManager, I would be more inclined to suspect the speed of the Android file I/O that is generating your log. You might try a benchmark of your sensor read code without writing to the log. Something like logging the current time in milliseconds, then doing 1,000,000 sensor reads, then logging the current time again. You might still have to use the C version to get the data, but at least you'll know definitively where the bottleneck lies.
There are a few issues I can see with this. The first is that you are most likely going to bog down the whole rest of the system if you try to force polling of sensor data that fast. If all you are doing is polling sensors that may be ok, but if you want any kind of user interaction, I am not sure that's going to work. Also, why do you need data that fast? If you're interacting with people there is no way there going to notice a lag of even 100ms.
have you resolved your problem?
i have a similar project, to get sample at least every 10 ms (about 100 Hz), here. But, nothing change in samples that i got, even when i set setEventRate = 10 milisec.
So i think there is any hardware limitation since i've read BMA220 datasheet (my sensor hardware) only provides 62,5 Hz for Orientation Sub-mode.
Related
I am developing an app that I would like to have constantly monitor accelerometer sensor data, even when the screen is off, but I would also like my battery to last longer than 5 hours :/ The most obvious thing of course is to set the sampling rate very low. I have tried to register the accelerometer with both SENSOR_DELAY_NORMAL and with a microsecond value of 1000000 (once per second) using
senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
senSensorManager.registerListener(this, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
but the Android OS quickly (after I jiggle the phone for a couple seconds) decides to override these suggested sampling rates and starts sending my app non-stop accelerometer sensor events at about 100/second, even when I turn the screen off. Needless to say, this is not good for the battery life.
What I have tried for now is a bit of a hack, and I'm wondering if 1. there is a better, Android appoved way to do it, and 2. if what I've done is going to not actually work the way that I want it to. My current solution is to immediate unregister the accelerometer after the first reading (from within the listener callback), record the time of unregistering and then to have a separate timer loop that re-registers the accelerometer listener after a half-second has passed. This seems to work, but I don't know if it's going to cause problems on some devices, or maybe the registerListener function itself drains batteries on some devices? Any advice from anybody else who has made a non-battery-draining always-on background accelerometer listener would be greatly appreciated. Thanks.
EDIT 9/7/2016:
The hack that I described above does seem to work and does seem to save significantly on battery, as long as I slow down the sampling speed to about 0.5 or 1.0 seconds. If I have any more experience, good or bad, with this technique I'll let you all know. (If it matters, I'm testing this on a Note 4, Android 5.1.1) (also added a bit more explanatory code up above)
You might want to look at how it's handled in this project:
https://github.com/alanszlosek/androidstudio-accelerometer-gps/blob/master/app/src/main/java/com/alanszlosek/whenmoving/MainService.java
Seems to be using alarms to schedule logging. Bit of a different situation with even lower sampling frequency, so I'm not sure what method is more efficient.
Would it be possible for you to stick your logger code up on github or somewhere? I'm trying to do accelerometer tracking for a grant project and having trouble getting the services and wakelocks to play well together.
What would be the best method in introducing a delay in the accelerometer readings of an Android application.
This code will be running in the intent service and it will run for long periods of time (3-6 hours at least). I'd like to make it resource efficient as well.
I'm using a Thread.Sleep() for now and I was wondering if there would be a better method to do this.
Also in the example provided in the documentation, they use a high pass filter to filter out the gravity. But would it be possible to consider the sum of all the readings on the 3 axes to be grater than 10 and simply subtract that value from the sum? (I'm only interested in the net acceleration on the phone not the directions).
Thanks!
Dear god do NOT use sleep to delay accelerometer readings. That won't actually delay readings, it will just make you react to them slower- the system will still be making readings at the same rate and in fact queue them up. If you want less frequent readings, specify so when you set up your sensor listener. It takes a frequency parameter.
You wouldn't sum the 3 and subtract 10- you'd sum their squares and subtract 100 (or more exactly, 9.8^2). But even that isn't quite right, as sensors aren't perfect, and an at rest device may not read exactly 9.8 (especially if you aren't at sea level- the gravity is less in Denver than it is in New York). Instead you should take a long term average and find out what that particular device reads at rest. Which might be what a high pass filter was doing, although I'd have to see the code to know for sure.
I'm working on Sensor fusion with Accelerometer, Gyroscope and Magnetic Field on Android. Thanks to SensorsManager I can be noticed for each new value of theses sensors.
In reality and this is the case for my Nexus 5 (I'm not sure for others Android devices), acceleration, rotation rate and magnetic field are sampled in same time. We can verify it using event.timestamp.
On others systems (like iOS, xSens...), Sensor SDK provides a notification with these 3 vectors in same time.
Of course, when I receive an acceleration(t), I can write some lines of codes with arrays to wait rotationRate(t) and magneticField(t). But if there is a way to have an access directly to these 3 vectors together it could be very interesting to know!
An other question relative to sensors data:
Is there advices from Android team to device constructors to provide data in chronological order ?
Thank you,
Thibaud
Short answer, no, Android doesn't provide a way to get all the sensor readings as it reads them.
Furthermore, the behavior that you've observed with SensorManager, namely that readings from different sensors happen to have the same timestamp suggesting that they were read together - should not be relied upon. There isn't documentation that guarantees this behavior (also, this is likely a quirk of your testing and update configuration), so relying upon it could come to bite you in some future update (and trying to take advantage of this is likely much more difficult to get right or fast than the approach I outline below).
Generally, unless all results are generated by the same sensor, it is impossible to get them all "at the same time". Furthermore, just about all the sensors are noisy so you'd already need to do some smoothing if you read them as fast as possible.
So, what you could do is sample them pretty quickly, then at specific intervals, report the latest sample from all sensors (or some smoothed value that accounts for the delta between sample time and report time). This is a trivial amount of extra code, especially if you're already smoothing noisy sensor data.
There is a workaround for this particular problem. When multiple registered listeners are present in an activty at the same time, timestamp for those event may be misleading. But you can multiple fragment objects into the said activity which have different context's. Then listen to every sensor in these fragments. With this approach the sensor reading timestamps become reliable.
Or listen in parallel threads if you know about concurrency...
The idea is Phone A sends a sound signal and bluetooth signal at the same time and Phone B will calculate the delay between the two signals.
In practice I am getting inconsistent results with delays from 90ms-160ms.
I tried optimizing both ends as much as possible.
On the output end:
Tone is generated once
Bluetooth and audio output each have their own thread
Bluetooth only outputs after AudioTrack.write and AudioTrack is in streaming mode so it should start outputting before the write is even completed.
On the receiving end:
Again two separate threads
System time is recorded before each AudioRecord.read
Sampling specs:
44.1khz
Reading entire buffer
Sampling 100 samples at a time using fft
Taking into account how many samples transformed since initial read()
Your method relies on basically zero latency throughout the whole pipeline, which is realistically impossible. You just can't synchronize it with that degree of accuracy. If you could get the delays down to 5-6ms, it might be possible, but you'll beat your head into your keyboard before that happens. Even then, it could only possibly be accurate to 1.5 meters or so.
Consider the lower end of the delays you're receiving. In 90ms, sound can travel slightly over 30m. That's the very end of the marketed bluetooth range, without even considering that you'll likely be in non-ideal transmitting conditions.
Here's a thread discussing low latency audio in Android. TL;DR is that it sucks, but is getting better. With the latest APIs and recent devices, you may be able to get it down to 30ms or so, assuming you run some hand-tuned audio functions. No simple AudioTrack here. Even then, that's still a good 10-meter circular error probability.
Edit:
A better approach, assuming you can synchronize the devices' clocks, would be to embed a timestamp into the audio signal, using a simple am/fm modulation or pulse train. Then you could decode it at the other end and know when it was sent. You still have to deal with the latency problem, but it simplifies the whole thing nicely. There's no need for bluetooth at all, since it isn't really a reliable clock anyway, since it can be regarded as having latency problems of its own.
This gives you a pretty good approach
http://netscale.cse.nd.edu/twiki/pub/Main/Projects/Analyze_the_frequency_and_strength_of_sound_in_Android.pdf
You have to create an 1 kHz sound with some amplitude (measure in dB) and try to measure the amplitude of the sound arrived to the other device. From the sedation you might be able to measure the distance.
As I remember: a0 = 20*log (4*pi*distance/lambda) where a0 is the sedation and lambda is given (you can count it from the 1kHz)
But in such a sensitive environment, the noise might spoil the whole thing, just an idea, how I would do if I were you.
Well i have successfully obtained the light value, however, it is EXTREMELY delayed. Approx 3~5 seconds even when using .SENSOR_DELAYED_FASTEST also even when entering 0 as the rate. Its so slow. I have the program check light sensor values upon screen on then change brightness accordingly HOPING it would solve the horrible automatic brightness delay. but after messing around with it, it seems to me that this is simply a flaw in android. It simply cannot update fast enough. I have used getDefaultSensor() but according to android documention this value can be delayed/filtered, but upon reading another post on stackoverflow the getSensorList() and getDefaultSensor() return the same values and that getSensorList() is no different than getDefaultSensor()
The reason for my question is: Is this correct? Is android simply a fail at updating immediatly? its funny cause my Windows MOBILE(not phone) can update immediatly and i loved it. but with all android devices ive seen its the same thing. so is this just a flaw in androids programming? Is there a way for me as an app dev to fix this? or do we have to live with it?
As I know you cannot get it faster. Please take a look on this question and answer: https://stackoverflow.com/a/5060690/1381641
I don't have the solution for your problem, but I do have an explanation for it. The Ambient light sensor has a delay because of the integration time downloads Sensor Box for android from the Playstore.
You will get the hardware ID of your ambient light sensor, then google search it, and you will get a PDF with technical details about that specific model number. Every Android or IOS phone does NOT use the same hardware.
In that PDF, you will get an integration time. It exists to keep the brightness control stable and delayed as well as sensible. If it is low, and you are in a disco your brightness level will keep on flickering. The same for outside, sometimes some shadows make it go up and down if the integration time is low. It will flicker more and will not be stable.
This will also cause harm to the backlight, so instead of taking single values they compile down the values of a big time interval. My integration time was 400ms. This value is sent to the processor, and then the decision is taken.
You could change this value. It is easy, AMD hard boh depends on your expertise like to update this you have to program the ALS unit by opening the phone, connecting a programmer to it, and connecting the pins in the right way. Then sending an 8 bit signal as mentioned in the PDF (if model is programmable).