forked from augcog/ROAR
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
aruco agent done, now need to go to lab and tune it
- Loading branch information
1 parent
e141e9e
commit 69b8509
Showing
7 changed files
with
294 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
from ROAR.control_module.controller import Controller | ||
from ROAR.utilities_module.data_structures_models import Transform | ||
from ROAR.utilities_module.vehicle_models import Vehicle | ||
from ROAR.utilities_module.vehicle_models import VehicleControl | ||
from collections import deque | ||
import numpy as np | ||
|
||
|
||
class SimplePIDController(Controller): | ||
def __init__(self, agent, distance_to_keep=0.5, center_x=-0.2, **kwargs): | ||
super().__init__(agent, **kwargs) | ||
|
||
self.yaw_error_buffer = deque(maxlen=20) | ||
|
||
self.lat_error_queue = deque(maxlen=20) # this is how much error you want to accumulate | ||
self.long_error_queue = deque(maxlen=20) # this is how much error you want to accumulate | ||
self.center_x = center_x | ||
self.lat_kp = 1 # this is how much you want to steer | ||
self.lat_kd = 0 # this is how much you want to resist change | ||
self.lat_ki = 0.005 # this is the correction on past error | ||
self.x_error_weight = 1 | ||
self.yaw_error_weight = 0.9 | ||
|
||
self.distance_to_keep = distance_to_keep | ||
self.max_throttle = 0.2 | ||
self.lon_kp = 0.16 # this is how much you want to steer | ||
self.lon_kd = 0.1 # this is how much you want to resist change | ||
self.lon_ki = 0.005 # this is the correction on past error | ||
|
||
def run_in_series(self, next_waypoint=None, **kwargs) -> VehicleControl: | ||
control = VehicleControl() | ||
self.lateral_pid_control(next_waypoint=next_waypoint, control=control) | ||
self.long_pid_control(next_waypoint=next_waypoint, control=control) | ||
return control | ||
|
||
def lateral_pid_control(self, next_waypoint: Transform, control: VehicleControl): | ||
x_error = (next_waypoint.location.x - self.center_x) / next_waypoint.location.z | ||
yaw_error = np.deg2rad(next_waypoint.rotation.yaw - 0) | ||
self.yaw_error_buffer.append(yaw_error) | ||
error = x_error * self.x_error_weight + np.average(self.yaw_error_buffer) * self.yaw_error_weight | ||
print(round(x_error, 3), round(yaw_error, 3), round(error, 3)) | ||
|
||
error_dt = 0 if len(self.lat_error_queue) == 0 else error - self.lat_error_queue[-1] | ||
self.lat_error_queue.append(error) | ||
error_it = sum(self.lat_error_queue) | ||
|
||
e_p = self.lat_kp * error | ||
e_d = self.lat_kd * error_dt | ||
e_i = self.lat_ki * error_it | ||
lat_control = np.clip((e_p + e_d + e_i), -1, 1) | ||
control.steering = lat_control | ||
|
||
def long_pid_control(self, next_waypoint: Transform, control: VehicleControl): | ||
dist_to_car = next_waypoint.location.z | ||
if dist_to_car < self.distance_to_keep: | ||
control.brake = True | ||
control.throttle = 0 | ||
else: | ||
error = dist_to_car - self.distance_to_keep | ||
error_dt = 0 if len(self.long_error_queue) == 0 else error - self.long_error_queue[-1] | ||
self.long_error_queue.append(error) | ||
error_it = sum(self.long_error_queue) | ||
e_p = self.lon_kp * error | ||
e_d = self.lon_kd * error_dt | ||
e_i = self.lon_ki * error_it | ||
long_control = np.clip(e_p + e_d + e_i, -1, self.max_throttle) | ||
control.throttle = long_control |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
from ROAR.perception_module.detector import Detector | ||
from ROAR.agent_module.agent import Agent | ||
import cv2 | ||
import cv2.aruco as aruco | ||
import numpy as np | ||
import math | ||
from ROAR.utilities_module.data_structures_models import Rotation | ||
|
||
|
||
class ArucoDetector(Detector): | ||
def __init__(self, aruco_id: int, agent: Agent, aruco_dict_key='DICT_5X5_250', marker_length=0.1, **kwargs): | ||
super().__init__(agent, **kwargs) | ||
self.aruco_id: int = aruco_id | ||
self.aruco_dict = aruco.Dictionary_get(getattr(aruco, aruco_dict_key)) | ||
self.aruco_param = aruco.DetectorParameters_create() | ||
self.marker_length = marker_length # in meters | ||
|
||
def run_in_series(self, **kwargs): | ||
if self.agent.front_rgb_camera.data is not None: | ||
try: | ||
img = self.agent.front_rgb_camera.data.copy() | ||
result: dict = self.findArucoMarkers(img) # {marker id -> bbox} | ||
if result and self.aruco_id in result: | ||
bbox = result[self.aruco_id] | ||
rvec, tvec, markerPoints = cv2.aruco.estimatePoseSingleMarkers(bbox, self.marker_length, | ||
self.agent.front_rgb_camera.intrinsics_matrix, | ||
self.agent.front_rgb_camera.distortion_coefficient) | ||
cv2.aruco.drawAxis(img, | ||
self.agent.front_rgb_camera.intrinsics_matrix, | ||
self.agent.front_rgb_camera.distortion_coefficient, | ||
rvec, | ||
tvec, | ||
self.marker_length) | ||
R = np.array(cv2.Rodrigues(rvec)[0]) | ||
T = tvec | ||
P = self.constructTransformation(R, T) | ||
return P | ||
except Exception as e: | ||
return None | ||
return None | ||
|
||
def findArucoMarkers(self, img): | ||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) | ||
bboxs, ids, rejected = aruco.detectMarkers(gray, self.aruco_dict, parameters=self.aruco_param, | ||
cameraMatrix=self.agent.front_rgb_camera.intrinsics_matrix, | ||
distCoeff=self.agent.front_rgb_camera.distortion_coefficient) | ||
log = dict() | ||
if ids is None: | ||
return log | ||
else: | ||
for i in ids: | ||
log[i[0]] = bboxs | ||
return log | ||
|
||
def save(self, **kwargs): | ||
pass | ||
|
||
# Checks if a matrix is a valid rotation matrix. | ||
def isRotationMatrix(self, R): | ||
Rt = np.transpose(R) | ||
shouldBeIdentity = np.dot(Rt, R) | ||
I = np.identity(3, dtype=R.dtype) | ||
n = np.linalg.norm(I - shouldBeIdentity) | ||
return n < 1e-6 | ||
|
||
# Calculates rotation matrix to euler angles | ||
# The result is the same as MATLAB except the order | ||
# of the euler angles ( x and z are swapped ). | ||
def rotationMatrixToEulerAngles(self, R) -> Rotation: | ||
assert (self.isRotationMatrix(R)) | ||
|
||
sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0]) | ||
|
||
singular = sy < 1e-6 | ||
|
||
if not singular: | ||
x = math.atan2(R[2, 1], R[2, 2]) | ||
y = math.atan2(-R[2, 0], sy) | ||
z = math.atan2(R[1, 0], R[0, 0]) | ||
else: | ||
x = math.atan2(-R[1, 2], R[1, 1]) | ||
y = math.atan2(-R[2, 0], sy) | ||
z = 0 | ||
|
||
euler_angles_deg = np.rad2deg(np.array([x, y, z])) | ||
|
||
rotation = Rotation( | ||
roll=euler_angles_deg[2], | ||
pitch=euler_angles_deg[0], | ||
yaw=euler_angles_deg[1], | ||
) | ||
return rotation | ||
|
||
@staticmethod | ||
def constructTransformation(R, T): | ||
transformation_matrix = np.zeros([4, 4]) | ||
transformation_matrix[0:3, 0:3] = R | ||
transformation_matrix[0:3, 3] = T | ||
transformation_matrix[3, 3] = 1 | ||
return transformation_matrix |
Oops, something went wrong.