
Show HN: SpaceX Dragon simulator docking autopilot in Clojure - danpetrov
https://github.com/DaniruKun/spacex-iss-docking-sim-autopilot
======
VLM
I have a question about control flow of the overall system. Note that I
haven't actually run this or debugged it. Or frankly, thought about it for
more than a minute or two. Its more of an architectural question.

So in dragon.clj there's a case statement to execute commands in the translate
function such that the command to go down or left in an abstract calculated
sense is implemented as hitting a virtual down or left keyboard key.

What happens if you have to go down AND left?

I was just thinking why not pass a Clojure list to the translate function and
when list contains a down it hits the virtual s key AND if the list contains a
left command it hits a virtual a key, then you could wiggle "down-left" at the
same time.

I mean, obviously it works and sometimes architectural decisions have no
technical reason and are arbitrary, which would be perfectly OK. I was just
idly curious.

Clojure is cool, like programmer catnip, so I had to look at it.

~~~
danpetrov
Heh, never thought about it that way! But good question. Yes, it can translate
on 2 axes at the same time, since the control loops for each axis run in
separate threads, so there is no control locking. The same is with rotation -
it can e.g. pitch, roll and yaw at the same time.

~~~
jcims
So if you click one of the rotate buttons after it has zeroed out the offsets
will it correct? Is it using a PID model or something else?

~~~
loeg
The SpaceX simulation is simplistic enough and gives you enough data that you
really don't need a PID controller to hit the target numbers.

~~~
jcims
Totally agree I’m just trying to learn PID control and seeing a few different
implementations in javascript (to solve the same problem) has actually been
quite informative.

------
GistNoesis
[https://www.reddit.com/r/spacex/comments/gigmfh/spacex_iss_d...](https://www.reddit.com/r/spacex/comments/gigmfh/spacex_iss_docking_simulator/fqfzatb/)
does it in one line but it's kind of cheating.

~~~
barbegal
Definitely cheating, it's not autopilot. It is just updating your co-ordinates
every 500ms on a straight line.

I would like to see a real autopilot written in javascript that you can paste
into the console.

~~~
zlsa
I wrote an autopilot[0] for the simulator in JS, which sends key events to the
game.

[0]:
[https://gist.github.com/ForestKatsch/01069f29e8316df11774025...](https://gist.github.com/ForestKatsch/01069f29e8316df117740258313665f1)

~~~
jcims
This is awesome! As a recent student of PIDs, it's even better after
uncommenting the createPidDisplay statement on line 566 :)

Only feature request is a 'Do a Barrel Roll!' button.

------
ggerganov
From all the auto-pilots I've seen so far, I believe mine docks the fastest
(without cheating):

[https://youtu.be/jWQQH2_UGLw](https://youtu.be/jWQQH2_UGLw)

Source code:

[https://gist.github.com/ggerganov/092b86a59fa34926998953701a...](https://gist.github.com/ggerganov/092b86a59fa34926998953701ae22ca1)

~~~
danpetrov
Nice! It will will the award in speed, but not in the amount of fuel it wasted
:D

~~~
ggerganov
Haha true :) Btw, found this clip of another auto-pilot which is even faster,
so my statement above is now incorrect :-)

[https://www.youtube.com/watch?v=WwWccjAD2i8](https://www.youtube.com/watch?v=WwWccjAD2i8)

------
thom
Not to say this is bad or incorrect, but this is very unidiomatic Clojure. I
would question the amount of global state, and the broad use of loops inside
threads. This can’t be fun to try and test!

Perhaps better would be to make pure functions to take current telemetry as an
argument and return actions as outputs, perhaps all at once or more likely
individually for each control. You could then capture all of this inside
core.async go-loops to manage the control flow and timeouts, but you could
also probably build something simple with one or more agents wrapping the
current state and updating a set of commands to be executed later. Another
argument for core.async would be to make it easier to funnel all commands into
a single channel because I’m not entirely convinced a WebDriver is
multithreaded, but perhaps the library manages that for you.

Anyway, cool stuff!

~~~
fsloth
Each time someone complains a working program is not "idiomatic" in what ever
language I die a little inside.

That makes it sound you approach this from a haughty presumptuous,
_uncharitable_ angle.

It sounds like you exclude the possibility that the author did not try it
"your way" first, for example, but found a simpler way to implement it.

"That's not the most obvious to do it IMO" or "I would have preferred to do it
like this..." are much better ways to approach this. Programs should be
beautiful and understandable, but "idiomatic" sounds it excludes lots of
simple beautiful solutions to a problem out of pure dogma.

~~~
thom
Clojure is a mostly pure functional language, it is very uncommon to have
almost all logic reach out to global variables to do work. It’s also rare to
see multithreaded code that eschews most of the mechanisms built into the
language for multithreading. These two things together (pure functional
programming and strong concurrency primitives) are arguably the fundamental
motivations behind the language. You value simplicity: Clojure can help make
this code simpler. If there’s a succinct way to say that without the word
idiomatic, one with fewer negative connotations, I will try to use that in the
future.

~~~
fsloth
And those are _valid_ critique. I'm sorry - my prior response was harsh now
I'm reading it again.

We all like to critizice things that offend our sense of aesthetics. But
criticism always hurts the author. It's _ok_ if it hurts if it is valid
critique. And the only way to get understood is to be explicit.

------
jcadam
Back when I worked on spacecraft simulation we used Ada, and we liked it (no,
we didn't).

------
tosh
related article: [https://medium.com/@thedanpetrov/creating-a-spacex-crew-
drag...](https://medium.com/@thedanpetrov/creating-a-spacex-crew-dragon-
simulator-autopilot-in-clojure-1ac095d9209b)

------
frompdx
For some reason I expected this to just interact with some form of http API.
After digging into the source code I discovered the author is using etaoin.
This is a really neat use of the etaoin library for selenium bindings in
Clojure.

------
fnord77
Really nice. Made it right up until almost docked.

It crashed for me right as it docked with:

    
    
        Syntax error (ExceptionInfo) compiling at (/private/var/folders/8f/wlmmp1rs38966nkmrs_slnjd1vkfkk/T/form- 
        init8037093313867620508.clj:1:125).
        throw+: {:type :etaoin/timeout, :message "Wait for {:css \"#success > h2\"} element is visible", :timeout 300, :interval 0.33, :times 910, :predicate #object[etaoin.api$wait_visible$fn__4868 0x173b24c4 "etaoin.api$wait_visible$fn__4868@173b24c4"]}

------
TeMPOraL
If you want the reverse of an autopilot, try this:

[https://news.ycombinator.com/item?id=23172281](https://news.ycombinator.com/item?id=23172281)

... and pull the appropriate Interstellar music up in a separate tab.

------
bloopernova
OK so yes the ISS docking sim is old news, but good lord do I love that UX. I
really hope someone has modded it into Kerbal Space Program!

~~~
munchbunny
It's definitely easier to read than KSP's navigation ball.

KSP was also 100% the reason I managed dock with the simulator on the first
try, because in a way it was more like the 50th-100th try, just using a
different interface.

------
karl11
That is some nice looking code!

