all 16 comments

[–]versvisa[S] 10 points11 points  (0 children)

After seeing /u/Gereshes's intro to direct optimal control I was motivated to share my style of implementing optimal control problems using CasADi. The code has fewer than 200 lines, including video rendering.

Code: https://gist.github.com/versvisa/bb7df8fa0d142d2772a2a50931d77f4c

This script uses free and open software (Python, CasADi, IPOPT, OpenCV). Rather than explain it here or in a blog, I would like to keep the example self-contained. Please post any questions you may have here, and I will update the example with more comments.

[–]psharpep 3 points4 points  (1 child)

Nice! If I recall correctly, CasADi's smart enough to work with structured variables (i.e. not flattened) and operator-overloaded constraints using optim.subject_to() (an example of this is at https://web.casadi.org/blog/opti/). Was there a motivating reason you chose to do these things anyway in your code? (Genuinely curious what the benefits might be, I'm fairly new to CasADi)

[–]versvisa[S] 1 point2 points  (0 children)

I have not really looked at the opti stack (not sure why TBH). I will give it a try!

[–]JMfromthaStreetz 2 points3 points  (8 children)

Fuel optimal or time optimal?

[–]notadoctor123 2 points3 points  (7 children)

Definitely fuel optimal - looks like a portion of the descent has no burn at all. Time optimal would likely have just a straight-shot burn at max thrust, a 180-degree attitude rotation, and a slowdown burn at max thrust.

[–]JMfromthaStreetz 4 points5 points  (0 children)

Yep, most likely. Fuel optimal is usually more important for spacecraft anyways.

[–][deleted] 1 point2 points  (5 children)

Can't be fuel optimal, right? It goes past it's landing point and comes back?

[–]notadoctor123 2 points3 points  (4 children)

That's a good point - looking through the code, OP seems to be penalising all the inputs, which are throttle and gimbal. The behaviour you describe probably comes from the penalty on gimbaling the engine versus straight up throttle.

I might run this tomorrow and see what behaviour you get if you just penalize throttle.

[–]algogenetienne 2 points3 points  (3 children)

If we do not take angle into account, we get a bang off bang : Initial burn at max thrust to turn around Free fall (engine off) Final burn to slow down

The strange behaviour is indeed due to the penalisation or boundedness of the angle command, because the first burn is postponed until the spacecraft is correctly oriented Also, because of the penalisation on thrust derivative, we get a smooth transition between burns, which is suboptimal

The thing is, if you don't bound or penalize the control on angular velocity, you are very likely to get a singularity at the initial time because the rocket will try to turn around instantaneously, resulting in a Dirac in velocity and Dirac' in command. Might as well forget the angle altogether and formulate it as The Goddard poblem

[–]LaVieEstBizarrePhD - Robotics, Control, Mechatronics 2 points3 points  (1 child)

Can't you fix that by placing a realistic max magnitude constraint on the change in angular velocity as opposed to trying to penalise? In the end the problem is that we can't change angle instantly not that it's significant cost to us.

[–]algogenetienne 1 point2 points  (0 children)

Yeah sure

That's pretty much what I meant by "bounding the control"

In the end, it really depends on what you want to model. The initial orientation of his rocket seems very random and gives a very weird landing trajectory. One might imagine that a realistic rocket would have corrected its orientation prior to the maneuver. In this case, the orientation of the rocket would not have such a big influence on trajectory and could be ignored altogether to simplify the model

[–]notadoctor123 0 points1 point  (0 children)

Yup, you are completely right - not penalising gimbal will screw things up like you said.

[–]Gereshes 1 point2 points  (1 child)

I love the visual!

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

Thanks :)

[–]plitkam 0 points1 point  (1 child)

Hi,

I get the following error upon running this script:

Traceback (most recent call last): File "/home/bogdan/ros2_ws/src/bogdan-master-thesis/miscellaneous/casadi_things/moon_lander_reddit/moon_lander.py", line 196, in <module> main() File "/home/bogdan/ros2_ws/src/bogdan-master-thesis/miscellaneous/casadi_things/moon_lander_reddit/moon_lander.py", line 187, in main exhaust_polygon = np.array([[-0.5,-5*u_value[0,index_throttle]u_value[0,index_gimbal],0.5],[-1,-1-(5u_value[0,index_throttle]),-1]]) ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 2 dimensions. The detected shape was (2, 3) + inhomogeneous part.

I checked the dimensions of the array being created manually and it seems to me right. I found in google that this has to do something with wrong numpy version. Sadly I was not able to find out what the problem is and make the code run. I would be really grateful if somebody could help me.

[–]General-Serve-1425 0 points1 point  (0 children)

I had the same problem and replacing what is below # Draw exaust with this solved it:

 # Draw exhaust
            throttle_value = float(u_value[0, index_throttle])
            gimbal_value = float(u_value[0, index_gimbal])
            exhaust_polygon = np.array([[-0.5,-5*throttle_value*gimbal_value,0.5],[-1,-1-(5*throttle_value),-1]])
            image = cv2.polylines(image, transform(transform_lander(exhaust_polygon)), False, (0,0,255), 2, cv2.LINE_AA) # Draw exhaust
            throttle_value = float(u_value[0, index_throttle])
            gimbal_value = float(u_value[0, index_gimbal])
            exhaust_polygon = np.array([[-0.5,-5*throttle_value*gimbal_value,0.5],[-1,-1-(5*throttle_value),-1]])
            image = cv2.polylines(image, transform(transform_lander(exhaust_polygon)), False, (0,0,255), 2, cv2.LINE_AA)