Obstacle avoidance Python solver status 2 and 4

Hello,

I am trying to implement MPC with obstacle avoidance for a simple mobile robot (kinematic model). I have implemented the code as below.


class mpc(object):
    def __init__(self):
        self.RUN_ONCE = True
        self.tcomp_sum = 0
        self.tcomp_max = 0
        self.acados_solver = 0
        self.N = 0

    def kine_model(self):

        model = types.SimpleNamespace()
        model_name = 'kine_ode'


        x = SX.sym('x')
        y = SX.sym('y')
        phi = SX.sym('phi')
        states = vertcat(x, y, phi)
        
        obs_x = SX.sym('obs_x')
        obs_y = SX.sym('obs_y')
        
        dist = sqrt((x- obs_x)*(x- obs_x)+(y - obs_y)*(y - obs_y))
        
        # controls
        v = SX.sym('v')
        phidot = SX.sym('phidot')
        u = vertcat(v,phidot)
        
        # statesdot
        xdot  = SX.sym('xdot')
        ydot  = SX.sym('ydot')
        phid = SX.sym('phid')


        statesdot = vertcat(xdot, ydot, phid)

        # algebraic variables
        # z = None

        # parameters
        p = vertcat(obs_x, obs_y)
        
        # dynamics
        f_expl = vertcat(v*cos(phi),
                        v*sin(phi),
                        phidot
                        )

        f_impl = statesdot - f_expl

        model = AcadosModel()

        model.f_impl_expr = f_impl
        model.f_expl_expr = f_expl
        model.x = states
        model.xdot = statesdot
        model.u = u
        # model.z = z
        model.p = p
        model.name = model_name
        
        model.con_h_expr = dist    
        model.con_h_expr_e = dist   
    

        return model

    ##############################################    
    def acado_set(self, x0):
        # create ocp object to formulate the OCP
        ocp = AcadosOcp()
        Tf = 1
        self.N = 20

        # set model
        model = self.kine_model()

        nx = model.x.size()[0]
        nu = model.u.size()[0]
        ny = nx + nu
        ny_e = nx
        npa = model.p.size()[0]


        ocp.model = model
        # set dimensions
        ocp.dims.N = self.N
        ocp.dims.np = npa


        # set cost module
        ocp.cost.cost_type = 'LINEAR_LS'
        ocp.cost.cost_type_e = 'LINEAR_LS'
        
        ocp.parameter_values = np.array([0.6, 0.6]) # initial obstacle location
             
        ocp.constraints.uh = np.array([10000])
        ocp.constraints.uh_e = np.array([10000])
        ocp.constraints.lh = np.array([0.15])
        ocp.constraints.lh_e = np.array([0.15])
        

        Q = np.diag([1, 1, 1])
        R = np.diag([0.001, 0.01])
        Qe = np.diag([0.1, 0.1, 0.1])

        ocp.cost.W = scipy.linalg.block_diag(Q, R)

        ocp.cost.W_e = Qe 

        ocp.cost.Vx = np.zeros((ny, nx))
        ocp.cost.Vx[:nx,:nx] = np.eye(nx)

        Vu = np.zeros((ny, nu))
        Vu[3,0] = 1.0
        Vu[4,1] = 1.0
        ocp.cost.Vu = Vu

        Vx_e = np.zeros((ny_e, nx))
        Vx_e[:nx, :nx] = np.eye(nx)
        ocp.cost.Vx_e = Vx_e

        ocp.cost.yref  = np.zeros((ny, ))
        ocp.cost.yref_e = np.zeros((ny_e, ))

        # set constraints
        vmax = 0.5
        phidotmax = 0.785
        ocp.constraints.lbu = np.array([-vmax, -phidotmax])
        ocp.constraints.ubu = np.array([vmax, phidotmax])
        ocp.constraints.x0 = x0
        ocp.constraints.idxbu = np.array([0, 1]) 

        ocp.solver_options.qp_solver = 'PARTIAL_CONDENSING_HPIPM'
        #ocp.solver_options.qp_solver = 'FULL_CONDENSING_HPIPM'
        ocp.solver_options.hessian_approx = 'GAUSS_NEWTON'
        ocp.solver_options.integrator_type = 'ERK'
        ocp.solver_options.nlp_solver_type = 'SQP' 
        ocp.solver_options.sim_method_num_stages = 4
        ocp.solver_options.sim_method_num_steps = 3
        ocp.solver_options.qp_solver_cond_N = 5
        ocp.solver_options.qp_solver_iter_max = 100
        ocp.solver_options.nlp_solver_max_iter = 500
        

        # set prediction horizon
        ocp.solver_options.tf = Tf

        acados_ocp_solver = AcadosOcpSolver(ocp, json_file = 'acados_ocp_' + model.name + '.json')

        return  acados_ocp_solver
    ############################################

    def run_mpc(self, ydes, x0, obs_x, obs_y):

        ## Assuming ydes is single point 

        if self.RUN_ONCE:
            self.acados_solver = self.acado_set(x0)
            self.RUN_ONCE = False
         
        
        for j in range(self.N):
            # yref = ydes[j]
            yref = ydes
            self.acados_solver.set(j, "yref", yref)
            self.acados_solver.set(j,"p", np.array([obs_x, obs_y]))
          
        yref_N = ydes[0:3]
        # yref_N=np.array([0,0,0,0,0,0])
        self.acados_solver.set(self.N, "yref", yref_N)
        
        self.acados_solver.set(0, "lbx", x0)
        self.acados_solver.set(0, "ubx", x0)


        # solve ocp
        status = self.acados_solver.solve()

        # get solution
        x0 = self.acados_solver.get(0, "x")
        u0 = self.acados_solver.get(0, "u")
        
        #self.acados_solver.print_statistics()

        return u0

