【python+ROS+路径规划】六、mpc轨迹规划和跟踪

该博客介绍了如何使用Python的Pyomo库进行模型预测控制(MPC)以优化轨迹并进行轨迹跟踪。内容包括使用A*算法生成初始路径,构建MPC的数学模型,定义目标函数和约束,以及解决优化问题的步骤。博客还展示了如何调整参数以优化路径,并通过MPC框架实时更新控制指令,确保机器人按照规划的轨迹行驶。
摘要由CSDN通过智能技术生成

所使用的就是pyomo,使用mpc框架,达到的效果是优化轨迹并进行轨迹跟踪,如图:
pyomo相关教程:【python+ROS+路径规划】五、pyomo非线性规划工具.

在这里插入图片描述

使用mpc优化路径

首先要有一个初始路径:
使用Astar的可以见这篇文章:【python+ROS+路径规划】四、发布路径
或者也可以使用ros包中的路径。

mpc框架的数学形式

在这里插入图片描述
其中目标函数为:
在这里插入图片描述
这里为了简化模型,控制不是加速度而是速度,第一项是原始轨迹和优化轨迹的差,第二项是参考控制和优化控制的差,第三项是两个相邻的控制之间的差。

mpc轨迹规划代码

使用pyomo搭建的具体框架如下:

def MPC_opt(path,theta):
	#滚动长度
    H = len(path)-1
    model = ConcreteModel()
    #Set
    model.zk_number = RangeSet(1,H)
    model.uk_number = RangeSet(0,H)
    model.uk_obj = RangeSet(0,H-1)

    # Parameters
    #需要调节的参数如下
    model.Q = Param(RangeSet(1,2),initialize={1:1,2:1},mutable=True)
    model.R = Param(RangeSet(1,2),initialize={1:1,2:1},mutable=True)
    model.S = Param(RangeSet(1,2),initialize={1:1,2:1},mutable=True)
	#这个要根据机器人来定
    model.vmax = Param(initialize=0.5)
	#这个也要自己计算,这里是每两个点之间的距离除以最大速度
    model.dt = Param(initialize=0.04998/model.vmax)
   

    model.z0 = Param(RangeSet(0,state_number-1),initialize={0:path[0][0],1:path[0][1],2:theta[0]})



    # Variables

    model.z = Var(RangeSet(0,state_number-1),model.uk_number)   #建立[x,y,θ]变量
    model.v = Var(model.uk_number,bounds=(0,model.vmax))
    model.w = Var(model.uk_number,bounds=(-1,1))

    #0:x   1:y    2:θ
    #0:v   1:w

    # Constraint
    model.z0_update = Constraint(RangeSet(0,state_number-1),rule=lambda model,i:model.z[i,0]==model.z0[i])
    
    model.x_update = Constraint(model.uk_number,rule=lambda model,k:model.z[0,k+1]==model.z[0,k]+model.v[k]*cos(model.z[2,k])*model.dt
                                if k<=H-1 else Constraint.Skip)
    model.y_update = Constraint(model.uk_number,rule=lambda model,k:model.z[1,k+1]==model.z[1,k]+model.v[k]*sin(model.z[2,k])*model.dt
                                if k<=H-1 else Constraint.Skip)
    model.θ_update = Constraint(model.uk_number,rule=lambda model,k:model.z[2,k+1]==model.z[2,k]+model.w[k]*model.dt
                                if k<=H-1 else Constraint.Skip)
    

    

    

    # Objective
    model.xQx = model.Q[1]*sum((model.z[0,i]-path[i-1][0])**2 for i in model.zk_number)
    model.yQy = model.Q[2]*sum((model.z[1,i]-path[i-1][1])**2 for i in model.zk_number)


    model.vRv = model.R[1]*sum((model.vmax-model.v[i])**2 for i in model.uk_obj)
    model.wRw = model.R[2]*sum(model.w[i]**2 for i in model.uk_obj)

    model.dvSdv = model.S[1]*sum((model.v[i+1]-model.v[i])**2 for i in model.uk_obj)
    model.dwSdw = model.S[2]*sum((model.w[i+1]-model.w[i])**2 for i in model.uk_obj)

    model.obj = Objective(expr=model.xQx+model.yQy+model.vRv+model.wRw+model.dvSdv+model.dwSdw,sense=minimize)
    

    #Solve
    SolverFactory("ipopt").solve(model)
    x_opt = [model.z[0,k]() for k in model.zk_number]
    y_opt = [model.z[1,k]() for k in model.zk_number]
    θ_opt = [model.z[2,k]() for k in model.zk_number]




    return x_opt,y_opt,θ_opt

这里注意,轨迹的优化方面初始是没有角度的,之所以最后给出了角度,是因为有运动学方程,这也是mpc的优点。

使用mpc跟踪

框架搭建同理:

def MPC_tracking(path,theta,vref,info):
    H = len(path)-1

    if H <= 2:
        return 0,0
    else:

        model = ConcreteModel()
        #Set
        model.zk_number = RangeSet(1,H)
        model.uk_number = RangeSet(0,H)
        model.uk_obj = RangeSet(0,H-1)

        # Parameters
        model.Q = Param(RangeSet(1,3),initialize={1:1,2:1,3:0.01},mutable=True)
        model.R = Param(RangeSet(1,2),initialize={1:0.5,2:0.02},mutable=True)
        model.S = Param(RangeSet(1,2),initialize={1:0.1,2:0.05},mutable=True)

        model.vref = vref

        model.dt = 0.04998/model.vref
    

        model.z0 = Param(RangeSet(0,state_number-1),initialize={0:info[0],1:info[1],2:info[2]})



        # Variables

        model.z = Var(RangeSet(0,state_number-1),model.uk_number)   #建立[x,y,θ]变量
        model.v = Var(model.uk_number,bounds=(0,vmax))
        model.w = Var(model.uk_number,bounds=(-1,1))

        #0:x   1:y    2:θ
        #0:v   1:w

        # Constraint
        model.z0_update = Constraint(RangeSet(0,state_number-1),rule=lambda model,i:model.z[i,0]==model.z0[i])
        
        model.x_update = Constraint(model.uk_number,rule=lambda model,k:model.z[0,k+1]==model.z[0,k]+model.v[k]*cos(model.z[2,k])*model.dt[k]
                                    if k<=H-1 else Constraint.Skip)
        model.y_update = Constraint(model.uk_number,rule=lambda model,k:model.z[1,k+1]==model.z[1,k]+model.v[k]*sin(model.z[2,k])*model.dt[k]
                                    if k<=H-1 else Constraint.Skip)
        model.θ_update = Constraint(model.uk_number,rule=lambda model,k:model.z[2,k+1]==model.z[2,k]+model.w[k]*model.dt[k]
                                    if k<=H-1 else Constraint.Skip)


        # Objective
        model.xQx = model.Q[1]*sum((model.z[0,i]-path[i-1][0])**2 for i in model.zk_number)
        model.yQy = model.Q[2]*sum((model.z[1,i]-path[i-1][1])**2 for i in model.zk_number)
        model.θQθ = model.Q[3]*sum((model.z[2,i]-theta[i])**2 for i in model.zk_number)


        model.vRv = model.R[1]*sum((model.vref[i]-model.v[i])**2 for i in model.uk_obj)
        model.wRw = model.R[2]*sum(model.w[i]**2 for i in model.uk_obj)

        model.dvSdv = model.S[1]*sum((model.v[i+1]-model.v[i])**2 for i in model.uk_obj)
        model.dwSdw = model.S[2]*sum((model.w[i+1]-model.w[i])**2 for i in model.uk_obj)

        model.obj = Objective(expr=model.xQx+model.yQy+model.θQθ+model.vRv+model.wRw+model.dvSdv+model.dwSdw,sense=minimize)
        

        #Solve
        SolverFactory("ipopt").solve(model)
        v_opt = model.v[0]()
        w_opt = model.w[0]() 

        return v_opt,w_opt

发布控制指令

之后发布速度和角速度:

    def mpcTracking(self):
        #前置信息
        #首先计算时间
        dt = 0.04998/self.Vref#最后一个没有用,第一个对应从第一个点到第二个点应该用的时间
        theta = self.iniTheta
        pose = self.iniPose
        vref = self.Vref
        #最后一个速度应该为0,先设置在约束上面

        MPCCC = rospy.Publisher("/cmd_vel",Twist,queue_size=15)
        msg = Twist()

        # rate = rospy.Rate(400)
        
        k = 0
        T = 10  #滚动时域
#----------------------------------------------------------------------------------
		while k < len(dt):
            du = rospy.Duration(dt[k])
        #需要根据时间获取当前信息
            now_x,now_y,now_theta = self.getNowPose()
        #这里得到的角度和使用的角度可能不一样
			info = [now_x,now_y,opt_theta]
#---------------------------------------------------------------------------------------
		#这里使用相关mpc算法,拿到速度角速度指令
		#v_opt,w_opt
#---------------------------------------------------------------------------------------
            msg.linear.x = v_opt
            msg.angular.z = w_opt
            MPCCC.publish(msg)
            # rate.sleep()
            rospy.sleep(du)
            k +=1
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薯一个蜂蜜牛奶味的愿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值