I am using JuMP and Ipopt to solve an online optimization for a Furuta pendulum. Quite quickly I got it running in simulation but for the real pendulum I had some trouble. The trouble was solved by substituting one of the inputs with a large negative number. My guess is that this simplifies the optimization making it faster and less prone to failing. If that is the case, why does it work that way? Could it be a scaling issue?
In the code below the phidot, theta and thetadot are the measured values from the pendulum. The phi angle is replaced with -1000.0 which makes the controller work.
function run_mpc(init_phi, init_phidot, init_theta, init_thetadot, u_last)
model = Model(Ipopt.Optimizer)
MOI.set(model, MOI.Silent(), true)
num_time_steps = 10 #10 for 0.02 and 6 for 0.04
Mc = 3
max_speed = 40
@variables model begin
phi[1:num_time_steps]
-max_speed <= phidot[1:num_time_steps] <= max_speed
theta[1:num_time_steps]
-max_speed <= thetadot[1:num_time_steps] <= max_speed
u[1:num_time_steps-1]
end
set_start_value.(u, vcat(u_last[2:num_time_steps-1],0.0))
# Dynamics constraints
@NLconstraint(model, [i=2:num_time_steps],
phi[i] == phidot[i-1]*h + phi[i-1])
@NLconstraint(model, [i=2:num_time_steps],
phidot[i] == h*(1/(alfa*beta-gamma^2+(beta^2+gamma^2)*sin(theta[i-1])^2)*(beta*gamma*(sin(theta[i-1])^2-1)*sin(theta[i-1])*phidot[i-1]^2-2*beta^2*cos(theta[i-1])*sin(theta[i-1])*phidot[i-1]*thetadot[i-1]+beta*gamma*sin(theta[i-1])*thetadot[i-1]^2-gamma*delta*cos(theta[i-1])*sin(theta[i-1])+beta*u[i-1]))+phidot[i-1])
@NLconstraint(model, [i=2:num_time_steps],
theta[i] == thetadot[i-1]*h + theta[i-1])
@NLconstraint(model, [i=2:num_time_steps],
thetadot[i] == h*(1/(alfa*beta-gamma^2+(beta^2+gamma^2)*sin(theta[i-1])^2)*(beta*(alfa+beta*sin(theta[i-1])^2)*cos(theta[i-1])*sin(theta[i-1])*phidot[i-1]^2+2*beta*gamma*(1-sin(theta[i-1])^2)*sin(theta[i-1])*phidot[i-1]*thetadot[i-1]-gamma^2*cos(theta[i-1])*sin(theta[i-1])*thetadot[i-1]^2+delta*(alfa+beta*sin(theta[i-1])^2)*sin(theta[i-1])-gamma*cos(theta[i-1])*u[i-1]))+thetadot[i-1])
#@constraint(model, [i=Mc+1:num_time_steps-1],
#u[i] == u[Mc])
# Cost function: minimize final position and final velocity
@objective(model, Min,
4*sum(theta[num_time_steps].^2) + 1*phidot[num_time_steps]^2 + 1*sum(thetadot[num_time_steps-1:num_time_steps].^2))
# Initial conditions:
@NLconstraint(model, phi[1] == init_phi)
@NLconstraint(model, phidot[1] == init_phidot)
@NLconstraint(model, theta[1] == init_theta)
@NLconstraint(model, thetadot[1] == init_thetadot)
optimize!(model)
return getvalue.(u)
end