JeVois Tutorials  1.22
JeVois Smart Embedded Machine Vision Tutorials
 
Share this page:
Loading...
Searching...
No Matches
JeVoisRobotCar2.C
Go to the documentation of this file.
1// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2//
3// JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2017 by Laurent Itti, the University of Southern
4// California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5//
6// This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7// redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8// Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10// License for more details. You should have received a copy of the GNU General Public License along with this program;
11// if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12//
13// Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14// Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16
17// You need to install the Arduino PID Library by Brett Beauregard
18#include <PID_v1.h>
19#include <Servo.h>
20
21// Pins setup: Use RXLED(17) on Arduino pro micro 32u4 which does not have LED(13)
22#define LPWMPIN 3
23#define LIN1PIN 2
24#define LIN2PIN 21
25#define RPWMPIN 5
26#define RIN1PIN 20
27#define RIN2PIN 4
28#define LEDPIN 17
29#define PANPIN 9
30#define TILTPIN 10
31
32// Serial port to use for JeVois:
33// On chips with USB (e.g., 32u4), that usually is Serial1. On chips without USB, use Serial.
34#define SERIAL Serial1
35
36// Serial port for debugging (optional):
37#define DBGSERIAL Serial
38
39// Buffer for received serial port bytes:
40#define INLEN 128
41char instr[INLEN + 1];
42
43// Gain values to compensate for unbalanced motors: Do not exceed 655. Give a lower value to the motor that is faster.
44// E.g., if your car vires to the left when both motors are 100% forward, your right motor is a bit faster, so decrease
45// rightgain to compensate.
46long leftgain = 655;
47long rightgain = 655;
48
49// Desired target width in standardized JeVois coordinates (a value of 2000 would occupy the whole field of view):
50int TARGW = 300;
51
52// Create a PID for target width, and one for steering angle:
53double wset, win, wout, aset, ain, aout;
54PID wpid(&win, &wout, &wset, 1.0, 0.01, 0.01, DIRECT);
55PID apid(&ain, &aout, &aset, 0.5, 0.05, 0.02, DIRECT);
56
57// current speed and steering:
58double speed = 0;
59double steer = 0;
60int steerdelay = 0; // Delay in steering when re-aquiring a target to avoid steering jerk
61
62// Pan and tilt servos zero values and +/- angular range, in degrees:
63#define PANZERO 90
64#define PANRANGE 60
65#define TILTZERO 70
66#define TILTRANGE 40
67
68// Handoff between several targets:
69int currid = -1, currw = 0, currt = 0, nextid = -1, nextw = 0, nextt = 0, doneid = -1;
70#define HANDOFFW ((TARGW * 5) / 10)
71int t = 0;
72
73// ###################################################################################################
74// Simple PD servo controller
75class ServoPD
76{
77public:
78 ServoPD(long Kp, long Kd, long zero, long range, long scalebits = 8) :
79 itsKp(Kp), itsKd(Kd), itsPos(zero << scalebits),
80 itsPrevTarget(zero << scalebits), itsZero(zero << scalebits),
81 itsRange(range << scalebits), itsScaleBits(scalebits)
82 { }
83
84 void attach(int pin, int pos)
85 {
86 itsServo.attach(pin);
87 itsPos = (pos << itsScaleBits);
88 itsServo.write(pos);
89 }
90
91 long get() const
92 {
93 return (itsPos >> itsScaleBits);
94 }
95
96 void update(long targetpos)
97 {
98 targetpos <<= itsScaleBits;
99 long diff = itsKp * targetpos + itsKd * (targetpos - itsPrevTarget);
100 itsPos += (diff >> 16);
101 itsPos = constrain(itsPos, itsZero - itsRange, itsZero + itsRange);
102 itsServo.write(itsPos >> itsScaleBits);
103 itsPrevTarget = targetpos;
104 }
105
106 void reset(long targetpos)
107 {
108 targetpos <<= itsScaleBits;
109 itsPos = constrain(itsPos, itsZero - itsRange, itsZero + itsRange);
110 itsPrevTarget = targetpos;
111 }
112
113 long rawget()
114 {
115 return itsPos >> itsScaleBits;
116 }
117
118 void rawset(long rawval)
119 {
120 itsPos = rawval << itsScaleBits;
121 itsServo.write(rawval);
122 }
123
124 private:
125 Servo itsServo;
126 long itsKp, itsKd, itsPos, itsPrevTarget, itsZero, itsRange, itsScaleBits;
127};
128
129// Create one servo PD controler for camera pan and another for camera tilt:
130//ServoPD panservo(400, 200, PANZERO, PANRANGE);
133
134// ###################################################################################################
135void setup()
136{
137 SERIAL.setTimeout(50);
138 SERIAL.begin(115200);
139 SERIAL.setTimeout(50);
140 pinMode(LPWMPIN, OUTPUT);
141 pinMode(LIN1PIN, OUTPUT);
142 pinMode(LIN2PIN, OUTPUT);
143 pinMode(RPWMPIN, OUTPUT);
144 pinMode(RIN1PIN, OUTPUT);
145 pinMode(RIN2PIN, OUTPUT);
146 pinMode(LEDPIN, OUTPUT);
147 pinMode(PANPIN, OUTPUT);
148 pinMode(TILTPIN, OUTPUT);
149 motor(0, 0);
150
153
154 win = TARGW; wset = TARGW; wout = 0;
155 wpid.SetMode(AUTOMATIC);
156 wpid.SetSampleTime(10);
157 wpid.SetOutputLimits(-120, 120);
158
159 ain = 0; aset = 0; aout = 0;
160 apid.SetMode(AUTOMATIC);
161 apid.SetSampleTime(10);
162 apid.SetOutputLimits(-50, 50);
163}
164
165// ###################################################################################################
166void loop()
167{
168 byte len = SERIAL.readBytesUntil('\n', instr, INLEN);
169 instr[len] = 0;
170
171 char * tok = strtok(instr, " \r\n");
172 int state = 0; int id, targx, targy, targw, targh;
173
174 while (tok)
175 {
176 // State machine:
177 // 0: start parsing
178 // 1: N2 command, parse id
179 // 2: N2 command, parse targx
180 // 3: N2 command, parse targy
181 // 4: N2 command, parse targw
182 // 5: N2 command, parse targh
183 // 6: N2 command complete
184 // 1000: unknown command
185 switch (state)
186 {
187 case 0: if (strcmp(tok, "N2") == 0) state = 1; else state = 1000; break;
188 case 1: id = atoi(&tok[1]); state = 2; break; // ignore prefix
189 case 2: targx = atoi(tok); state = 3; break;
190 case 3: targy = atoi(tok); state = 4; break;
191 case 4: targw = atoi(tok); state = 5; break;
192 case 5: targh = atoi(tok); state = 6; break;
193 default: break; // Skip any additional tokens
194 }
195 tok = strtok(0, " \r\n");
196 }
197
198 // If a complete new N2 command was received, act:
199 if (state == 6)
200 {
201 // Update our steering delay after re-aquisition of previously lost target:
202 if (steerdelay) steerdelay -= 1;
203
204 // Decide whether we should track this target or another (larger) one:
205 int trackit = 0;
206
207 // If we are not tracking anything, track this one:
208 if (currid == -1)
209 { currid = id; currw = targw; currt = t; trackit = 1; } // New target, track it
210 else
211 {
212 if (id == doneid)
213 { trackit = 0; } // Ignore this one as we have already tracked it all the way
214 else if (id == currid)
215 { currw = targw; currt = t; trackit = 1; } // Keep tracking current target
216 else if (nextid == -1 && targw < currw)
217 { nextid = id; nextw = targw; nextt = t; trackit = 0; } // Next target detected, do not track it yet
218 else if (id == nextid && currw > HANDOFFW)
219 { doneid = currid; currid = nextid; nextid = -1; currw = targw; currt = t; trackit = 1; } // handoff
220 }
221
222 if (trackit)
223 {
224 // Actuate the pan/tilt head to track the target:
225 panservo.update(-targx);
226 tiltservo.update(targy);
227
228 // Move the car forward/backward to track the derired target width:
229 win = targw; wpid.Compute(); speed = wout;
230
231 // Steer the car to zero out the camera's pan angle:
232 ain = panservo.get() - PANZERO; apid.Compute(); steer = aout * (1.0 + fabs(speed) * 0.05);
233 }
234 }
235 else
236 {
237 // Slow down if we lost track:
238 speed *= 0.95;
239 steer *= 0.8;
240 steerdelay = 1;
241 }
242
243 // Actuate the motors:
244 if (steerdelay) steer = 0.0; // delay steering a bit after target re-acquisition to avoid steering jerk
246
247 // Invalidate previously detected targets that we have not seen in a while:
248 if (t - currt > 30) { currid = -1; nextid = -1; doneid = -1; }
249 if (t - nextt > 30) nextid = -1;
250
251 // Blink the LED on every loop:
252 digitalWrite(LEDPIN, t & 1);
253 t += 1;
254}
255
256// ###################################################################################################
257// Actuate the motors: Values in [-100 .. 100]; positive = forward, negative = backward, 0 = brake
258void motor(long left, long right)
259{
260 if (left > 100) left = 100; else if (left < -100) left = -100;
261 if (right > 100) right = 100; else if (right < -100) right = -100;
262
263 long motleft = (left * leftgain) >> 8;
264 long motright = (right * rightgain) >> 8;
265
266 if (motleft > 0) {
267 digitalWrite(LIN1PIN, LOW);
268 digitalWrite(LIN2PIN, HIGH);
269 analogWrite(LPWMPIN, motleft);
270 } else if (motleft < 0) {
271 digitalWrite(LIN1PIN, HIGH);
272 digitalWrite(LIN2PIN, LOW);
273 analogWrite(LPWMPIN, -motleft);
274 } else {
275 digitalWrite(LIN1PIN, LOW);
276 digitalWrite(LIN2PIN, LOW);
277 }
278
279 if (motright > 0) {
280 digitalWrite(RIN1PIN, LOW);
281 digitalWrite(RIN2PIN, HIGH);
282 analogWrite(RPWMPIN, motright);
283 } else if (motright < 0) {
284 digitalWrite(RIN1PIN, HIGH);
285 digitalWrite(RIN2PIN, LOW);
286 analogWrite(RPWMPIN, -motright);
287 } else {
288 digitalWrite(RIN1PIN, LOW);
289 digitalWrite(RIN2PIN, LOW);
290 }
291}
292
#define TILTPIN
#define RIN1PIN
#define TILTZERO
#define RIN2PIN
int currt
#define HANDOFFW
#define LEDPIN
int nextt
int currid
void setup()
long rightgain
#define INLEN
long leftgain
int nextid
int TARGW
void motor(long left, long right)
ServoPD tiltservo(300, 100, TILTZERO, TILTRANGE)
double speed
#define PANRANGE
#define TILTRANGE
double wset
ServoPD panservo(100, 50, PANZERO, PANRANGE)
double wout
#define LIN1PIN
#define PANPIN
int currw
#define SERIAL
double ain
char instr[INLEN+1]
int t
int steerdelay
#define LIN2PIN
double win
int nextw
#define LPWMPIN
#define PANZERO
double aset
int doneid
#define RPWMPIN
double aout
double steer
void loop()
void update(long targetpos)
long rawget()
void attach(int pin, int pos)
long get() const
void reset(long targetpos)
ServoPD(long Kp, long Kd, long zero, long range, long scalebits=8)
void rawset(long rawval)