android LinkedList , strange behavior - android

I have an ArrayList of LinkedList to store my sensors captured data in a thread ( using synchronized on the ArrayList object)
upon capture, sensor events are added, I can see the linkedlist increasing, but the first and last element are ALWAYS the last capture event .. something is wrong somewhere ... ?
// main thread ('samplingFifoQueues' passed as an arg to be synchronized ...)
public volatile LinkedList<SensorEvent> accelFifoQueue = new LinkedList<SensorEvent>();
public volatile LinkedList<SensorEvent> magnetFifoQueue = new
.......
public volatile ArrayList<LinkedList<SensorEvent>> samplingFifoQueues = new ArrayList<LinkedList<SensorEvent>>();
In my capture thread , I add the sensor events
LinkedList<SensorEvent> accelFifoQueue;
LinkedList<SensorEvent> magnetFifoQueue;
......
ArrayList<LinkedList<SensorEvent>> samplingFifoQueues;
.....
public void onSensorChanged(SensorEvent sensorEvent) {
...
synchronized (samplingFifoQueues) {
switch (sensorEvent.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
Log.d(TAG, "new accel sensor event at: " + sensorEvent.timestamp );
accelFifoQueue.add(sensorEvent);
SensorEvent nse = accelFifoQueue.getLast();
SensorEvent lse = accelFifoQueue.getFirst();
Log.d(TAG, "accel: " + accelFifoQueue.size() + " elements, last at: " + nse.timestamp + " , first at: " + lse.timestamp);
break;
....
The log output indicate first and last timestamp after each new event , and the first is ALWAYS = to the last, even if the size is increasing :
new accel sensor event at: 1391793870096061895
accel: 1 elements, last at: 1391793870096061895 , first at: 1391793870096061895
new accel sensor event at: 1391793870117302130
accel: 2 elements, last at: 1391793870117302130 , first at: 1391793870117302130
new accel sensor event at: 1391793870121208380
accel: 3 elements, last at: 1391793870121208380 , first at: 1391793870121208380
new accel sensor event at: 1391793870129020880
accel: 4 elements, last at: 1391793870129020880 , first at: 1391793870129020880

as per answer in post : How to make a copy of the Android Sensor SensorEvent Object
the sensorEvent is overwritten... it's a system class so I need to do my own clone object...

This is because you are using ArrayList, and ArrayList was stored sensor event objet's reference, so, all you added to this array list may be the same object's reference, this is why elements in array list are ALWAYS the last capture event.

Related

Counting issues during real-time tracking on Android

I am making an app using ML KIT. I am currently implementing counting while doing squats. The problem is that it counts when it goes down to a certain angle, but because it is a real-time tracking, it counts multiple times rather than once. In other words, practically when I do one squat, the counting is much more than that.
So I tried solving the problem using a timer handler. But I failed. Here is my code What should I do?
//going down
if((rightKneeAngle<=90 && leftKneeAngle<=90) || (rightHipAngle<=135 && leftHipAngle<=135)){
//Timer setting
mTimer.schedule(new CustomTimer(), 2000);
Log.d("PoseGraphic.class", "goingdown"+"rightKneeAngle : " + rightKneeAngle+ " leftKneeAngle : " + leftKneeAngle);
Log.d("PoseGraphic.class","leftHip"+leftHipAngle+"RighHip"+rightHipAngle);
Log.d("PoseGraphic.class", "cnt: " + cnt);
//going up
if((rightKneeAngle>170 && leftKneeAngle>90)|| (rightHipAngle>135 && leftHipAngle>135)){
Log.d("PoseGraphic.class", "going up"+"rightKneeAngle : " + rightKneeAngle+ " leftKneeAngle : " + leftKneeAngle);
Log.d("PoseGraphic.class","leftHip"+leftHipAngle+"RightHip"+rightHipAngle);
if(cnt==12) {
canvas.drawText("complete!", x, y, textPaint);
//ExerciseCount.cnt = 0;
cnt=0;
}
}
}
// TIMER handler class
class CustomTimer extends TimerTask
#Override
public void run() {
cnt++;
}
I cannot fully understand how you do it without seeing more code.
An suggestion would be:
Instead of +1 to the count when the pose is in squat_down state, record the entering of that state with a boolean and +1 to the count only once the user exit squat_down and enter squat_up state. Then reset the state boolean.
By doing this, you will only +1 when user finish an entire cycle from squat_down to up.
Actually, ML Kit just launched an example for squat and pushup classification and rep-counting. Here is the app you can try. If you want to classify some other poses, here is some guide and a Colab.

How can I use the Magnetometer from this Sensor API?

I'm trying to get use the magnetometer from this Sensor API but I'm not sure if I'm doing so correctly.
I copied and edited the example code from the their site into my test site;
let sensor = new Magnetometer();
sensor.start();
sensor.onreading = () => {
console.log("Magnetic field along the X-axis " + sensor.x);
console.log("Magnetic field along the Y-axis " + sensor.y);
console.log("Magnetic field along the Z-axis " + sensor.z);
document.getElementById("x").innerHTML = "X = " + sensor.x;
document.getElementById("y").innerHTML = "Y = " + sensor.y;
document.getElementById("z").innerHTML = "Z = " + sensor.z;
};
sensor.onerror = event => console.log(event.error.name, event.error.message);
But when I load the page it doesn't give me any readings. Checking the site on my laptop brings back this error message;
Uncaught ReferenceError: Magnetometer is not defined
at magnetometer.js:1
Any insight into this would be greatly appreciated.
I found the answer. After looking around I found that you need to go to chrome://flags/#enable-generic-sensor-extra-classes and enable Generic Sensor Extra Classes.
I'm not sure why this is the case but I am now getting the readings I was after.

Sensor data is written multiple times when using Asynctask

I write an app to save sensors data into a file. Goal is to save IMU datas with 100 Hz.
I use Asynctask for the storage part. All seems well; but when i saw values in file, there's a many data written many times. Do you have any ideas:
#Override
public final void onSensorChanged(SensorEvent event) {
//timestamp = (new Date()).getTime() + (event.timestamp - System.nanoTime()) / 1000000L;
timestamp = new Date().getTime();
// Handle accelerometer reading
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
bufferData[0] = event.values[0];
bufferData[1] = event.values[1];
bufferData[2] = event.values[2];
}
// Handle a gyro reading
else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
bufferData[3] = event.values[0];
bufferData[4] = event.values[1];
bufferData[5] = event.values[2];
}
save_IMU save_imu = new save_IMU();
save_imu.execute();
}
AsyncTask is not good choice for your problem.
You'r asynctask reads shared data from the bufferData array which is overiden each time sensor value changes. The AsyncTask is not started in the moment you call execute method. It's put into a queue and than it is waiting for free thread to be executed. So it can take same time before it'll run. Writing to the storage can be slower than you need so the queue will fill up and more tasks can be run between two onSensorChanged calls. Than they can write multiple equal rows as you see.
My suggestion:
Create queue / buffer for measured values. Add new items in onSensorChanged
Use Handler to periodically (e.g. each 250ms) check buffer and write items to disk (more at on run). If you don't want to experiment with handlers it can be also done with AsyncTask.
bufferData should be a local variable of onSensorChanged() function.
You should transfer the buffer to the asynctask with new save_IMU(bufferData );.

Leveraging Sensor batching

I'm trying to utilize the max fifo size of Accelerometer on Nexus 6
SensorManager sensorManager =
(SensorManager) getSystemService(Context.SENSOR_SERVICE);
Sensor sensor = sensorManager.getDefaultSensor(typeAccelerometer);
Log.e("test",
"Max delay: " + sensor.getMaxDelay() + " - Fifo count" + sensor.getFifoReservedEventCount()); // prints 1000000 (1 second) - Fifo count 10000
// Register the listener for this sensor in batch mode.
// Following code reports every 190ms when screen is ON, and every 10 seconds when screen is OFF. I always want every 10 seconds.
final boolean batchMode = sensorManager.registerListener(
mListener, sensor, 1000000 /* 1 second */, 10000000 /* 10 seconds */);
private final SensorEventListener mListener = new SensorEventListener() {
long lastTimeStamp;
#Override
public void onSensorChanged(SensorEvent event) {
long current = System.currentTimeMillis();
long time = current - lastTimeStamp;
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
Log.e("test",
"New ACCELERO "+ " -> "+ time + "ms -> " + (int)event.values[0] + " -> "+ (int)event.values[1] +" -> "+ (int)event.values[2]);
lastTimeStamp = current;
}
}
#Override
public void onAccuracyChanged(Sensor s, int accuracy) {
}
};
When Screen is ON, I get the events every 190ms. However, when screen is off, it obeys 10 seconds.
How do I utilize the full batching FIFO (with delayed listeners) when screen is ON, for minimal CPU impact.
Code above is fine. On Nexus 6, accelerometer doesnt batch as long as screen is ON. All other sensors do fine.
sensor.getFifoReservedEventCount() returns the amount of values it can store, i dont think its time in ms
Beware of the third argument to registerListener. It is not in seconds like you wrote:
final boolean batchMode = sensorManager.registerListener(
mListener, sensor, 1000000 /* WRONG */, 10000000);
It should be one of the following constants:
SENSOR_DELAY_NORMAL
SENSOR_DELAY_UI
SENSOR_DELAY_GAME
SENSOR_DELAY_FASTEST.
Source: https://developer.android.com/reference/android/hardware/SensorManager.html#registerListener(android.hardware.SensorEventListener,%20android.hardware.Sensor,%20int,%20int)

