提问人:adav0033 提问时间:10/10/2023 最后编辑:adav0033 更新时间:10/10/2023 访问量:42
Python 2D 路径规划算法 - 动态窗口方法,机器人在达到目标之前失速
Python 2D Path Planning Algo - Dynamic Window Approach, Robot Stalls Before Reaching Goal
问:
我一直在尝试通过从在线一些来源定制一个类似的示例来为差速驱动机器人实现 DWA pp 算法。问题是机器人似乎与目标目的地一致移动,然后似乎停滞不前,再次查看数学/代码并更改权重。我觉得我忽略了一些非常简单的事情。
AtsushiSakai Github Repo Andrew Davison 的实现
import math
import matplotlib.pyplot as plt
import numpy as np
show_animation = True
def dwa_control(x, config, goal, ob):
"""
Dynamic Window Approach control
"""
dw = calc_dynamic_window(x, config)
u, trajectory = calc_control_and_trajectory(x, dw, config, goal, ob)
return u, trajectory
class RobotType(Enum):
circle = 0
class Config:
"""
simulation parameter class
"""
def __init__(self, objects=[]):
# robot parameter
self.max_speed = 1 # [m/s]
self.min_speed = 0.1 # [m/s]
self.max_yaw_rate = 40.0 * math.pi / 180.0 # [rad/s]
self.max_accel = 0.5 # [m/ss]
self.max_delta_yaw_rate = 40.0 * math.pi / 180.0 # [rad/ss]
self.v_resolution = 0.01 # [m/s]
self.yaw_rate_resolution = 0.001 * math.pi / 180.0 # [rad/s]
self.dt = 0.1 # [s] Time tick for motion prediction
self.predict_time = 3.0 # [s]
self.to_goal_cost_gain = 1
self.speed_cost_gain = 1
self.obstacle_cost_gain = 0.2
self.robot_stuck_flag_cons = 0.1 # constant to prevent robot being stuck
self.robot_radius = 0.08 # [m] for collision check
########################################
#### Create the boarder ################
########################################
# Set the interval and the half-length of the square
interval = 0.1 # Set the interval
half_length = 1.5 # Half of the square's side length
# Define the coordinates for the four corners of the square
corners = np.array([[-half_length, -half_length],
[-half_length, half_length],
[half_length, half_length],
[half_length, -half_length],
[-half_length, -half_length]]) # Close the square
# Initialize lists to hold the x and y coordinates of the perimeter points
x_coords = []
y_coords = []
# Loop over each edge of the square
for i in range(4):
# Get the x and y coordinates of the start and end points of the edge
x_start, y_start = corners[i]
x_end, y_end = corners[i+1]
# Compute the number of points on the edge (excluding the end point)
num_points = int(np.linalg.norm([x_end - x_start, y_end - y_start]) / interval)
# Generate the x and y coordinates of the points along the edge
x_edge = np.linspace(x_start, x_end, num_points+1, endpoint=False)
y_edge = np.linspace(y_start, y_end, num_points+1, endpoint=False)
# Add the generated coordinates to the lists
x_coords.extend(x_edge)
y_coords.extend(y_edge)
# Convert the lists of x and y coordinates to numpy arrays
x_coords = np.array(x_coords)
y_coords = np.array(y_coords)
# Stack the x and y coordinates horizontally to get the perimeter coordinates
perimeter_coords = np.column_stack((x_coords, y_coords))
########################################
#### Create the boarder ################
########################################
original_list =[[0.8969064108491706, -0.5651451250864348],
[1.0854540479797645, -0.004174765982885018],
[1.3828062660399116, 0.451466868665515],
[1.1216589663314864, 1.238792062624063],
[0.2084636335510397, 0.7959588658531208],
[-1.1115975896775006, 0.883937535573489],
[-1.0916288401200633, -0.031936362295673044],
[-0.6641606999682717, -0.47796167568644166],
[-0.06879411068633204, -0.30915717155985245],
[0.1899610618971512, -0.9471530659845089],
[0.760028409037262, 0.6834467529016156],
[1.3510913382496061, 1.0674145068585537],
[1.3759976980309085, -0.4530586281364102],
[0.7631617249072551, -0.9427117705816841],
[0.28885775051621065, -0.3788668917799926],
[-0.9452180429272703, -1.0168972472130489],
[-0.9078708465646994, 0.10253493795037877],
[-1.1256202508375832, 1.265576336316949],
[-0.2858945061253501, 0.19947932814292693],
[-0.2236097796312978, 1.0420796482650274]]
# Concatenate the perimeter coordinates and the scaled obstacles
self.ob = np.concatenate((original_list, perimeter_coords), axis=0)
config = Config()
def motion(x, u, dt, operate={}):
"""
motion model: Differential Drive Robot
"""
# u: control input [v(m/s), w(rad/m)]
# x: state [x(m), y(m), yaw(rad), v(m/s), omega(rad/s)]
# dt: change in time
# dt = drive_meas.dt
# if angular_velocity == 0:
# self.state[0] += np.cos(self.state[2]) * linear_velocity * dt
# self.state[1] += np.sin(self.state[2]) * linear_velocity * dt
# else:
# th = self.state[2]
# self.state[0] += linear_velocity / angular_velocity * (np.sin(th+dt*angular_velocity) - np.sin(th))
# self.state[1] += -linear_velocity / angular_velocity * (np.cos(th+dt*angular_velocity) - np.cos(th))
# self.state[2] += dt*angular_velocity
# Check for zero angular velocity to avoid division by zero
if u[1] == 0:
x[0] += u[0] * math.cos(x[2]) * dt # Update x-position
x[1] += u[0] * math.sin(x[2]) * dt # Update y-position
else:
th = x[2]
x[0] += u[0] / u[1] * (math.sin(th + dt * u[1]) - math.sin(th)) # Update x-position
x[1] += -u[0] / u[1] * (math.cos(th + dt * u[1]) - math.cos(th)) # Update y-position
x[2] += dt * u[1] # Update yaw
x[3] = u[0] # Update linear velocity
x[4] = u[1] # Update angular velocity
return x
def calc_dynamic_window(x, config):
"""
calculation dynamic window based on current state x
"""
# Dynamic window from robot specification
Vs = [config.min_speed, config.max_speed, -config.max_yaw_rate, config.max_yaw_rate]
# Dynamic window from motion model
Vd = [x[3] - config.max_accel * config.dt, x[3] + config.max_accel * config.dt, x[4] - config.max_delta_yaw_rate * config.dt, x[4] + config.max_delta_yaw_rate * config.dt]
# [v_min, v_max, yaw_rate_min, yaw_rate_max]
dw = [max(Vs[0], Vd[0]), min(Vs[1], Vd[1]), max(Vs[2], Vd[2]), min(Vs[3], Vd[3])]
return dw
def predict_trajectory(x_init, v, y, config):
"""
predict trajectory with an input
"""
# x_init is the initial state
# v is the linear velocity control input.
# y is the angular velocity control input.
# config is the conf object
x = np.array(x_init)
trajectory = np.array(x)
time = 0
while time <= config.predict_time:
x = motion(x, [v, y], config.dt)
trajectory = np.vstack((trajectory, x))
time += config.dt
return trajectory
def calc_control_and_trajectory(x, dw, config, goal, ob):
"""
calculation final input with dynamic window
"""
x_init = x[:]
min_cost = float("inf")
best_u = [0.0, 0.0]
best_trajectory = np.array([x])
# evaluate all trajectory with sampled input in dynamic window
for v in np.arange(dw[0], dw[1], config.v_resolution):
for y in np.arange(dw[2], dw[3], config.yaw_rate_resolution):
trajectory = predict_trajectory(x_init, v, y, config)
# calc cost
to_goal_cost = config.to_goal_cost_gain * calc_to_goal_cost(trajectory, goal)
speed_cost = config.speed_cost_gain * (config.max_speed - trajectory[-1, 3])
ob_cost = config.obstacle_cost_gain * calc_obstacle_cost(trajectory, ob, config)
final_cost = to_goal_cost + speed_cost + ob_cost
# search minimum trajectory
if min_cost >= final_cost:
min_cost = final_cost
best_u = [v, y]
best_trajectory = trajectory
if abs(best_u[0]) < config.robot_stuck_flag_cons \
and abs(x[3]) < config.robot_stuck_flag_cons:
# to ensure the robot do not get stuck in
# best v=0 m/s (in front of an obstacle) and
# best omega=0 rad/s (heading to the goal with
# angle difference of 0)
best_u[1] = -config.max_delta_yaw_rate
return best_u, best_trajectory
def calc_obstacle_cost(trajectory, ob, config):
"""
calc obstacle cost inf: collision
"""
ox = ob[:, 0]
oy = ob[:, 1]
dx = trajectory[:, 0] - ox[:, None]
dy = trajectory[:, 1] - oy[:, None]
r = np.hypot(dx, dy)
if np.array(r <= config.robot_radius).any():
return float("Inf")
min_r = np.min(r)
return 1.0 / min_r # OK
def calc_to_goal_cost(trajectory, goal):
"""
calc to goal cost with angle difference
"""
dx = goal[0] - trajectory[-1, 0]
dy = goal[1] - trajectory[-1, 1]
error_angle = math.atan2(dy, dx)
cost_angle = error_angle - trajectory[-1, 2]
cost = abs(math.atan2(math.sin(cost_angle), math.cos(cost_angle)))
return cost
####################################
######### Plot Functions ###########
####################################
def plot_arrow(x, y, yaw, length=0.1, width=0.01): # pragma: no cover
plt.arrow(x, y, length * math.cos(yaw), length * math.sin(yaw),
head_length=width, head_width=width)
plt.plot(x, y)
def plot_robot(x, y, yaw, config): # pragma: no cover
circle = plt.Circle((x, y), config.robot_radius, color="b")
plt.gcf().gca().add_artist(circle)
out_x, out_y = (np.array([x, y]) +
np.array([np.cos(yaw), np.sin(yaw)]) * config.robot_radius)
plt.plot([x, out_x], [y, out_y], "-k")
####################################
######### Plot Functions ###########
####################################
def main(gx=1.0, gy=1.0):
print(__file__ + " start!!")
# initial state [x(m), y(m), yaw(rad), v(m/s), omega(rad/s)]
x = np.array([0.0, 0.0, math.pi / 8.0, 0.0, 0.0])
# goal position [x(m), y(m)]
goal = np.array([gx, gy])
# input [forward speed, yaw_rate]
trajectory = np.array(x)
ob = config.ob
while True:
u, predicted_trajectory = dwa_control(x, config, goal, ob)
x = motion(x, u, config.dt) # simulate robot
trajectory = np.vstack((trajectory, x)) # store state history
if show_animation:
plt.cla()
# for stopping simulation with the esc key.
plt.gcf().canvas.mpl_connect(
'key_release_event',
lambda event: [exit(0) if event.key == 'escape' else None])
plt.plot(predicted_trajectory[:, 0], predicted_trajectory[:, 1], "-g")
plt.plot(x[0], x[1], "xr")
plt.plot(goal[0], goal[1], "xb")
plt.plot(ob[:, 0], ob[:, 1], "ok")
plot_robot(x[0], x[1], x[2], config)
plot_arrow(x[0], x[1], x[2])
plt.axis("equal")
plt.grid(True)
plt.pause(0.0001)
# check reaching goal
dist_to_goal = math.hypot(x[0] - goal[0], x[1] - goal[1])
if dist_to_goal <= config.robot_radius:
print("Goal!!")
break
print("Done")
if show_animation:
plt.plot(trajectory[:, 0], trajectory[:, 1], "-r")
plt.pause(0.0001)
plt.show()
我试图更改参数,即......
self.max_speed = 1 # [m/s]
self.min_speed = 0.1 # [m/s]
self.max_yaw_rate = 40.0 * math.pi / 180.0 # [rad/s]
self.max_accel = 0.5 # [m/ss]
self.max_delta_yaw_rate = 40.0 * math.pi / 180.0 # [rad/ss]
self.v_resolution = 0.01 # [m/s]
self.yaw_rate_resolution = 0.001 * math.pi / 180.0 # [rad/s]
self.dt = 0.1 # [s] Time tick for motion prediction
self.predict_time = 3.0 # [s]
self.to_goal_cost_gain = 1
self.speed_cost_gain = 1
self.obstacle_cost_gain = 0.2
self.robot_stuck_flag_cons = 0.1 # constant to prevent robot being stuck
self.robot_radius = 0.08 # [m] for collision check
然而,所有组合都没有效果。在我看来,当机器人θ向零前进时,建议的轨迹也有零轨迹或类似的东西。
答: 暂无答案
评论