-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added a example: crane moving a load #197
Added a example: crane moving a load #197
Conversation
I tried to copy all 'formalities' from an existing example in examples_gallery, so I hope it will run with sphinx. |
This seems to look o.k. in html |
I ran this and it failed:
Examples should be robust and always converge. The most reliable way is to give a better initial guess (possibly even a solution). |
Yes, nice work! |
@@ -0,0 +1,294 @@ | |||
# %% | |||
""" | |||
Crane moving a load |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Crane moving a load | |
Crane Moving a Load |
|
||
A load is moved by a crane. The load is rotably connected to the crane by a | ||
massless rod. The goal is to move the load from the initial position to the | ||
final position in the shortest possible time. The load must not 'overswing' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final position in the shortest possible time. The load must not 'overswing' | |
final position in the shortest possible time. The load must not over-swing |
**Constants** | ||
|
||
- l: length of the rod attaching the load to the crane [m] | ||
- m1: mass of mover attached to the arm of the crane [kg] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variables should be latex or code:
- :math:`m_1` OR ``m1``
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variables should be latex or code:
- :math:`m_1` OR ``m1``
I had played around with :math:.....
but did not get it to work right.
Will it only work in lines like:
"""
- :math:
... .
"""
not in lines starting with # ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Math in RestructuredText is explained here:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Math in RestructuredText is explained here:
This is what I looked at, but never got it to work. I will play around some more.
As I understand, :math: or ..math: only works in docstrings. In simulations for examples_gallery there is a docstring at the very beginning.
Question: are docstrings allowed further down in the text, or to be avoided?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sphinx-gallery treats the module level "docstring" as a "cell" of RestructuredText.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has not bee addressed.
- uxc: velocity of the mover in x-direction [m/s] | ||
- uxl: velocity of the load in x-direction [m/s] dependent speed | ||
- uyl: velocity of the load in y-direction [m/s] dependent speed | ||
- u: angular velocity of the rod [rad/s] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The states are technically only the minimal set of coordinates and speeds, which are likely q and u.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The states are technically only the minimal set of coordinates and speeds, which are likely q and u.
I did not know this definition, I will correct this and the other suggestions. I needed the dependent coordinates to model the non over . swing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see below you are doing a non-minimal coordinate formulation. The states are still then only the independent coordinates and speeds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The states are technically only the minimal set of coordinates and speeds, which are likely q and u.
they are xc, uxc, q, u.
|
||
""" | ||
import sympy.physics.mechanics as me | ||
from collections import OrderedDict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OrderedDict is no longer needed, it is a remnant of Python 2 not ordering dictionaries by default.
|
||
# %% | ||
# Set up Kane's equations of motion. | ||
# Just the standard way of doing it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the second line, unnecessary.
P1a = me.Particle('P1a', P1, m1) | ||
P2a = me.Particle('P2a', P2, m2) | ||
|
||
BODY = [P1a, P2a] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BODY = [P1a, P2a] | |
bodies = [P1a, P2a] |
Use PEP8 naming conventions if at all possible.
Strange. I never happened with me. |
|
||
BODY = [P1a, P2a] | ||
|
||
FL = [(P1, F * N.x - m1*g*N.y), (P2, -m2*g*N.y)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FL = [(P1, F * N.x - m1*g*N.y), (P2, -m2*g*N.y)] | |
forces = [(P1, F * N.x - m1*g*N.y), (P2, -m2*g*N.y)] |
configuration_constraints=config_constr, | ||
velocity_constraints=speed_constr) | ||
|
||
(fr, frstar) = KM.kanes_equations(BODY, FL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(fr, frstar) = KM.kanes_equations(BODY, FL) | |
fr, frstar = KM.kanes_equations(bodies, loads=forces) |
velocity_constraints=speed_constr) | ||
|
||
(fr, frstar) = KM.kanes_equations(BODY, FL) | ||
EOM = kd.col_join(fr + frstar) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EOM = kd.col_join(fr + frstar) | |
eom = kd.col_join(fr + frstar) |
# Set up the optimization problem and solve it. | ||
# Note: While opty could calculate the reaction forces on, say, the mover, | ||
# (add them to the state variables), my trials showed that even with this | ||
# small example the calculation time increases enourmously. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The note is not helpful in this example, as it is vaguely explained and likely just distracts. I recommend removing it.
state_symbols = tuple((*q_ind, *q_dep, *u_ind, *u_dep)) | ||
constant_symbols = (l, m1, m2, g) | ||
specified_symbols = (F,) | ||
h_opty = sm.symbols('h_opty') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curions why you've chosen to use h_opty
. I changed the variable name internally to this so that there would be no clashes with using h
as a symbol name by the user. It is my intention that a user would never know about this naming convention for the internals and showing it here reveals that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curions why you've chosen to use
h_opty
. I changed the variable name internally to this so that there would be no clashes with usingh
as a symbol name by the user. It is my intention that a user would never know about this naming convention for the internals and showing it here reveals that!
Now I understand your intention with h_opty. Will change back to h.
interval_value = h_opty | ||
|
||
# Specify the known system parameters. | ||
par_map = OrderedDict() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
par_map = OrderedDict() | |
par_map = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had wondered about the OrderedDict - but just copied it from your examples. Will change it.
grad[-1] = 1. | ||
return grad | ||
|
||
# start location and and final location of the load. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make a cell so text is rendered.
|
||
# start location and and final location of the load. | ||
anfang = 0.0 | ||
ende = 15.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is preferable if the documentation is all in English to be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is preferable if the documentation is all in English to be consistent.
I did this because in my early python times, I used English words, which were standard Python terms - and then I wondered why my program did not run (like I called a variable 'range'. Will change it to English.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good method, but we should just make the docs consistent in language. Sphinx does have mechanisms to make multiple versions of the docs in different languages. I've never done that, but I'm sure it would be helpful to many learners.
constant_symbols = (l, m1, m2, g) | ||
specified_symbols = (F,) | ||
h_opty = sm.symbols('h_opty') | ||
unknown_symbols = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used below?
No. I also copied from some example, maybe from Timo. Allows the prob = Problem(..) to be always the same.
Better delete it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it isn't used, then delete it.
) | ||
# %% | ||
# Using a 'reasonable' initial guess speeds up the optimization process a lot. | ||
# 'Bad' initial guesses may even prevent convergence. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just state what initial guess you are constructing. You can plot it easily with plot_trajectories()
to show the reader what it is.
|
||
|
||
# this allows to change the maximum number of iterations. | ||
# Standard is 3000. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still a code comment. Render as cell text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or remove.
# Standard is 3000. | ||
prob.add_option('max_iter', 1000) | ||
# Find the optimal solution. | ||
for _ in range(1): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this loop if there is only one iteration.
Ideally all examples solve with a single call to .solve()
.
print(f"Objective value {solution[-1]: .3e}") | ||
|
||
# %% | ||
# plot the accuracy of the solution. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# plot the accuracy of the solution. | |
# Plot the accuracy of the solution. |
I changed, say, q to |
I made a number of formatting fixes and tried to correct the fps. You can see what I changed here: You can do Two issues remain:
|
In this example, I stored the result of a run, and use this result like this: initial_guess = np.load('solution of a previous run'). I think, the failing test is because Github does not 'have' the previous solution ? |
# - i4 = [-par_map[l] for _ in range(num_nodes)] | ||
# - i5 = [0.0 for _ in range(5*num_nodes)] | ||
# - i6 = [0.01] | ||
# - initial_guess = np.array(i1 + i2 + i3 + i4 + i5 + i6) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this to a full comment cell as an explanation, something like:
# %%
# This initial guess was used to get a solution which forms the actual initial
# guess::
#
# i1 = ...
# i2 = ...
|
||
anim = animation.FuncAnimation(fig, update, | ||
frames=np.arange(t0, tf, 1/fps), | ||
interval=1/fps*1000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The animation does not run until it hits the for me. Maybe it is running out of memory. I suggest reduce the fps and number of frames.
# range(num_nodes)] | ||
# guess:: | ||
# | ||
# - i1 = [(ending_location - starting_location)/num_nodes*i for i in range(num_nodes)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The spacing needs to be such that it renders as code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The spacing needs to be such that it renders as code.
I tried to go as per the sphinx instructions you sent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your idea to execute it but then just overwrite the initial guess with the solution is better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your idea to execute it but then just overwrite the initial guess with the solution is better.
I will change this and make a new PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't make new prs for the same topic, just update this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't make new prs for the same topic, just update this one.
Sorry, I meant I would add to this one only!
# 'solution.npy', to speed up convergence. To get this solution, the initial | ||
# guess above was used, which is now overwritten. | ||
|
||
initial_guess = np.load('solution.npy') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you rename the file to crane_moving_a_load_solution.npy
because we will likely add more of these files. I think even another PR has one named the same and they are all in the same directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you rename the file to
crane_moving_a_load_solution.npy
because we will likely add more of these files. I think even another PR has one named the same and they are all in the same directory.
Makes emminent sense! Will do so right now
You need to |
..and then push again? (By the time I will be 75 I'll be o.k. :-) ) |
Yes |
Can I push while the old check is still running? |
Yes |
|
||
# %% | ||
# The initial guess is the solution of some previous run, saved in the file | ||
# 'solution.npy', to speed up convergence. To get this solution, the initial |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs updating to new filename.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs updating to new filename.
How come you see EVERYTHING?!? I guess, because you are a teacher by trade. Will change it right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, maybe grading papers causes that.
Thanks! Nice example. |
Thank YOU! I must admit, it makes me feel good! :-) |
A load hanging on the horizontal jib of a crane is to be moved from A to B as fast as possible. However, the load must not 'swing over' the final position B, say there is a wall it should not crash into. opty's solution is quite different from what I naively expected.