The robot was able to reach the target each time when no obstacles were present. After adding the obstacles (taking into consideration only the nearest object) the solver either ignores the obstacle and crashes into it or if it passes really close the status of the solver is always 2 or 4. I tried changing the number of iterations but nothing changed.

  1. What am I doing wrong?
  2. How is the idxbu matrix set? (I used it as the race cars example and tried changing the values)
  3. Is it possible to reset the solver after it keeps returning status 4?
    All suggestions are welcome. :slightly_smiling_face:

Update 1:

  1. I forgot to include p at the terminal step.
  2. Figured out the idxbu matrix setting.
  3. The solver returns the following message regularly and the robot crashes into obstacles.
QP solver returned error status 37 in SQP iteration 1, QP iteration 72.
[INFO] [1643279185.566672, 4.098000]: acados returned status 4
  1. I tried adding the levenberg_marquardt term but the issue persists.

@FreyJo Could you give me some hints? Thanks in advance

Hi,

did you play a bit with the initialization of the solver?
Ideally, try the store_iterate() and load_iterate() functions.

This topic seems to be strongly related to the question here

Although posed specifically for Matlab there.

Cheers!

Hey @FreyJo ,

I actually tried storing each iterate with a 0 return status and then load it the next iterate, but it didn’t make any noticeable improvements.
I then tried initializing X at each iterate (with the current status instead of zeros) the same way mentioned here Cost and linearization points - #6 by FreyJo . It did improve the performance a little (less crashes) but the errors persists.

  1. Could you please suggest a different way to initialize x, u and pi ?
  2. If the initialization of X is necessary for this OCP, does that mean that it would be better to include a path planner (for better x initialization)?

Thanks for your time :slightly_smiling_face:

Hi @mdavid ,
is your implementation with the obstacle correct? Does the solver give you useful outputs when you parameterize the obstacle far outside, so that it shouldn’t influence your actual trajectory?

If you have more information about your optimal solution, it’s better and it will faster converge. But the question here is, if it is caused by this initialization or anything different in your problem formulation.

Bye!

Hey @mss ,

is your implementation with the obstacle correct? Does the solver give you useful outputs when you parameterize the obstacle far outside, so that it shouldn’t influence your actual trajectory?

I tried placing the parameters far and the solver stopped giving errors. So I think the implementation with the obstacle is correct.

I will try to formulate the problem differently first, if it fails I will try using a planner.

Thanks for your answer.

Hi,
try to penalize your final value more and not that much on your states. That might soften your problem.

Hey @mss ,

Thank you for the suggestion, I actually tried manipulating the weight matrices a lot but it didn’t show any improvement.
I also tried using another instance of the solver with no obstacles and use the states generated for the initialization of the original solver (avoiding the obstacles) but it didn’t work either. :man_facepalming: