How can I calculate the time of acceleration to 100kmh?
Well, I registered a location listener when the !location.hasSpeed() is true store the time of location into a variable. When the speed is reach of the given speed in this case 100km/h (27.77 m/s) I substract from the spped of location and the result I divide by 1000.
Here is the "pseudo code"
#Override
public void onLocationChanged(Location currentLoc) {
// when stop reseted, when start reset again
if (isAccelerationLoggingStarted) {
if (currentLoc.hasSpeed() && currentLoc.getSpeed() > 0.0) {
// dismiss the time between reset to start to move
startAccelerationToTime = (double) currentLoc.getTime();
}
}
if (!currentLoc.hasSpeed()) {
isAccelerationLoggingStarted = true;
startAccelerationToTime = (double) currentLoc.getTime();
acceleration100 = 0.0;
}
if (isAccelerationLoggingStarted) {
if (currentLoc.getSpeed() >= 27.77) {
acceleration100 = (currentLoc.getTime() - startAccelerationToTime) / 1000;
isAccelerationLoggingStarted = false;
}
}
}
The main problem i see here, is that whenever the device is moving, startAccelerationToTime is reset. (The first if only checks whether there's movement; it doesn't check whether there's already a start time recorded.
I don't see where isAccelerationLoggingStarted is needed at all -- the speed, and the variables themselves, can be cleaned up a bit to make it clear what the next step should be.
Your pseudocode probably ought to look something like:
if speed is 0
clear start time
else if no start time yet
start time = current time
clear acceleration time
else if no acceleration time yet, and if speed >= 100 mph
acceleration time = current time - start time
In Java, that'd look like...
long startTime = 0;
double accelerationTime = 0.0;
#Override
public void onLocationChanged(Location currentLoc) {
// when stopped (or so slow we might as well be), reset start time
if (!currentLoc.hasSpeed() || currentLoc.getSpeed() < 0.005) {
startTime = 0;
}
// We're moving, but is there a start time yet?
// if not, set it and clear the acceleration time
else if (startTime == 0) {
startTime = currentLoc.getTime();
accelerationTime = 0.0;
}
// There's a start time, but are we going over 100 km/h?
// if so, and we don't have an acceleration time yet, set it
else if (accelerationTime == 0.0 && currentLoc.getSpeed() >= 27.77) {
accelerationTime = (double)(currentLoc.getTime() - startTime) / 1000.0;
}
}
Now, i'm not sure exactly how location listeners work, or how often they notify you when you're moving. So this may only semi work. In particular, onLocationChanged might not get called when you're not moving; you may need to request an update (perhaps via a "reset" button or something) or set certain params in order to trigger the stuff that happens when speed == 0.
Related
This is related to the previous question I have posted. I think that while it is related, it might be different enough to warrant its own question.
The code used is:
public static void main(String[] args){
ChronicleQueue QUEUE = SingleChronicleQueueBuilder.single("./chronicle/roll")
.rollCycle(RollCycles.MINUTELY).build();
ExcerptTailer TAILER = QUEUE.createTailer();
ArrayList<Long> seqNums = new ArrayList<>();
//this reads all roll cycles starting from first and carries on to next rollcycle.
//busy spinner that spins non-stop trying to read from queue
int currentCycle = TAILER.cycle();
System.out.println(TAILER.cycle());
while(true){
//if it moves over to new cycle, start over the sequencing (fresh start for next day)
int cycleCheck = TAILER.cycle();
long indexCheck = TAILER.index();
System.out.println(cycleCheck);
System.out.println("idx: "+indexCheck);
if (currentCycle != cycleCheck){
LOGGER.warn("Changing to new roll cycle, from: "+currentCycle+" to: "+cycleCheck+". Clearing list of size "+seqNums.size());
seqNums.clear(); // this may cause a memory issue see: https://stackoverflow.com/a/6961397/16034206
currentCycle = cycleCheck;
TAILER.moveToCycle(currentCycle);
cycleCheck = TAILER.cycle();
indexCheck = TAILER.index();
System.out.println("cycle: "+cycleCheck);
System.out.println("idx: "+indexCheck);
}
//TODO:2nd option, on starting the chronicle runner, always move to end, and wait for next day's cycle to start
if (TAILER.readDocument(w -> w.read("packet").marshallable(
m -> {
long seqNum = m.read("seqNum").readLong();
int size = seqNums.size();
if (size > 0){
int idx;
if ((idx = seqNums.indexOf(seqNum)) >= 0){
LOGGER.warn("Duplicate seqNum: "+seqNum+" at idx: "+idx);
}else{
long previous = seqNums.get(size-1);
long gap = seqNum - previous;
if (Math.abs(gap) > 1L){
LOGGER.error("sequence gap at seqNum: "+previous+" and "+seqNum+"! Gap of "+gap);
}
}
}
seqNums.add(seqNum);
System.out.println(m.read("moldUdpHeader").text());
}
))){ ; }else { TAILER.close(); break; }
//breaks out from spinner if nothing to be read.
//a named tailer could be used to pick up from where is left off.
}
}
At this point, I have 2 roll cycle files, one ends in a sequence Number of 1001, then the next file starts with seqNum of 0. Using the while loop, it would read both files, but there is an if statement to check that the cycle has changed or not and reset accordingly.
The output is as follows:
The output when .moveToCycle() is commented:
As you can see, the first index of the next file is read as part of previous file, but when I use the TAILER.moveToCycle(currentCycle) it moves to start of the next file again, but it has a different index this time. If you comment this line of code out, it will not re-read the entry with seqNum of 0.
Alright, I tested the following and it works just fine. How it works is that it reads the value (I am assuming the internal workings would only shift the index and cycle after it reads an incoming value), then tests for cycle change (from testing before reading to testing after reading). This is probably how one should iterate over multiple roll cycle files, while keeping track of when it roll overs.
Also, note that previously it prints cycle and index before printing the object, now it prints object before printing cycle and index, so its likely that you may misread it and assume it doesn't work if you try to test the following code.
public static void main(String[] args){
ChronicleQueue QUEUE = SingleChronicleQueueBuilder.single("./chronicle/roll")
.rollCycle(RollCycles.FIVE_MINUTELY).build();
ExcerptTailer TAILER = QUEUE.createTailer();
ArrayList<Long> seqNums = new ArrayList<>();
//this reads all roll cycles starting from first and carries on to next roll cycle.
//busy spinner that spins non-stop trying to read from queue
int currentCycle = TAILER.cycle();
System.out.println(TAILER.cycle());
AtomicLong seqNum = new AtomicLong();
while(true){
if (TAILER.readDocument(w -> w.read("packet").marshallable(
m -> {
long val = m.read("seqNum").readLong();
seqNum.set(val);
System.out.println(m.read("moldUdpHeader").text());
}
))){
//if it moves over to new cycle, start over the sequencing (fresh start for next day)
int cycleCheck = TAILER.cycle();
long indexCheck = TAILER.index();
System.out.println("cycle: "+cycleCheck);
System.out.println("idx: "+indexCheck);
if (currentCycle != cycleCheck){
LOGGER.warn("Changing to new roll cycle, from: "+currentCycle+" to: "+cycleCheck+". Clearing list of size "+seqNums.size());
seqNums.clear(); // this may cause a memory issue see: https://stackoverflow.com/a/6961397/16034206
currentCycle = cycleCheck;
}
int size = seqNums.size();
long val = seqNum.get();
if (size > 0){
int idx;
if ((idx = seqNums.indexOf(seqNum)) >= 0){
LOGGER.warn("Duplicate seqNum: "+seqNum+" at idx: "+idx);
}else{
long previous = seqNums.get(size-1);
long gap = val - previous;
if (Math.abs(gap) > 1L){
LOGGER.error("sequence gap at seqNum: "+previous+" and "+seqNum+"! Gap of "+gap);
}
}
}
seqNums.add(val);
} else { TAILER.close(); break; }
//breaks out from spinner if nothing to be read.
//a named tailer could be used to pick up from where is left off.
}
}
I'm making a game in Unity2D where are 4 roads that tanks drive on, tanks spawn in random positions, I want to make sure that a tank can't spawn in a position that another tank is already in. When I start the game the Unity Editor crashes I think there is a problem somewhere in the do while loop but I haven't found it, hoping I described it right.
Thanks.
{
public GameObject tank;
public float spawnTime = 1f;
float positionX;
float positionY;
private bool check;
// Start is called before the first frame update
void Start()
{
InvokeRepeating("TankSpawn", 1f, spawnTime);
}
void TankSpawn()
{
do
{
int rndY = Random.Range(1, 5);
float rndX = Random.Range(20.5f, 35.0f);
if (rndY == 1)
{
positionY = -3.5f;
positionX = rndX;
}
else if (rndY == 2)
{
positionY = 0.5f;
positionX = rndX;
}
else if (rndY == 3)
{
positionY = 4.5f;
positionX = rndX;
}
else if (rndY == 4)
{
positionY = 8.5f;
positionX = rndX;
}
GameObject[] tanks = GameObject.FindGameObjectsWithTag("tank");
foreach (GameObject tank in tanks)
{
if (tank.transform.position.x == positionX && tank.transform.position.y == positionY)
{
check = false;
}
else
{
check = true;
}
}
} while (check != true);
Instantiate(tank, new Vector2(positionX, positionY), transform.rotation);
}
}```
Firstly the problem that is doing you in:
By default bool variables. like check, are false. The while loops when check is false. The only way for check to be set to true is thru the forloop if the generated coordinates don't match any tank positions. The problem with that is that if there are no tanks in the scene the forloop is never even started meaning that there is no way for check to become true, ergo your while loop keeps looping and hangs up your editor.
A quick solution would be to check the length of found tanks array and if it is zero set check to true.
if (tanks.Length == 0)
{
check = true;
}
Sidenotes:
There is name ambiguity between the tank in the forloop and the tank in the prefab. Its good practice to avoid that.
It is extremely hard to match two float values with == due to rounding. They might be extremely close, but are still different.
With your method tanks will still overlap. I would recommend to check if a position is truly free, by using Physics2D.OverlapBox or Physics2D.OverlapCircle
If a lot of tanks spawn there might not be any valid positions. You should think of a way to timeout or impose some other limit, else you'll get softlocked in the while loop again.
I read about the problem a day ago where the problem occurs with people but when it comes to the final second. I kept noticing in my timer that the as it counts down it sometimes skips a second, some suggested changing the interval from 1000ms to 500ms others said make it 900. And there are those who suggested making your own Timer.
My timer is a bit big as it contains two smaller timers within it, that count down individual minutes within the total time and I activate an animation during those times. So basically I am asking what approach should I take to for a time critical counter that is 100% accurate?
This is my code:
private void startTimer() {
Log.println(Log.ASSERT, "CHECK","Entered startTimer() method");
millisInFuture = mTimeLeftInMillis;
mCountDownTimer = new CountDownTimer(mTimeLeftInMillis, 900) {
#Override
public void onTick(long millisUntilFinished) {
mTimeLeftInMillis = millisUntilFinished;
updateCountDownText();
millisPassed = millisInFuture - mTimeLeftInMillis;
progress = (int) (millisPassed * 100 / millisInFuture);
pb.setProgress(progress);
pb2.setProgress(0);
pb3.setProgress(0);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Key: 60 sec
if (millisInFuture == 480000) {
if (millisPassed <= 60000 || (millisPassed > 180000 && millisPassed <= 240000) || (millisPassed > 300000 && millisPassed <= 360000 || (millisPassed > 420000 && millisPassed <= 480000))) {
// Animation animation = AnimationUtils.loadAnimation(tool1mode1.this, R.anim.fade_in);
// stepupimage.setAnimation(animation);
Log.println(Log.ASSERT,"CHECK","Check that the first if statement of key 60 is entered");
statusIfUp();
time_of_stage = (millisInFuture - millisPassed) % 60000;
progress2 = (int) (time_of_stage*100 / 60000);
Log.println(Log.VERBOSE,"CHECK","TIME OF STAGE = "+time_of_stage);
Log.println(Log.VERBOSE,"CHECK","progress2= "+progress2);
pb2.setProgress(progress2);
updateStageUpCount();
upArrowAnimation();
setflowrate();
}
}
#Override
public void onFinish() {
Toast.makeText(tool1mode1.this, "Done", Toast.LENGTH_SHORT).show();
avd2.stop(); avd3.stop();
try {
pb.setProgress(100); pb2.setProgress(0); pb3.setProgress(0);
stage_timer.setVisibility(View.INVISIBLE);
stage_timer.setVisibility(View.INVISIBLE);
progressBar.setVisibility(View.INVISIBLE);
progressBar2.setVisibility(View.INVISIBLE);
progressBar.setProgress(0);
progressBar2.setProgress(0);
progressBar.setTranslationY(60);
progressBar2.setTranslationY(60);
flow.setTranslationY(60);
animation1.cancel(); animation2.cancel();
//Vibration
if (Build.VERSION.SDK_INT >= 26) {
((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(VibrationEffect.createOneShot(150, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(VibrationEffect.createWaveform(new long[]{150}, new int[]{VibrationEffect.EFFECT_CLICK}, -1));
}
}
catch (NullPointerException e) {
e.printStackTrace();
}
}
}.start();
}
So to summarize: I have a big timer and two small timers that count certain intervals within the larger timer. Now the CountDownTimer class that is provided by Android skips a second or two at times during the count down. I want to fix this problem and don't know how, I would have just rolled with it but unfortunately the one I'm making the app for requires it to be 100% accurate as the application is time critical.
Note: pb, pb2, pb3, are progress bars of the timers (1st is the big one, 2nd and 3rd alternate for the second timer)
I created a program on STM8S103F3 to generate a delay in rage of micro seconds using TIM2 module, but the timer is not ticking as expected and when I tried to call 5 sec delay using it, it is giving around 3 sec delay. I'm using 16MHz HSI oscillator and timer pre-scalar is set to 16. please see my code below. Please help me to figure out what is wrong with my code.
void clock_setup(void)
{
CLK_DeInit();
CLK_HSECmd(DISABLE);
CLK_LSICmd(DISABLE);
CLK_HSICmd(ENABLE);
while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE);
CLK_ClockSwitchCmd(ENABLE);
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI,
DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE);
}
void delay_us(uint16_t us)
{
volatile uint16_t temp;
TIM2_DeInit();
TIM2_TimeBaseInit(TIM2_PRESCALER_16, 2000); //Prescalar value 8,Timer clock 2MHz
TIM2_Cmd(ENABLE);
do{
temp = TIM2_GetCounter();
}while(temp < us);
TIM2_ClearFlag(TIM2_FLAG_UPDATE);
TIM2_Cmd(DISABLE);
}
void delay_ms(uint16_t ms)
{
while(ms--)
{
//delay_us(1000);
delay_us(1000);
}
}
It is better to use a 10us time base to round the delays. Well in order to achive a 10us timebase, if you use 16MHz master clock and you prescale TIM2 by 16, then you get a 1 us increment time, right? But we want TIM2 to overflow to generate an event named 16us event. Since we know that the timer will increment every 1us, if we use a reload value 65536 - 10 = 65526, this will give us a 10us overflow hence, 10us time base. If we are ok until here in delay code we'll just check the TIM2 update flag to know whther it has overflowed or not. See the example code snippet below.
// Set up it once since our time base is a fixed 10us
void setupTIM2(){
TIM2_DeInit();
TIM2_TimeBaseInit(TIM2_PRESCALER_16, 65526); //Prescalar value 16,Timer clock 1MHz
}
void delay_us(uint16_t us)
{
volatile uint16_t temp;
TIM2_Cmd(ENABLE);
const uint16_t count = us / 10; //Get the required counts for 10us time base
// Loop until the temp reaches the required count value
do{
while(TIM2_GetFlagStatus(TIM2_FLAG_UPDATE) == RESET); //Wait for the TIM2 to overflow
TIM2_ClearFlag(TIM2_FLAG_UPDATE); // Clear the overflow flag
temp++;
} while(temp < count);
TIM2_Cmd(DISABLE);
}
void delay_ms(uint16_t ms)
{
while(ms--)
{
//delay_us(1000);
delay_us(1000);
}
}
void main(void){
...
setupTIM2();
...
delay_ms(5000);
}
Trying to make simon says game as my semester project, problem is I cant add a delay between the colors when they change,
i.e i want to add a delay so that when one box color changes, then after about 3~4 seconds the next box color changes, but the problem is when I put the Sleep() in my for loop, the system pauses for the amount given as a whole, then displays all the colors changed at the same time not one by one....
Any help, here is the function that i call when the game's start button is clicked. How to fix it ?
void flash()
{
srand(time(NULL));
int x;
for (int i = 5; i > 0;i--)
{
x = rand() % 4;
if (x == 0)
{
button1->BackColor = System::Drawing::Color::Blue;
}
else if (x == 1)
{
button2->BackColor = System::Drawing::Color::Blue;
}
else if (x == 2)
{
button3->BackColor = System::Drawing::Color::Blue;
}
else if (x == 3)
{
button4->BackColor = System::Drawing::Color::Blue;
}
Sleep(500);
}
}
P.s I have tried to put the sleep in the if statements but that doesn't work either, Any help please ?
As your code is single-treaded and you are updating the colors of the buttons in a loop, there is (currently) no chance for the application's standard drawing routines to kick in, until the loop is finished. If you do want a redraw while being in the loop, you have to manually issue it by (e.g.):
button1->Invalidate();
button1->Update();
Please be aware that, if you stay in the loop for too long, windows does recognize that your application is not responding to windows messages and renders it "unresponsive" (window fading to half white). To circumvent this, you can use the Timer class from System::Windows::Forms to implement the delay behaviour.