-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPixyViSy.cpp
235 lines (205 loc) · 6.22 KB
/
PixyViSy.cpp
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#include <PixyViSy.h>
#include <math.h>
const int16_t h_center = (PIXY_MAX_X + 1) / 2;
const int16_t v_center = (PIXY_MAX_Y + 1) / 2;
const uint8_t def_goal_height = 12;
const uint8_t def_orange_ball_size = 7;
const uint8_t def_IR_ball_size = 8;
inline uint16_t block_area(Block& block)
{
return block.height * block.width;
}
PixyViSy::PixyViSy(uint16_t pixel_Fx, uint16_t pixel_Fy)
{
pixy.init();
Fyp = pixel_Fy;
Fxp = pixel_Fx;
goal_height = def_goal_height;
ball_size = def_IR_ball_size;
ball_sig = goal_sig = 0;
min_ball_area = min_goal_area = 0;
setDefValues();
}
void PixyViSy::printParams()
{
Serial.print("Fyp: "); Serial.println(Fyp);
Serial.print("Fxp: "); Serial.println(Fxp);
Serial.print("goal_sig: "); Serial.println(goal_sig);
Serial.print("goal_height: "); Serial.println(goal_height);
Serial.print("goal_angle: "); Serial.println(goal_angle);
Serial.print("min_goal_area: "); Serial.println(min_goal_area);
Serial.print("ball_sig: "); Serial.println(ball_sig);
Serial.print("ball_size: "); Serial.println(ball_size);
Serial.print("min_ball_area: "); Serial.println(min_ball_area);
Serial.print("teammate_sig: "); Serial.println(team_sig);
Serial.print("teammate_angle: ");Serial.println(team_angle);
}
void PixyViSy::update(uint8_t flag)
{
setDefValues();
blocks_count = pixy.getBlocks();
if (blocks_count == 0) {
return;
}
if (flag & PIXYVISY_GOAL) {
processGoal(flag & PIXYVISY_ANGG);
}
if (flag & PIXYVISY_BALL) {
processBall();
}
if (flag & PIXYVISY_TEAM) {
processTeam();
}
}
void PixyViSy::processBall()
{
uint16_t ball_i;
if (findNMax(ball_sig, 1, &ball_i, min_ball_area) == 0) {
return;
}
Block& ball = pixy.blocks[ball_i];
/* prevent covered ball (e.g. by robot) */
if (ball.width > ball.height) {
ball_dist = getRealZ(ball_size, ball.width, 'X');
} else {
ball_dist = getRealZ(ball_size, ball.height, 'Y');
}
ball_angle = getAngleH(ball.x);
}
uint16_t PixyViSy::valueGoalBlock(Block& block, int16_t Z)
{
uint16_t value = 0;
if (block.x > h_center) {
value = 100 * block.width / (block.x - h_center);
} else if (block.x < h_center) {
value = 100 * block.width / (h_center - block.x);
} else {
value = 100 * block.width * 2;
}
if (getRealX(block.width, Z) > ball_size) {
value *= 4;
}
return value;
}
void PixyViSy::processGoal(bool set_angle)
{
uint16_t max[3];
uint8_t goal_blocks_count = findNMax(goal_sig, 3, max, min_goal_area);
if (goal_blocks_count == 0) {
return;
}
/* counting goal_pix_height */
for (uint8_t i = 0; i < goal_blocks_count; i++) {
Block& block = pixy.blocks[max[i]];
goal_pix_height += block.height;
}
// counting distance and suggesting action
goal_pix_height /= goal_blocks_count; // average value
goal_dist = getRealZ(goal_height, goal_pix_height, 'Y');
// x coordinates of ball's borders
// (just prediction where it should be after kick)
int16_t ball_left = getPixX(-ball_size/2, goal_dist);
int16_t ball_right = getPixX(ball_size/2, goal_dist);
Block& best = pixy.blocks[max[0]];
uint16_t best_val = valueGoalBlock(best, goal_dist);
for (uint8_t i = 0; i < goal_blocks_count; i++) {
Block& block = pixy.blocks[max[i]];
// x coordinates of goal_block's borders
int16_t goal_right = block.x + block.width / 2;
int16_t goal_left = block.x - block.width / 2;
if (goal_left <= ball_left && goal_right >= ball_right) {
goal_action = 'K'; // as "Kick"
if (set_angle) {
goal_angle = getAngleH(block.x);
}
return;
}
uint16_t block_val = valueGoalBlock(block, goal_dist);
if (block_val > best_val) {
best = block;
best_val = block_val;
}
}
if (best.x < h_center) {
goal_action = 'L'; // as "move Left"
} else {
goal_action = 'R'; // as "move Right"
}
if (set_angle) {
goal_angle = getAngleH(best.x);
}
}
void PixyViSy::processTeam()
{
uint16_t team_i;
if (findNMax(team_sig, 1, &team_i, min_team_area) == 0) {
return;
}
Block& team = pixy.blocks[team_i];
team_dist = getRealZ(team_size, team.height, 'Y');
team_angle = getAngleH(team.x);
team_dx = getRealX(team.x, team_dist);
}
void PixyViSy::setDefValues()
{
blocks_count = 0;
goal_pix_height = 0;
goal_action = 'N'; // as "Nothing"
goal_dist = PIXYVISY_NOBLOCK;
goal_angle = 0;
ball_dist = PIXYVISY_NOBLOCK;
ball_angle = 0;
team_dist = PIXYVISY_NOBLOCK;
team_angle = 0;
team_dx = 0;
}
uint16_t PixyViSy::findNMax(uint8_t sig, uint16_t n, uint16_t *out_blocks,
uint16_t thresh)
{
uint16_t i, cnt;
// pixy sends blocks in order by size from the biggest
for (i = 0, cnt = 0; i < blocks_count && cnt < n; i++) {
if (pixy.blocks[i].signature == sig) {
if (block_area(pixy.blocks[i]) < thresh) {
break;
}
out_blocks[cnt] = i;
cnt++;
}
}
return cnt;
}
inline int16_t PixyViSy::getRealX(int16_t Xp, int16_t Z)
{
return (Xp - h_center) * Z / Fxp;
}
inline int16_t PixyViSy::getRealY(int16_t Yp, int16_t Z)
{
return (v_center - Yp) * Z / Fyp;
}
inline int16_t PixyViSy::getRealZ(int16_t D, int16_t Dp, char axis)
{
if (axis == 'x' || axis == 'X' || axis == 'h' || axis == 'H') {
return Fxp * D / Dp;
} else if (axis == 'y' || axis == 'Y' || axis == 'v' || axis == 'V') {
return Fyp * D / Dp;
}
}
inline int16_t PixyViSy::getPixX(int16_t X, int16_t Z)
{
return h_center + X * Fxp / Z;
}
inline int16_t PixyViSy::getPixY(int16_t Y, int16_t Z)
{
return v_center - Y * Fyp / Z;
}
/* Note that atan is not as slow as other goniometric functions */
inline int16_t PixyViSy::getAngleH(int16_t Xp)
{
return RAD_TO_DEG * atan2(Xp - h_center, Fxp);
}
inline int16_t PixyViSy::getAngleV(int16_t Yp)
{
return RAD_TO_DEG * atan2(Yp - h_center, Fyp);
}
/* vim: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab : */