Coroutines make robot code easy
71–80 of 127 posts
Re: Coroutines make robot code easy
#72Seeing them make an odd resurgence in recent years has been awkward. I'm not entirely clear that they make things much more readable than alternatives. Reminds me of thinking continuations were amazing, when I saw some demos. Than I saw some attempts at using them in anger, and that rarely worked out that well.
Also to the point of the article, I love being "that guy" that points out that LISP having a very easy "code as data" path makes the concerns expressed over the "command" system basically go away. You can keep the code as, essentially:
(DriveForward 0.5 48)
(while (NotCarryingBall)
(Grab)
(pause 2))
(DriveBackward -0.5 48)
(Shoot)
With god knows how much bike shedding around how you want to write the loop there.Of course, you could go further for the "pretty" code that you want by using conditions/restarts such that you could have:
(DriveForward 0.5 48)
(Grab)
(DriveBackward -0.5 48)
(Shoot)
And then show what happens if "Grab" is unsuccessful and define a restart that is basically "sleep, then try again." Could start plugging in new restart ideas such as "turn a little, then try again." All without changing that core loop.Re: Coroutines make robot code easy
#73I think that developers have minimal scheduling primitives available to them, to schedule complicated work, in the order and timings you want it to have. I don't like hardcoding functions in coroutine pipelines. Depending on the ordering of your pipeline, you might have to create things and then refer to them, because of the forward reference problem. Here's my stackoverflow question for what I'm getting at: https://…
> I would like to build a rich "process api" that can fork, merge, pause, yield, yield until, drop while, synchronize, wait (latch), react according to events. I feel every distributed systems builds this again and again. Years ago I attempted to build an experimental language with first-class resumable functions. Every function can be invoked by the caller through a special reference type called "quaint". The caller…
And moreover made it a reasonable and readable variant!
Re: Coroutines make robot code easy
#74Arguably this devalues the programming they are learning since Coroutines aren’t as generally applicable
Re: Coroutines make robot code easy
#75I 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,…
Re: Coroutines make robot code easy
#76Earlier quoted context omitted.
> 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 th…
If you just have stream of events that need to be decided upon in order you're in a very happy place; complexity strikes when you want to run handlers for them in parallel to cut on latency, and those handles also need to do multiple things that can be done asynchronously to cut on latency.
Message passing works well here, you can just send a bunch of requests to various components then just wait for each at the moment they are needed; async/await is essentially a very bastardised version of it (and usually stuck in single thread in most implementations so no parallel computing)
Re: Coroutines make robot code easy
#77If you want to make it easy for high schoolers, just don't use java in the first place...
The only officially supported languages for the competition are C++, Java, and LabVIEW. When those are your educational options...you stick with Java. (We've now switched to Lua, integrated with the official C++, but it's a lot more work behind the scenes.)
Re: Coroutines make robot code easy
#78Earlier quoted context omitted.
The only officially supported languages for the competition are C++, Java, and LabVIEW. When those are your educational options...you stick with Java. (We've now switched to Lua, integrated with the official C++, but it's a lot more work behind the scenes.)
Why not Python? I thought that was the popular language for learning these days. My son gets quite a bit of Python in school.
Re: Coroutines make robot code easy
#79If you want to make it easy for high schoolers, just don't use java in the first place...
We learned borland pascal and borland c in high school. Java is perfectly fine.
I've been making a living coding in Java for 10+ years
I'm a strong believer in types etc etc
I still don't think Java is a great language to teach programming lol
too much pointless boilerplate and abstraction to achieve the simplest things
lots of footguns and objectively bad standard practices built into the language and the native libraries
to me Python and Kotlin seem like probably better choices (though they too have massive flaws)
Re: Coroutines make robot code easy
#80People 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.
Consider this example algorithm, of several async steps,
1. Download a file into memory
2. Email a link to a review web page.
3. Wait for the user to review.
4. Upload the file to a partner.
5. Update a database.
You could implement this as callbacks. Callback from each step leads to the next being triggered. Downside - your business logic is spread across all the callbacks. You could mitigate this somewhat by defining a class with one method for each step, with those methods being defined in the same visual order as the algorithm. Then have each callbacks call a method. (The article shows something different but similar with its Command autoCommand pattern.)
Tricks like this only go so far. Imagine if the reviewer user had a choice of pressing 'approve' or 'reject' on the webserver interface, with the algorithm changing depending on their answer. How do you now represent the business logic so the programmer can follow it?
Such changes are easy in coroutines. Here is the algorithm with that variation in coroutine code,
async def review(review_id, url):
file_content = await download_large_file(url, review_id)
ws_review_id = await create_webserver_review_page(file_content)
await email_the_user(ws_review_id)
result = await get_webserver_user_response(ws_review_id)
if result:
await upload_to_partner(file_content)
else:
await alert_failure(review_id, file_content)
await update_database(review_id, ws_review_id, result)
You state that callback code gives you easy visibility to what actually happens - yes, they do. When you read callback code, it is natural to follow business-logic to system calls. Coroutine tends towards code of layered business-logic and abstraction.