如何在Pyomo中实现多智能体路径规划的碰撞避免约束?
解决Pyomo多智能体路径规划中的碰撞避免约束问题
错误原因说明
你遇到的Cannot convert non-constant Pyomo expression (...) to bool错误,是因为Pyomo不允许在约束中直接使用!=或or这类布尔逻辑操作——这些操作会试图将包含变量的Pyomo表达式转换为布尔值,但变量在求解完成前是未知的,无法直接判定真假。必须用线性化技术(比如大M法)来表达碰撞避免的逻辑,或者使用非线性求解器支持的非线性约束。
方案1:引入位置变量+大M线性化约束(推荐)
先优化模型结构,显式定义智能体的位置变量,替代原来的get_x/get_y函数,这样约束更清晰,计算效率更高,再用大M法实现线性化的碰撞避免逻辑。
步骤1:添加位置变量与更新约束
# 1. 定义位置变量,整数域对应网格范围 model.pos_x = po.Var(model.time, model.agents, domain=po.Integers, bounds=(1, 10)) model.pos_y = po.Var(model.time, model.agents, domain=po.Integers, bounds=(1, 10)) # 2. 初始位置约束:t=1时位置等于出生点 def init_pos_x(model, a): return model.pos_x[1, a] == model.spawns[a, 1] model.init_pos_x = po.Constraint(model.agents, rule=init_pos_x) def init_pos_y(model, a): return model.pos_y[1, a] == model.spawns[a, 2] model.init_pos_y = po.Constraint(model.agents, rule=init_pos_y) # 3. 位置更新约束:每个时间步的位置由前一步位置+移动量决定 def update_pos_x(model, t, a): if t == 1: return po.Constraint.Skip return model.pos_x[t, a] == model.pos_x[t-1, a] + model.moveRight[t-1, a] - model.moveLeft[t-1, a] model.update_pos_x = po.Constraint(model.time, model.agents, rule=update_pos_x) def update_pos_y(model, t, a): if t == 1: return po.Constraint.Skip return model.pos_y[t, a] == model.pos_y[t-1, a] + model.moveDown[t-1, a] - model.moveUp[t-1, a] model.update_pos_y = po.Constraint(model.time, model.agents, rule=update_pos_y)
步骤2:实现碰撞避免约束(大M法)
引入辅助布尔变量,通过线性约束确保任意两个智能体在同一时间步的x或y坐标至少相差1:
# 大M值取网格最大边长即可(这里网格是10x10,取10) M = 10 # 辅助布尔变量:z1[t,a,a']=1表示智能体a和a'的x坐标不同;z2表示y坐标不同 model.z1 = po.Var(model.time, model.agents, model.agents, domain=po.Boolean) model.z2 = po.Var(model.time, model.agents, model.agents, domain=po.Boolean) # 碰撞避免约束逻辑 def collision_avoidance(model, t, a, a_prime): if t == 1 or a >= a_prime: return po.Constraint.Skip # 跳过初始时间和重复的智能体对 # 约束1:z1=1时,x坐标至少相差1;z1=0时约束自动满足 cons1 = model.pos_x[t, a] - model.pos_x[t, a_prime] >= 1 - M * (1 - model.z1[t, a, a_prime]) cons2 = model.pos_x[t, a_prime] - model.pos_x[t, a] >= 1 - M * model.z1[t, a, a_prime] # 约束2:z2=1时,y坐标至少相差1;z2=0时约束自动满足 cons3 = model.pos_y[t, a] - model.pos_y[t, a_prime] >= 1 - M * (1 - model.z2[t, a, a_prime]) cons4 = model.pos_y[t, a_prime] - model.pos_y[t, a] >= 1 - M * model.z2[t, a, a_prime] # 约束3:z1和z2至少有一个为1,即x或y坐标必须错开 cons5 = model.z1[t, a, a_prime] + model.z2[t, a, a_prime] >= 1 return [cons1, cons2, cons3, cons4, cons5] model.collision_cons = po.Constraint(model.time, model.agents, model.agents, rule=collision_avoidance)
方案2:非线性约束(仅适用于非线性求解器)
如果你可以使用支持非线性规划的求解器(比如IPOPT),可以直接用距离约束,无需引入辅助变量:
def collision_avoidance_nonlinear(model, t, a, a_prime): if t == 1 or a >= a_prime: return po.Constraint.Skip # 两个智能体的欧氏距离平方至少为1(即不同位置) return (model.pos_x[t,a] - model.pos_x[t,a_prime])**2 + (model.pos_y[t,a] - model.pos_y[t,a_prime])**2 >= 1 model.collision_cons_nonlinear = po.Constraint(model.time, model.agents, model.agents, rule=collision_avoidance_nonlinear)
注意:这种方法求解速度通常比线性化方法慢,且只能用非线性求解器。
补充现有代码的小问题修正
- 你的代码中
params["width"]和params["height"]未定义,建议替换为实际网格边界,比如10或model.width.last(); limit_speed约束应确保智能体同一时间步最多向一个方向移动(或不动),示例如下:def limit_speed(model, t, a): return model.moveRight[t,a] + model.moveLeft[t,a] + model.moveUp[t,a] + model.moveDown[t,a] <= 1
内容的提问来源于stack exchange,提问作者Girop
相关产品推荐
相关产品推荐

