Skip to content

Commit 3aadeb0

Browse files
committed
better pathplanning
1 parent 1a97e9c commit 3aadeb0

2 files changed

Lines changed: 61 additions & 9 deletions

File tree

navigation/dynamicPathPlanner.py

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ class DynamicPathPlannerGoal():
1414
def __init__(self, endPose:Pose2d):
1515
self.endPose = endPose
1616
self.baseMap = GradientDescentCostMap(self.endPose)
17+
self.baseMap.add_obstacle(Translation2d(5.56, 2.74),100,0.75)
18+
self.baseMap.add_obstacle(Translation2d(3.45, 4.07),100,0.75)
19+
self.baseMap.add_obstacle(Translation2d(5.56, 5.35),100,0.75)
20+
self.baseMap.add_obstacle(Translation2d(11.0, 2.74),100,0.75)
21+
self.baseMap.add_obstacle(Translation2d(13.27, 4.07),100,0.75)
22+
self.baseMap.add_obstacle(Translation2d(11.0, 5.35),100,0.75)
1723

1824
GOAL_PICKUP = DynamicPathPlannerGoal(Pose2d.fromFeet(40,5,Rotation2d.fromDegrees(0.0)))
1925
GOAL_SPEAKER = DynamicPathPlannerGoal(Pose2d.fromFeet(3,20,Rotation2d.fromDegrees(0.0)))
@@ -54,7 +60,12 @@ def addObstacleObservation(self, obs:ObstacleObservation):
5460
def _obstacleCostHeuristic(timeToLive:float)->float:
5561
""" return the "height" used in pathplanning based on the alive time"""
5662
return timeToLive * 2.0
57-
63+
64+
def _getHolonomicRotation(self, time_s:float)->Rotation2d:
65+
if(self.curTraj is not None and self.trajStartTime_s is not None):
66+
initialPose = self.trajCfg
67+
68+
5869
def get(self) -> DrivetrainCommand:
5970
if(self.curTraj is not None and self.trajStartTime_s is not None):
6071
# Trajectory doesn't work great for holonomic drivetrains.
@@ -66,9 +77,14 @@ def get(self) -> DrivetrainCommand:
6677
nextTime = curTime + 0.01
6778
deltaTime = nextTime - prevTime
6879

69-
prevSample = self.curTraj.sample(prevTime).pose
70-
curSample = self.curTraj.sample(curTime).pose
71-
nextSample = self.curTraj.sample(nextTime).pose
80+
prevSampleTrans = self.curTraj.sample(prevTime).pose.translation()
81+
curSampleTrans = self.curTraj.sample(curTime).pose.translation()
82+
nextSampleTrans = self.curTraj.sample(nextTime).pose.translation()
83+
84+
# Adjust the sample poses to have the correct holonomic rotation
85+
prevSample = Pose2d(prevSampleTrans, Rotation2d())
86+
curSample = Pose2d(curSampleTrans, Rotation2d())
87+
nextSample = Pose2d(nextSampleTrans, Rotation2d())
7288

7389
xVel = (nextSample.translation().X() - prevSample.translation().X())/deltaTime
7490
yVel = (nextSample.translation().Y() - prevSample.translation().Y())/deltaTime
@@ -116,8 +132,44 @@ def _do_replan(self, curPose:Pose2d) -> np.ndarray:
116132
# Calc a new path
117133
self.waypoints = workingMap.calculate_path(curPose)
118134

135+
# Get start/end poses for feeding to the trajectory generation
136+
# These should be in the same translations as start/end points
137+
# But with rotations that reflect the intended velocity vector of the robot
138+
# at the start and end.
139+
# This is needed because the trajectory generator is designed around tank drives
140+
# but since we have a swerve drive, robot heading and velocity vector heading are decoupled
141+
if(len(self.waypoints) > 2):
142+
startTrajPose = Pose2d(
143+
translation=curPose.translation(),
144+
rotation=self._getDirection(self.waypoints[0], self.waypoints[1])
145+
)
146+
endTrajPose = Pose2d(
147+
translation=self.curGoal.endPose.translation(),
148+
rotation=self._getDirection( self.waypoints[-2],self.waypoints[-1])
149+
)
150+
else:
151+
startTrajPose = Pose2d(
152+
translation=curPose.translation(),
153+
rotation=self._getDirection(curPose.translation(),
154+
self.curGoal.endPose.translation())
155+
)
156+
endTrajPose = Pose2d(
157+
translation=self.curGoal.endPose.translation(),
158+
rotation=self._getDirection(curPose.translation(),
159+
self.curGoal.endPose.translation())
160+
)
161+
162+
119163
# TODO - initial velocity
120-
self.curTraj = TrajectoryGenerator.generateTrajectory(curPose, self.waypoints, self.curGoal.endPose, self.trajCfg)
121-
self.trajStartTime_s = Timer.getFPGATimestamp()
164+
self.curTraj = TrajectoryGenerator.generateTrajectory(startTrajPose, self.waypoints, endTrajPose, self.trajCfg)
122165

166+
167+
self.trajStartTime_s = Timer.getFPGATimestamp()
123168
return workingMap.base_grid
169+
170+
@staticmethod
171+
def _getDirection(from_tans:Translation2d, to_trans:Translation2d) -> Rotation2d:
172+
deltaX = (to_trans.X() - from_tans.X())
173+
deltaY = (to_trans.Y() - from_tans.Y())
174+
return Rotation2d(x=deltaX, y=deltaY)
175+

navigation/gradientDescentCostMap.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ def get_copy(self) -> 'GradientDescentCostMap':
4040
base_grid_copy = np.copy(self.base_grid)
4141
return GradientDescentCostMap(self.end_pose, base_grid_copy)
4242

43-
def add_obstacle(self, pose: Pose2d, cost: float, radius_m: float):
44-
y_peak = pose.Y()/GRID_SIZE_M
45-
x_peak = pose.X()/GRID_SIZE_M
43+
def add_obstacle(self, translate: Translation2d, cost: float, radius_m: float):
44+
y_peak = translate.Y()/GRID_SIZE_M
45+
x_peak = translate.X()/GRID_SIZE_M
4646
peak_radius = radius_m/GRID_SIZE_M
4747

4848
y_min = max(0,round(y_peak - peak_radius))

0 commit comments

Comments
 (0)