Rigid body motion with non-conservative forces 👀 #16
Replies: 38 comments 5 replies
-
Beta Was this translation helpful? Give feedback.
-
|
After watching the lecture, it was pretty clear that deriving EOMs for every generalized coordinate using the Euler-Lagrange method can be super tedious (especially for cases with a ton of generalized coordinates). So I decided to make a function that does it for me. The code below defines a function that takes the following inputs:
The function uses the Euler-Lagrange equation to build a symbolic equation for each generalized coordinate. It then converts the 2nd-order equations into a 1st-order system, which is returned as an In the main driver, parameters for a physical system (the compound pendulum shown in the lecture) are defined and passed into the Which shows both Overall, defining a function to automate the derivation of the EOMs for a system for us will save a significant amount of time and effort. Code: using Symbolics
using ModelingToolkit
using OrdinaryDiffEq
using Plots
# ------------------------------------------------------------------------
# Define Lagrangian System
# ------------------------------------------------------------------------
"""
build_lagrangian_system(T, V, F_nc, q_vars, q_dots, t, params)
Automates derivation of EOMs for a physical system using Lagrangian Mechanics
# Arguments
- `T`: Symbolic expression for Kinetic Energy
- `V`: Symbolic expression for Potential Energy
- `F_nc`: Vector of non-conservative forces
- `q_vars`: Vector of generalized coordinates
- `q_dots`: Vector of time derivatives of generalized coordinates
- `t`: time
- `params`: Vector of symbolic parameters
# Returns
- `sys`: ODESystem struct containing vector of 1st-order system of equations for each generalized coordinate and its time derivative (in addition to other objects)
"""
function build_lagrangian_system(T, V, F_nc, q_vars, q_dots, t, params)
Lag = T - V
Dt = Differential(t)
eqs = Equation[]
for i in eachindex(q_vars)
# Euler-Lagrange: d/dt(dL/dq_dot) - dL/dq = F_nc
term1 = Dt(Symbolics.derivative(Lag, q_dots[i]))
term2 = Symbolics.derivative(Lag, q_vars[i])
# build symbolic equation
push!(eqs, expand_derivatives(term1 - term2) ~ F_nc[i])
end
@named sys = ODESystem(eqs, t, q_vars, params)
return structural_simplify(sys)
end
# ------------------------------------------------------------------------
# Main Driver Function
# ------------------------------------------------------------------------
function main()
# --------------------------------------------------------------------
# Symbolic Variables and Parameters
# --------------------------------------------------------------------
@independent_variables t
@variables x(t) θ(t)
@parameters m=0.4 L=1.0 g=9.81 k=0.1 b=0.2
Dt = Differential(t)
x_dot = Dt(x)
θ_dot = Dt(θ)
# --------------------------------------------------------------------
# Kinematics & Energies
# --------------------------------------------------------------------
T = 0.5 * m * (x_dot^2 + (L^2 * θ_dot^2 / 3) + L * x_dot * θ_dot * cos(θ))
V = 0.5 * k * x^2 + m * g * (L/2) * (1 - cos(θ))
F_nc = [-b * x_dot, 0]
q_vars = [x, θ]
q_dots = [x_dot, θ_dot]
params = [m, L, g, k, b]
sys = build_lagrangian_system(T, V, F_nc, q_vars, q_dots, t, params)
# --------------------------------------------------------------------
# Initial Conditions
# --------------------------------------------------------------------
u0 = [
x => 0.0,
θ => 0.5,
x_dot => 0.0,
θ_dot => 0.0
]
tspan = (0.0, 25.0)
prob = ODEProblem(sys, u0, tspan)
sol = solve(prob, Rodas5P())
# --------------------------------------------------------------------
# Plot Results
# --------------------------------------------------------------------
p = plot(sol, idxs=θ, ylabel="Amplitude", label="θ(t)", legend=:topleft)
plot!(p, sol, idxs=x, label="x(t)")
xlabel!(p, "Time (s)")
display(p)
savefig(p, "system_results.png")
end
# ------------------------------------------------------------------------
# Main Driver Call
# ------------------------------------------------------------------------
if abspath(PROGRAM_FILE) == @__FILE__
main()
end
|
Beta Was this translation helpful? Give feedback.
-
|
Yes, this workflow is definitely achievable in Julia, through the following steps outlined:
|
Beta Was this translation helpful? Give feedback.
-
|
this workflow is definitely doable in Julia. The notebook already lays out most of it; you define I think the biggest advantage is how scalable it is. Once you set up a general function, you don’t have to manually derive equations every time, you can just plug in new systems and go straight from physics to simulation, which is way more efficient. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
@cjdipietrantonio I was able to take your code and manipulate it a little to find the optimal mass and best settling time. I found the following results: Optimal Mass: 0.3 kg |
Beta Was this translation helpful? Give feedback.
-
|
Yes I was able to with this setup in Julia, which can automatically generate a full set of differential equations from a Lagrangian and then pass those equations directly into a general numerical solver that produces plots and figures. With the energies T and V, and the Lagrangian L=T−V, and applying the Euler–Lagrange formula, the code uses Symbolics and ModelingToolkit to derive the governing equations symbolically from the generalized coordinates x(t) and θ(t). These symbolic equations are then converted into an ODE system, simplified, and passed to a matrix compatible solver. Finally, the solution object integrates the system over time and can be visualized easily with Plots. Overall Julia is able to be used to handle the entire workflow from physics definition, to automatic equation generation, to numerical solution, to plotting. |
Beta Was this translation helpful? Give feedback.
-
|
Yes, this workflow is achievable in Julia and the setup from the notebook already shows the main pieces needed to go from the physics definition to simulation and visualization. Starting from the kinematics shown in the screenshots, the generalized coordinates are q = [x, θ], and the position and velocity definitions allow us to form the kinetic and potential energies. From there we define the Lagrangian L = T − V, where the kinetic energy includes the coupling term between ẋ and θ̇ and the potential energy includes both the spring energy (1/2)kx² and the gravitational term mg(L/2)(1 − cosθ). Once the Lagrangian is defined symbolically (like in the Pluto notebook using Symbolics and ModelingToolkit), the Euler–Lagrange equations d/dt(∂L/∂q̇ᵢ) − ∂L/∂qᵢ = Fqᵢ can be applied to both x and θ. The damping at the support can be incorporated as a non-conservative generalized force (for example Fx = −b ẋ and Fθ = 0). This produces the coupled second-order differential equations like the ones shown in the symbolic outputs. From there, the next step is converting the second-order equations into a first-order system so they can be used with a numerical solver such as ODEProblem() from DifferentialEquations.jl. After defining the initial conditions, parameters, and time span, the solver generates a solution object that can be directly plotted. This creates a clean pipeline from defining T and V, to forming L = T − V, to automatically generating the equations of motion, to solving and plotting. Similar to what others observed, the results should show the expected damped behavior. The displacement x(t) and angle θ(t) both oscillate and decay toward equilibrium because the damper removes energy from the system. The phase portrait would spiral inward, which indicates a stable damped system, and the total energy should decrease over time, which makes sense physically since the damper dissipates energy. Overall, building a general function to automate the Euler–Lagrange derivation (like looping through the generalized coordinates and constructing the symbolic equations) makes this approach much more efficient. Instead of manually deriving equations for every new mechanical system, you can just define T, V, the generalized coordinates, and any non-conservative forces, then pass everything into a general solver to go directly from the physical model to numerical results and plots. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
I was able to create a set of differential equations in Julia with this set up, then build a general solver that goes from the 3 steps. The general code that builds this is 3 blocks in my code Total cells before code starts: 4Cell 5 of 8 — Build a symbolic system directly from the Euler–Lagrange equationsbegin Total cells before code starts: 5Cell 6 of 8 — Initial conditions and time spanbegin Total cells before code starts: 6Cell 7 of 8 — Generate and solve the ODE problem directly from the symbolic systembegin I find it similar to MATLAB, and I used a similar method,R odas4, rather than Rosenbrock23 which did not work at first. Seems like when choosing these methods it is best for tolerance changes in accuracy.
|
Beta Was this translation helpful? Give feedback.
-
|
Yes, I think this setup can be turned into a general Julia solver. Starting from L=T−V, we can symbolically form the Euler–Lagrange equations, include damping as a generalized force, and then use "ModelingToolkit" plus "OrdinaryDiffEq" to solve the system numerically. Once the equations are packaged into an "ODESystem", the workflow naturally goes from symbolic mechanics to simulation and plotting. The damped pendulum support example is a good case because it shows how coupled equations in x(t) and θ(t) can be derived once and then solved for different parameter values. This can also be generalized into a reusable solver function where you define |
Beta Was this translation helpful? Give feedback.
-
|
It is definitely possible to build a general solver in Julia that moves from the Lagrangian (L = T - V) directly to a numerical solution. By using the Symbolics.jl and ModelingToolkit.jl packages, we can automate the derivation of the equations of motion (EOMs) which saves a lot of time compared to doing the 2nd-order calculus by hand. For the damped pendulum on a sliding support, I defined the kinetic and potential energies and then formed the Lagrangian. The key is to include the non-conservative damping force (F_nc = -b * x_dot) on the right-hand side of the Euler-Lagrange equation: ddt(dL/dq_dot) - dL/dq = F_nc Define symbolic variables for t, x(t), theta(t) and parameters like m, L, g, k, b. Use a loop to apply the Euler-Lagrange formula for each generalized coordinate. Use the structural_simplify() function in ModelingToolkit to convert the 2nd-order symbolic equations into a 1st-order ODESystem. Pass the system to ODEProblem() and use a solver like Rodas5P() or Rosenbrock23(). The resulting plots show exactly what you would expect for a damped system: the displacement x and the angle theta both oscillate and decay over time. Looking at the phase portrait, the inward spiral confirms that the energy is being dissipated by the support damper. This automated approach is much more scalable for complex systems where manual derivation becomes tedious. |
Beta Was this translation helpful? Give feedback.
-
|
This setup can be implemented in Julia and it is possible to build a general solver that goes from a Lagrangian definition all the way to numerical solutions and plots. Working through this problem really helped me appreciate why automation is so useful for Lagrangian mechanics. Building a general function to handle the derivation made the process feel less intimidating. It allowed me to focus more on defining the physics correctly by choosing the right forces. I also found that seeing the symbolic equations turn directly into a numerical solution made the connection between theory and simulation much clearer. Once the equations were converted into a first‑order ODE system and solved, the results matched the lecture: the oscillations decay over time and the system settles back to equilibrium due to damping. Overall, this workflow made Lagrangian mechanics feel more practical and scalable, especially for larger systems. |
Beta Was this translation helpful? Give feedback.
-
|
this is definitely achievable with Julia and similar to others I noticed most of the work was done in the notebook. the steps are defining T and V then inserting the damping term on the right side, applying Euler equations to convert into a differential equation then using an equation solver to find x(t) then convert x(t) into cyclindrical cordinates. |
Beta Was this translation helpful? Give feedback.
-
|
Yes, this can be created in Julia by forming the Lagrangian L=T−V and including damping as a non-conservative force to generate the equations of motion. These equations can then be converted into an ODE system and solved numerically to produce plots and visualizations. The results behave as expected for a damped system: both x and θ oscillate and decay over time as energy is dissipated through the support. In some cases, x may not return to zero but instead settles at a nonzero equilibrium position, which reflects how the system balances under damping and restoring forces. Overall, this workflow is efficient and scalable, allowing you to go directly from defining the physics to analyzing system behavior without manually deriving equations each time. |
Beta Was this translation helpful? Give feedback.
-
|
Yes, this workflow is very feasible in Julia using the existing symbolic and numerical tooling: you can define the Lagrangian L=T−VL=T-VL=T−V symbolically, automatically form the Euler–Lagrange equations including non‑conservative generalized forces FqF_qFq, and then pass the resulting differential equations directly to DifferentialEquations.jl for numerical solution. ModelingToolkit in particular is designed to go from symbolic system definition to generated ODE functions, which makes it possible to build a fairly general pipeline that starts from LLL, constructs d/dt(∂L/∂q˙)−∂L/∂q=Fq, solves the equations, and produces plots using Plots.jl—all with minimal boilerplate and good performance. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
|
Beta Was this translation helpful? Give feedback.
-
|
Yes a set of differential equations can be built into Julia with this set up. First you have to define the kinetic and potential energy to form the Lagrangian as L=T−V. Then use the Euler-Lagrange equation to each coordinate, with the damping added. Then, the equations can be converted into a first-order ODE system and solved and put into julia to graph it. |
Beta Was this translation helpful? Give feedback.
-
|
This discussion helped clarify the goals and expectations for the rotating pendulum project. It was useful to see how the system builds directly on the simple pendulum example but adds complexity through rotation, coupling, and non inertial effects. Identifying appropriate generalized coordinates early on seems especially important to keep the equations of motion manageable. I also appreciated the emphasis on using a Lagrangian approach rather than force balances, since it makes it easier to account for constraints and energy terms in a systematic way. It’s clear that visualizations and animations are important for validating the model and understanding how parameters like rotation rate affect stability and motion. Overall, this discussion made the project feel more approachable by framing it as a natural extension of what we’ve already done rather than an entirely new problem. |
Beta Was this translation helpful? Give feedback.
-
here is what I were able to put together. it can definetly be put together as seen above
|
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
As many others have already demonstrated, it is possible to go from the Lagrangian to the Euler-Lagrange to the solved ODE, and then plot it. I have found a tool in Julia called multibody that can provide plots and models of multibody systems without having to define the Euler-Lagrange or ODEs. Whether or not that helps develop an understanding or appreciation of advanced dynamics is for you to decide. Below is the link to the tutorial site if you are interested in building something with it. All you need to do is define the shapes of the bodies, their connections, and the initial conditions, and then Multibody can solve it for you. |
Beta Was this translation helpful? Give feedback.
-
|
Yes it is possible to create the solver and plot it. Going through the notebook I started with L = T - V, which then made the rest of the process feel more organized. Having the Lagrangian set, the Euler-Lagrange equations were formed quickly with Symbolics. Adding the damping term as a generalized force also made sense since the damping comes from the moving support.. After that, the equations can be passed into ModelingToolkit and turned into a first‑order ODE system, making them easy to solve with OrdinaryDiffEq. From there, plotting the results helps show how the base motion and pendulum angle are coupled and how both motions decay over time due to damping at the support. |
Beta Was this translation helpful? Give feedback.



























Uh oh!
There was an error while loading. Please reload this page.
-
Rigid body motion with non-conservative forces
In this video, I build the Lagrange equations of motion for a pendulum that is damped at its support. In the Pluto notebook, I start to create the Symbolic equations of motion with the variational equations derived in the video.
Are you able to create a set of differential equations in Julia with this set up? Can we build a general solver that goes from:
eqs =ode_solver(eqs)to plots and figures?
Beta Was this translation helpful? Give feedback.
All reactions