ORMLite's createOrUpdate seems slow - what is normal speed?

Calling the ORMLite RuntimeExceptionDao's createOrUpdate(...) method in my app is very slow.
I have a very simple object (Item) with a 2 ints (one is the generatedId), a String and a double. I test the time it takes (roughly) to update the object in the database (a 100 times) with the code below. The log statement logs:
time to update 1 row 100 times: 3069
Why does it take 3 seconds to update an object 100 times, in a table with only 1 row. Is this the normal ORMLite speed? If not, what might be the problem?
RuntimeExceptionDao<Item, Integer> dao =
DatabaseManager.getInstance().getHelper().getReadingStateDao();
Item item = new Item();
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
item.setViewMode(i);
dao.createOrUpdate(item);
}
long update = System.currentTimeMillis();
Log.v(TAG, "time to update 1 row 100 times: " + (update - start));
If I create 100 new rows then the speed is even slower.
Note: I am already using ormlite_config.txt. It logs "Loaded configuration for class ...Item" so this is not the problem.
Thanks.
This may be the "expected" speed unfortunately. Make sure you are using ORMLite version 4.39 or higher. createOrUpdate(...) was using a more expensive method to test for existing of the object in the database beforehand. But I suspect this is going to be a minimal speed improvement.
If I create 100 new rows then the speed is even slower.
By default Sqlite is in auto-commit mode. One thing to try is to wrap your inserts (or your createOrUpdates) using the the ORMLite Dao.callBatchTasks(...) method.
In by BulkInsertsTest android unit test, the following doInserts(...) method inserts 1000 items. When I just call it:
doInserts(dao);
It takes 7.3 seconds in my emulator. If I call using the callBatchTasks(...) method which wraps a transactions around the call in Android Sqlite:
dao.callBatchTasks(new Callable<Void>() {
public Void call() throws Exception {
doInserts(dao);
return null;
}
});
It takes 1.6 seconds. The same performance can be had by using the dao.setSavePoint(...) method. This starts a transaction but is not as good as the callBachTasks(...) method because you have to make sure you close your own transaction:
DatabaseConnection conn = dao.startThreadConnection();
Savepoint savePoint = null;
try {
savePoint = conn.setSavePoint(null);
doInserts(dao);
} finally {
// commit at the end
conn.commit(savePoint);
dao.endThreadConnection(conn);
}
This also takes ~1.7 seconds.

Categories

Resources