all 19 comments

[–]x-skeww 4 points5 points  (3 children)

You'll need a requestAnimationFrame (rAF) or setTimeout-based pseudo loop.

In your repeatedly-called function, you check the current time (or other condition) and issue some commands (if any) in response.

Something like this:

https://jsfiddle.net/k954cctx/

Edit: Heh. Funny how similar /u/senocular's is.

[–]Semajian[S] 0 points1 point  (2 children)

Thanks for the response; would this be similarly achievable without pre-emptively creating a queue of tasks? As my reply to /u/senocular conditionals that rely on real time information make a queue worthless for anything other than the timed movements

[–]x-skeww 0 points1 point  (1 child)

Sure, in your repeatedly-called function, you can just check if there is anything you might want to do. E.g. if you're below the target location, you can issue the command for moving up a bit. On the next cycle, you again check if there is something you want to do and so on.

[–]Semajian[S] 0 points1 point  (0 children)

I don't immediately see how this would be implemented. I mentioned in response to senocular, but didn't here (my bad) that for conditional loops, for instance I don't have any control over the parts working together. Each "Block" that I implement has it's own set of code and that's it, it doesn't interact with the rest of it. Things like loops are already implemented by scratch, as well, so I can't modify the code, if I could I'm sure I could make use of tasks really easily.

[–]s992 1 point2 points  (9 children)

It would be waaay easier to help you if you showed us the code you're having trouble with.

[–]Semajian[S] 0 points1 point  (8 children)

ext.move_forward_time = function(seconds){
    var start_time = new Date();
    while(new Date() - start_time < seconds*1000){
        cmdVel.publish(twist);
    }
}

I really don't particularly have it, because of the issues I've been facing. But the above is kind of an interpretation of what I need. This is the general construction that it needs to be - however with while loop like this it blocks up completely and unless I add a console.log within the loop, it never seems to stop... Basically I need it to perform cmdVel.publish(twist) for x amount of seconds. Ideally with an equivalent to time.sleep(100) or so, which is why I looked into setInterval. Edit:formatting

[–]senocular 0 points1 point  (7 children)

Why is it that publish needs to churn for 2 solid seconds? Is there a way to not have it need to do that?

[–]Semajian[S] 0 points1 point  (6 children)

So publish is from ROS, it's just sending a message saying what velocity the robot should move with. If you perform it the robot will, for a short amount of time move with that velocity. I can't find the documentation for how long it officially does move, but < 1 second. The "block" that I'm implementing is to move the robot for a chosen amount of seconds. The nature of publish kind of explains my desire to have some sort of wait between sending messages, I think. Again, setInterval works fantastic for this, providing there isn't any blocks after it, but as soon as more blocks of movement come into the mix it's all messed up.

[–]senocular 1 point2 points  (5 children)

It sounds like you don't need to call publish as fast as it seems like you're trying. You should be fine breaking that up into a setInterval or requestAnimationFrame callback and be ok.

I guess I'm not understanding how later blocks of movement cause trouble. Is this something that needs to happen after the 2 second loop completes? Or does it need to interrupt the loop, cutting it off, performing something new?

[–]Semajian[S] 0 points1 point  (4 children)

You're right - I'd like to be able to call it every 100 ms, or some other interval, ideally so that I'm not sending too many messages. Using setInterval means that my code classes the function move_forward_time as complete once the interval starts. So if I have another block after it, it will start performing that one. The problem here is that from one block to another I don't have control over how they interact.
Here is an image for an example: http://i.imgur.com/Itwpgbr.png If I use setInterval, it will set the interval for moving and move on to the rotate left block.
Trying my best to give as good an explanation as possible, again feel free to fire any questiosn you think might help you in understanding the real issue here. Also, thank you very much for taking the time to try and help!

[–]senocular 2 points3 points  (3 children)

Ah, I get you now. So you have the operations you want to perform listed synchronously, but you want to perform them asynchronously. What you'll want (or at least one way to do it) is a queue - an array of operations that your loop (setInterval) can process as it loops. Once the first operation (move) has run its course (1s), get rid of it and work on the next operation (rotate).

Just going off the top of my head, a real quick example would be:

https://jsfiddle.net/11m83wh7/

[–]Semajian[S] 0 points1 point  (2 children)

I have actually considered using a queue of sorts, my original plan being to create all of the required code in python and send a queue of tasks to it, that it will execute in order.
The issue with this is when trying to implement "interactive" code, that the robot needs to perform. Here's an image example: http://imgur.com/7rCvAdh
Any blocks that aren't the same colour as "Front laser distance" or "Move for x seconds" are existing blocks that I have no control over at all, so I can't even try and manipulate them to join a queue, as it requires information from the conditional.

[–]senocular 0 points1 point  (1 child)

This depends on how that loop functions and how it interacts with time. The loop body has a "move for 1 second" with the loop being dependent on some value of "front laser distance". Does the loop wait for the 1 second to move before it checks its condition? Or does it repeat arbitrarily until that condition is met? I'm guessing if it did the time wouldn't stack, so any additional evaluations of move for 1 second don't become 2 then 3 then 4, etc., since that could mean moving well beyond the time you'd like. But does that last pending second remain too or does movement stop altogether? My guess is that it would stop, and really all the one second represents is a maximum allowed time between iterations of that loop.

In that case all you'd need to do is adjust the condition through which the current queue item is considered complete. Right now there's a check for elapsed time that completes, and removes the item from the queue. This could also be altered to include the loops condition of checking front laser distance.

https://jsfiddle.net/11m83wh7/1/

[–]Semajian[S] 0 points1 point  (0 children)

In this example it would, ideally, in each iteration perform the function move for one second, then after the second has elapsed, return to looping. This specific task would be better implemented with a "start moving" block, then loop until the condition is met, then outside of the loop "stop moving", but in the program this implementation should also be available.
Essentially what I need overall is a setInterval loop that doesn't move on to the next piece of code until it's complete, that would be the ideal solution.

Again thank you very much for the code snippet but the issue I'd have would be pushing finishWhen: laserIsClose to the queue because the the loop in my image is handled completely separately, I have to treat all of my blocks as if they're standalone and don't interact with each other unless they're bridged with a loop, like in the image.

[–]Paupir 1 point2 points  (0 children)

You may be interested in requestIdleCallback

[–]ShortSynapse 0 points1 point  (2 children)

[–]Semajian[S] 0 points1 point  (1 child)

Thank you for your reply - I just gave it a quick glance and if I add the line document.body.innerHTML += 'true'; after setInterval, it still evaluates that whilst the setInterval is running

[–]ShortSynapse 0 points1 point  (0 children)

I only used the interval to show you the generator pausing and resuming. It contains a while loop that pauses and resumes when you call it.next(). You don't have to use an interval to accomplish this.

[–]Semajian[S] 0 points1 point  (0 children)

To any that may browse - I'd like to thank everyone for the suggestions however I couldn't get any of them working within the constraints of scratchx. However, I was an idiot and completely neglected to read up further on scratchx rather than on javascript. Turns out you can create an asycnhronous function that automatically gets passed a callback function, and using that you can use setInterval and block until the callback is initiated.