-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpid.py
executable file
·102 lines (84 loc) · 3.66 KB
/
pid.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import numpy as np
import cv2
import sys
import time
import matplotlib.pyplot as plt
from math import sqrt
# 2.7g ball: kp: 1617.05, ki: 1848.74, kd: 231.09
class PIDController:
def __init__(self, target_pos):
self.target_pos = target_pos
self.Kp = 4201.68 #2563.03
self.Ki = 3571.43#2878.15
self.Kd = 252.10#338.15
self.bias = 0.0 #static
self.last_error = 0.0
self.Iterm = 0.0
self.frame_counter = 0.0
return
def reset(self):
self.Pterm = 0.0
self.Iterm = 0.0
self.Dterm = 0.0
self.last_error = 0.0
self.output = 0.0
return
def get_fan_rpm(self, image_frame=None):
threshold = 1000.0
self.frame_counter += 1
temp = self.detect_ball(image_frame)
vertical_ball_position = (483-(temp + 1))/483
print(vertical_ball_position)
error = self.target_pos - vertical_ball_position
delta_error = error - self.last_error
delta_time = 1/60 #60fps
self.Pterm = self.Kp * error
self.Iterm += error * delta_time
if (self.Iterm < -threshold):
self.Iterm = -threshold
elif(self.Iterm > threshold):
self.Iterm = threshold
self.Dterm = delta_error / delta_time
# Remember last time and last error for next calculation
self.last_error = error
output = self.Pterm + (self.Ki * self.Iterm) + (self.Kd * self.Dterm)
#print('current error: ', error)
#print('vertical position: ', vertical_ball_position)
#print('pid: ', output)
#print('P: ', self.Pterm, 'I: ', self.Iterm, 'D: ', self.Dterm)
print(output)
return output, vertical_ball_position
def detect_ball(self, frame):
bgr_color = 75, 65, 160
color_threshold = 50
hsv_color = cv2.cvtColor( np.uint8([[bgr_color]] ), cv2.COLOR_BGR2HSV)[0][0]
HSV_lower = np.array([hsv_color[0] - color_threshold, hsv_color[1] - color_threshold, hsv_color[2] - color_threshold])
HSV_upper = np.array([hsv_color[0] + color_threshold, hsv_color[1] + color_threshold, hsv_color[2] + color_threshold])
x, y, radius = -1, -1, -1
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv_frame, HSV_lower, HSV_upper)
mask = cv2.erode(mask, None, iterations= 1)#5
mask = cv2.dilate(mask, None, iterations= 5)#multiple contours
im2, contours, hierarchy = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
center = (-1, -1)
# only proceed if at least one contour was found
if len(contours) > 0:
# find the largest contour in the mask, then use
# it to compute the minimum enclosing circle and
# centroid
c = max(contours, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
#print(radius)
#print (x)
M = cv2.moments(mask)
horizontal = int(M["m10"] / M["m00"])
vertical = int(M["m01"] / M["m00"])
center = (horizontal, vertical)
#print(center)
# check that the radius is larger than some threshold
if radius > 0:
#outline ball
cv2.circle(frame, (int(x), int(y)), int(radius), (255, 0, 0), 2)
#show ball center
cv2.circle(frame, center, 3, (0, 255, 0), -1)
return center[1]