Live data from Hacker News

Coroutines make robot code easy

bvisness.me

61–70 of 127 posts

Re: Coroutines make robot code easy

#61

Yes. The callback is not a natural construct (i.e. it does not map well to our intuitive understanding of X is doing something while Y is doing something else). I'm annoyed when coroutines are reserved for use only in high performance, c10k-type of situations. For example, the KJ library's doc says: "Because of this, fibers should not be used just to make code look nice (C++20's co_await, described below, is a better…

Yes. What question are you answering 'yes' to? The callback is not a natural construct According to who? It is very natural to anyone making a GUI or anything interactive for the firs time. Eventually I would try to move people to queueing up events and handling them all at the same time so that the order is easier to debug. Coroutines are the latest silver bullet syndrome. Fundamentally you still need to synchronize…

> According to who? It is very natural to anyone making a GUI or anything interactive for the firs time.

The people that do not make GUIs but apps with complex behaviours.

Callbacks are nice and simple. Callbacks calling callbacks calling callbacks calling callbacks (because of one of worst ideas in programming ever, function coloring) stops being simple. Async/await is just a patch over that ugliness for languages that can't do any better easily

Re: Coroutines make robot code easy

#62

Maybe I'm missing something but why doesn't the Java section right before the Lua section not work? It looks like normal procedural code that can just keep running. The lua version is just one coroutine and it's not yielding to anything else. Is it just a matter of some kind of timing constraint/controller from FRC in the background that need to keep calling myAuto?

autonomousPeriodic is a tick function; we need to keep ticking. If we spent more than our allotted 20ms in a single autonomousPeriodic then the robot framework’s safety systems kick in and disable all the motors.

Ah okay that makes sense, thanks! It may help to make that note near the final java example.

Re: Coroutines make robot code easy

#63
post #30

I don’t understand why doing this with normal Java is difficult. Just have a list of objectives. Each objective is a class. The autonomous loop picks the next objective from the list and each tick, asks if it has finished, if so get the next objective and so on. All the details about the actual commands to complete the objective and checking the state and so on go into the classes. If no more objectives in the list,…

Having taught FRC students to use Java: when you're talking about people with very little experience programming before, the multiple class abstraction is itself an obstacle to accomplishing the goal. I can't tell you how many times students have gotten frustrated trying to understand why you have to pass arguments into the constructor or, for that matter, Why the constructor is different from other method calls. "Bu…

[deleted]

Re: Coroutines make robot code easy

#64

Earlier quoted context omitted.

Unfortunately high schools are forced to continue teaching Java, or else Oracle starts executing hostages.

I feel bad for autonomous participants, Java is almost a uniquely poor choice for the size of project FIRST teams would be creating. Java has its domains, but small, algorithm driven code worked on by a small, inexperienced group isn't one.

