I have a step counter app in which I am running a service which counts steps taken and then sends a broadcast to the fragment which is then updated on the fragment. The step counting is working fine but I want to calculate speed based on the steps. Here is what I am trying right now.
The receiver to get step count:
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int steps = intent.getIntExtra(StepCounterService.STEP_INCREMENT_KEY, 0);
if (firstStepTime.equals("0")) {
firstStepTime = intent.getStringExtra(StepCounterService.TIME_STAMP_KEY);
} else if (secondStepTime.equals("0")) {
secondStepTime = intent.getStringExtra(StepCounterService.TIME_STAMP_KEY);
} else {
firstStepTime = secondStepTime;
secondStepTime = intent.getStringExtra(StepCounterService.TIME_STAMP_KEY);
}
updateAllUI(steps);
}
};
So what I am doing is as soon as I start getting steps, I see if the variable firstStepTime is empty. If it is, I save the time in firstStepTime variable. The in the next step I see if secondStepTime is empty, and if it is, I save that time in secondStepTime variable.
Now for the next steps both these are updated.
public void updateAllUI(int numberOfSteps) {
if (!(firstStepTime.equals("0")) && !(secondStepTime.equals("0"))) {
try {
Calendar c = Calendar.getInstance();
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss.SSS");
timeDifference = timeFormat.parse(secondStepTime).getTime() - timeFormat.parse(firstStepTime).getTime();
speed = (float) ((0.0254 / (timeDifference * 0.001)) * 3.6);
} catch (Exception e) {
timeDifference = 0;
speed = 0;
}
textview.settext(speed +"Km/h);
}
}
So in this I just check if both are not empty, I take the values and calculate the difference in times. The problem here is sometimes it doesn't count speed properly. And a bigger problem is if the user stops, the speed remains constant and doesn't drop to zero.
Is there any better way to do the speed calculation?
As you're only counting steps and would like to calculate speed with steps taken only i am assuming that you would not like to use GPS for counting speed or you would like to provide backup speed counter if GPS is not there.
You can start a new thread by doing
int interval=1*1000; //specifying interval to check steps
Handler.postDelayed(mySpeedChecker(),1000);
You'll need to do this for every step taken
public void mySpeedChecker(){
// assuming steps taken stored in a global variable
// and there is one more variable which is updated by this function
// to store number of steps before as global variable to calculate number of steps in time interval.
// this should check if another step has been taken in the interval to check
// if stepsTaken>0 then speed is not zero and you'll know how much steps are taken
// if zero steps are taken then speed is zero
// also it will tell you number of steps taken in last second
// so you can use this to calculate and update speed
// increase the interval for high accuracy but lower frequency of updates
}
Also, it's a good idea to calculate user stride length when GPS is available so, whenever user is using GPS the step length can be calculated by finding out the distance covered/number of steps taken with the help of GPS, this will help your system calculate accurately the distance covered by user with the help of number of steps taken.
The usual way to calculate speed ideally would be using Location.getSpeed(), or some analysis on Accelerometer values. but I'm assuming you want to get it based on steps counted.
To solve one of the problems: " if the user stops, the speed remains constant and doesn't drop to zero."
You can use the Android Activity Recognition Api to see the users current activity. Use
ActivityRecognition.getMostProbableActivity()
If the DetectedActivity is type STILL, you can set your speed to be zero.
You can also get the confidence DetectedActivity.getConfidence() to be sure.
For the other problem when you said it doesn't count speed properly, could you elaborate more on that question?
Every information coming from the sensors has an amount of error and even loose of data.
You should store the information received in a queue or database including the time stamp.
Periodically, you will pick the data and analyze it, including filtering to get a more accurate information.
Hope it helps.
Related
I am writing an android app in java which uses Android phone's Step Counter sensor event values to record walking steps taken by the user.
Basically my java code to display current Steps is as follows:
if (running) {
totalSteps = event.values[0];
currentSteps = totalSteps - previousTotalSteps;
tv_stepsTaken.setText(String.valueOf(currentSteps));
}
I am using SharedPreferences to load, save and reset previousTotalSteps on a daily basis.
My problem is that when phone reboots, the totalSteps event value from Step Counter Sensor is reset automatically to zero, hence it turns my currentSteps value to negative as previousTotalSteps value is then being subtracted from zero. Only solution that is coming to my mind is to set previousTotalSteps to zero too. But it will defeat the purpose of recording daily steps. If the user reboots the phone in the middle of the day, then half day's data will be lost or otherwise turn negative in display. I am also recording this daily steps value to sqlite database as daily history to be shown graphically to user. So, this negative value goes to sqlite databse too and ruins the historical graph. I need suggestions to solve this problem. My reset data code is as follows:
previousTotalSteps = totalSteps;
tv_stepsTaken.setText("0");
saveStepsData();
return true;
So, I have solved this problem by myself. I am posting this solution for anyone else who find themselves in this situation, so that it might help them solve it.
For this, currentSteps as well as previousSteps need to be saved to SharedPreferences after each step. Earlier only previousSteps was being saved and that too once daily.
Thus, totalSteps-previousSteps will give an increment of one step to be added to currentSteps.
In case, the phone reboots, totalSteps value is reset to zero. If that happens(or by any chance, if totalSteps is less than previousSteps), then the previousSteps value will also be set equal to totalSteps for that condition before applying both variables for current steps calculation.
if (running) {
totalSteps = event.values[0];
loadCurrentStepsData();
loadPreviousStepsData();
if (totalSteps == 0 || totalSteps<previousSteps) {
previousSteps = totalSteps;
savePreviousStepsData();
}
currentSteps = currentSteps + (totalSteps - previousSteps);
previousSteps = totalSteps;
saveCurrentStepsData();
savePreviousStepsData();
}
tv_stepsTaken.setText(String.valueOf(currentSteps));
in my model I have 9 different service blocks and each service can produce 9 different features. Each combination has a different delay time and standard deviation. For example feature 3 need 5 minutes in service block 8 with a deviation of 0.05, but only needs 3 minutes with a deviation of 0.1 in service block 4.
How can I permanently track the last 5 needed times of each combination and calculate the average (like a moving average)? I want to use the average to let the products decide which service block to choose for the respective feature according to the shortes time comparing the past times of all of the machines for the respective feature. The product agents already have a parameter for the time entering the service and one calculating the processing time by subtracting the entering time from the time leaving the service block.
Thank you for your support!
I am not sure if I understand what you are asking, but this may be an answer:
to track the last 5 needed times you can use a dataset from the analysis palette, limiting the number of samples to 5...
you will update the dataset using dataset.add(yourTimeVariable); so you can leave the vertical axis value of the dataset empty.
I assume you would need 1 dataset per feature
Then you can calculate your moving average doing:
dataset.getYMean();
If you need 81 datasets, then you can create a collection as an ArrayList with element type DataSet
And on Main properties, in On Startup you can add the following code and it will have the same effect.
for(int i=0;i<81;i++){
collection.add(new DataSet( 5, new DataUpdater_xjal() {
double _lastUpdateX = Double.NaN;
#Override
public void update( DataSet _d ) {
if ( time() == _lastUpdateX ) { return; }
_d.add( time(), 0 );
_lastUpdateX = time();
}
#Override
public double getDataXValue() {
return time();
}
} )
);
}
you will only need to remember what corresponds to what serviceblock and feature and then you can just do
collection.get(4).getYMean();
and to add a new value to the dataset:
collection.get(2).add(yourTimeVariable);
I have written a 2x2x2 rubiks cube solver that uses a breadth first search algorithm to solve a cube position entered by the user. The program does solve the cube. However I encounter a problem when I enter in a hard position to solve which would be found deep in the search, I run out of heap space. My computer only has 4 GB of RAM and when I run the program I give 3GB to it. I was wondering what I could do to reduce the amount of ram the search takes. Possibly by changing a few aspects of the BFS.
static private void solve(Cube c) {
Set<Cube> cubesFound = new HashSet<Cube>();
cubesFound.add(c);
Stack<Cube> s = new Stack<Cube>();
s.push(c);
Set<Stack<Cube>> initialPaths = new HashSet<Stack<Cube>>();
initialPaths.add(s);
solve(initialPaths, cubesFound);
}
static private void solve(Set<Stack<Cube>> livePaths, Set<Cube> cubesFoundSoFar) {
System.out.println("livePaths size:" + livePaths.size());
int numDupes = 0;
Set<Stack<Cube>> newLivePaths = new HashSet<Stack<Cube>>();
for(Stack<Cube> currentPath : livePaths) {
Set<Cube> nextStates = currentPath.peek().getNextStates();
for (Cube next : nextStates) {
if (currentPath.size() > 1 && next.isSolved()) {
currentPath.push(next);
System.out.println("Path length:" + currentPath.size());
System.out.println("Path:" + currentPath);
System.exit(0);
} else if (!cubesFoundSoFar.contains(next)) {
Stack<Cube> newCurrentPath = new Stack<Cube>();
newCurrentPath.addAll(currentPath);
newCurrentPath.push(next);
newLivePaths.add(newCurrentPath);
cubesFoundSoFar.add(next);
} else {
numDupes += 1;
}
}
}
String storeStates = "positions.txt";
try {
PrintWriter outputStream = new PrintWriter(storeStates);
outputStream.println(cubesFoundSoFar);
outputStream.println(storeStates);
outputStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Duplicates found " + numDupes + ".");
solve(newLivePaths, cubesFoundSoFar);
}
That is the BFS but I fear that its not all the information needed to understand what is going on so here is the link to file with all the code. https://github.com/HaginCodes/2x2-Cube-Solver/blob/master/src/com/haginonyango/pocketsolver/Cube.java
By definition, "Best first search" keeps the entire search frontier of possible paths through the space.
That can be exponentially large. With 3x3x3 Rubik's cube, I think there are 12? possible moves at each point, so a 10 move sequence to solve arguably requires 12^10 combinations which is well over a billion (10^9). WIth this many states, you'll want to minimize the size of the state to minimize total storage. (Uh, you actually print all the states? " outputStream.println(cubesFoundSoFar);" Isnt that a vast amount of output?)
With 2x2x2, you only have 8 possible moves at each point. I don't know solution lengths here for random problems. If it is still length 10, you get 8^10 which is still pretty big.
Now, many move sequences lead to the same cube configuration. To recognize this you need to check that a generated move does not re-generate a position already visited. You seem to be doing that (good!) and tracking the number of hits; I'd expect that hit count to be pretty high as many paths should lead to the same configuration.
What you don't show, is how you score each move sequence to guide the search. What node does it expand next? This is where best comes into play. If you don't have any guidance (e.g., all move sequences enumerated have the same value), you truly will wander over a huge space because all move sequences are equally good. What guides your solver to a solution? You need something like a priority queue over nodes with priority being determined by score, and that I don't see in the code you presented here.
I don't know what a great heuristic for measuring the score as a quality of a move sequence, but you can start by scoring a move sequence with the number of moves it takes to arrive there. The next "best move" to try is then the one with the shortest path. That will probably help immensely.
(A simple enhancement that might work is to count the number of colors on a face; 3 colors hints [is this true?] that it might take 3-1 --> 2 moves minimum to remove the wrong colors. Then the score might be #moves+#facecolors-1, to estimate number of moves to a solution; clearly you want the shortest sequence of moves. This might be a so-called "admissible" hueristic score).
You'll also have to adjust your scheme to detecting duplicate move sequences. When you find an already encountered state, that state will now presumably have attached to it the score (move count) it takes to reach that state. When you get a hit, you've found another way to get to that same state... but the score for new path, may be smaller than what is recorded in the state. In this case, you need to revise the score of discovered duplicate state with the smaller new score. This way a path/state with score 20 may in fact be discovered to have a score of 10, which means it is suddenly improved.
So i wrote a java program where the user can create several data sets. The data sets consist of a URL and a time.
Now the program's job is to permanently check if the current time is equal to one of the times saved in the data sets. If the current time appears to be the same time as one of the times defined in the data sets, a browser shall be opened with the URL saved in the data set of which the time has occured to be equal to the current time.
e.g "1.dataset: url="www.justexampleurl.com", time="24.12.2015 14:00"
Correctly executed, a browser with url "justexampleurl.com" would open when the current time hits 14 o'clock on the 24th of December, 2015.
Question: What is an efficient way to handle something like that? It seems like my program has to check the time e.g. every second, if the time is equal to one of the times of the datasets.
I was thinking about the need of a thread, since it has to run seperatly while the user still is able to create new datasets.
Can I use a timer/thread for this purpose or what are my possibilities?
Thanks a lot for your help, it is greatly appreciated since I have not written anything like that!
Instead of constantly polling to check & compare the time, why not just calculate the the difference between the future time & the current time, and Thread.sleep() until the the future time arrives? If you still want the user to be able to create new datasets while the timers are running, you can deploy a new thread for each additional dataset.
class MyTimerThread extends Thread {
int seconds;
String url;
Thread(String url, int seconds) {
this.seconds = seconds;
this.url = url;
}
public void run() {
this.sleep(seconds * 1000);
//Code to open browser...
}
From your program's main execution...
public static void main() {
while(true) {
//Wait for user input (url, futureTime, currentTime)
long secondsDifference = futureTime - currentTime; //Use unixtime
(new MyTimerThread(url, secondsDifference)).start();
}
I'm using google maps android to get current location:
LatLng currentLocation = new LatLng(location.getLatitude(), location.getLongitude());
How would I construct a simple loop to produce only say every 4th currentLocation instead of every point being fed through the locationManager?
Rather than using a loop to ignore location updates, I think you should only request location updates at the frequency you would like to receive them, otherwise the device is using all the power to get the location only to have it ignored.
You should be using the LocationClient rather than LocationManager
See the following links for how to use LocationClient
http://developer.android.com/training/location/retrieve-current.html
http://developer.android.com/reference/com/google/android/gms/location/LocationClient.html#requestLocationUpdates(com.google.android.gms.location.LocationRequest, android.app.PendingIntent)
vs LocationManager
http://developer.android.com/reference/android/location/LocationManager.html#requestLocationUpdates(long, float, android.location.Criteria, android.app.PendingIntent)
but both provide methods to request location updates at a specific frequency via a
requestLocationUpdates()
Option 1 - the right one - limit location provider querying
This should somewhat optimize battery life and is how the API was intended to be used.
Assuming you use LocationManager#requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener) for obtaining current location, if you increase minTime four times you will effectively receive every fourth location update.
Option 2 - the lazy one - only update map every n seconds
This will allow you to process every location received from location provider but update map only every n seconds.
You want to keep track of when you last updated map and only update if n seconds have passed.
Declarations:
long lastTime = -1; // no location update yet
final long delta = 15 * 1000; // fifteen seconds apart
In your onLocationChanged:
// common code here, do this for every location received ...
Log.d(TAG, location + "");
// this gets executed only after fifteen seconds
if (location.getTime() > lastTime + delta) {
// update map here
lastTime = location.getTime();
}
Note that this will not ensure that you get a map update precisely every fifteen seconds. You will get the first update after fifteen seconds have passed.