Especially when people try to impose Enterprise Quality Java on the students, and your project gets bloated with interfaces and dependency injection and config files…all for a single platform with fixed hardware :(

When we were still using Java, I had the students just make everything static. We don’t need more than one instance of our IntakeSubsystem. We only have one intake. But the OOP boilerplate persists.

Re: Coroutines make robot code easy

#65
post #61

Earlier quoted context omitted.

Yes. What question are you answering 'yes' to? The callback is not a natural construct According to who? It is very natural to anyone making a GUI or anything interactive for the firs time. Eventually I would try to move people to queueing up events and handling them all at the same time so that the order is easier to debug. Coroutines are the latest silver bullet syndrome. Fundamentally you still need to synchronize…

> According to who? It is very natural to anyone making a GUI or anything interactive for the firs time. The people that do not make GUIs but apps with complex behaviours. Callbacks are nice and simple. Callbacks calling callbacks calling callbacks calling callbacks (because of one of worst ideas in programming ever, function coloring) stops being simple. Async/await is just a patch over that ugliness for languages t…

The people that do not make GUIs but apps with complex behaviours.

I don't think there is a difference here.

Callbacks are nice and simple. Callbacks calling callbacks calling callbacks calling callbacks (because of one of worst ideas in programming ever, function coloring) stops being simple. Async/await is just a patch over that ugliness for languages that can't do any better easily

I agree with all of this, but they said 'callbacks are not natural'. I don't think this is a language issue either and I don't think coroutines help. Just like I said in the first comment, I think the way to go is to have a queue of events/inputs and use that because the ordering and debugging is much better and you don't get the same web of jumping to different parts of the execution.

I do think that callbacks are a 'natural' and straightforward idea that most people either think of independently or understand well the first time they see it. It doesn't mean that's the best way to do it, but to say it isn't 'natural' is bizarre.

Re: Coroutines make robot code easy

#66

People always say that coroutines make code easier to understand, but I've always found normal asynchronous code with callbacks much easier to understand. They're equivalent except that asynchronous callbacks is what actually happens and you have clear control and visibility on how control flow moves.

If you want to see the callbacks, an alternative middle ground is promises, e.g. code that looks like doSomething().then(() => doSomethingElse()).then(() => doLastTask());

I currently work on a project that involves Java code with a promise library, and Unreal Engine C++ code which does not and uses callbacks (and do async JS stuff in my personal projects), and both have to do asynchronous logic. The Unreal code is just so much harder to deal with.

Specific problems the Unreal code has:

- There's no "high level" part of the code that you can look at to see what the logic flow is.

- Many functions are side-effecty, triggering the next part of the sequential logic without it being clear that that's what they're doing. Like the handleFetchAccount() callback kicks off another httpRequest for the next step, but you wouldn't know that it does that just from the name.

I'd admit some of these problems might be mitigatable in a better written codebase though.

Re: Coroutines make robot code easy

#67

Thankfully a piece that emphasizes that coroutines are functions that pause. Java frameworks like Quasar became focused on other goals besides that basic capability and lost their way (IMHO). Java's not the easiest to pick up in high school unless you really make a big after-school effort. Something like Lua is probably better.

> Java frameworks like Quasar became focused on other goals besides that basic capability and lost their way (IMHO).

A bit of an aside maybe, but the guy that made Quasar is behind project loom to add light weight threads to JVM which will become available in JVM 21 https://openjdk.org/jeps/444

Re: Coroutines make robot code easy

#68
post #28

Yes. The callback is not a natural construct (i.e. it does not map well to our intuitive understanding of X is doing something while Y is doing something else). I'm annoyed when coroutines are reserved for use only in high performance, c10k-type of situations. For example, the KJ library's doc says: "Because of this, fibers should not be used just to make code look nice (C++20's co_await, described below, is a better…

I want to add to the callback vs coroutines and async/serial discussion that it all depends on how you treat errors. Are errors mere exceptions or do you want to handle errors in the control flow ? For example turndeg(90), Move(10), PickupItem(), turndeg(180), Move(10) you treat errors as exceptions, if the robot fail to pickup the item, or if it ends up at the wrong place it's an exception. Now if you put all these…

Ish. You can also have error recovery in the form of the "conditions/restarts" system of common lisp. Such that you can have "look nice" things if you want with many different setups.

Re: Coroutines make robot code easy

#70
I've been playing with JavaScript generators recently, and the ability to "pause" a function is exactly what I'm using them for. The goal is to create an animation of how a maze generation algorithm works, so it lets me write loops like I normally would but allow the function to pause which the website recenders the current state.

When I create games, there's also a similar tick() function that's called every frame to handle the main logic, and normally to handle logic that needs to execute over multiple frames I write state machines like the article talks about, coupled with promises to allow things to chain off each other. This article might change how I write that code??

I'm also thinking that instead of using a coroutine and yield(), you could asynchronous functions and "await nextTick()". Mostly for my own sake, trying to think of the differences between the two between the two:

- Coroutines allow the decision of when to execute them to be made outside the function. Whereas asynchronous code goes off and does its own thing. With the corountine approach you fit into the normal code flow of having a tick function that does something every frame, so that seems better.

- This approach only supports one coroutine at a time, whereas it's easy to kick off parallel operations with async code. Not being able to do things in parallel is probably desirable for a robot like this, as otherwise you might accidentally try to move towards two different goals at the same time.

- You can interrupt a coroutine by just not calling it anymore. Async code generally can't be interrupted by an external function. So it would be easier to switch to doing new behaviour.

- Composability. A quick search seems to indicate that support for nested coroutines in lua is not very good [1]. Which means that you can't split your main logic into small functions. In my language of JavaScript though, this isn't a problem thanks to yield*. But seems like asynchronous functions might win out there.

Hm. More to think about. I suppose I'll try it on my next game jam.

[1]: Is this the only way to yield all the results of a second coroutine in Lua?? https://gist.github.com/nicloay/2b893b3de1d964dcc92023c6318a...

Post reply on HN