-
Notifications
You must be signed in to change notification settings - Fork 2
/
eye-animatronics.ino
313 lines (264 loc) · 7.83 KB
/
eye-animatronics.ino
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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/*
* Original ADNS3080 Code by: Simon Winder
* https://github.com/impressivemachines/Arduino
* https://www.youtube.com/user/robotbugs
* small changes by: Jan Neumann aka. Neumi
* https://github.com/Neumi
* https://www.youtube.com/user/NeumiElektronik
* Motion Follow Eye animatronics Created By Galor Nimrod 11/7/2018
* https://github.com/Nimrod-Galor/eye-animatronics
*
* Arduino sketch for eye animatronics
* Based on Optical Flow Sensor (ADNS3080)
* instructables: https://www.instructables.com/id/Eye-Animatronics/
* youtube: https://youtu.be/Ep9fWQiFmoM
*/
#include <SPI.h>
#include <Servo.h>
Servo srvRx; // pin 2 - right swing
Servo srvRy; // pin 3 - right tilt
Servo srvLx; // pin 7 - left swing
Servo srvLy; // pin 6 - left tilt
Servo srvLid; // pin 4 - eyelid tilt
Servo srvShut; // pin 5 - eyelid open/close
short loopDelay = 10;
int posX = 90; //swing
int posY = 90; // tilt
int posS = 90; // shut
short blinkMax = 55;
short blinkMin = 80;
short yMin = 70;
short yMax = 110;
short xMin = 60;
short xMax = 120;
short posYrev = 90;
unsigned long blinkTime = 2000;
unsigned long lastTrack = 0;
const int ledCount = 4; // the number of LEDs in the bar graph
int ledPins[] = {A7, A6, A5, A4}; // an array of pin numbers to which LEDs are attached
bool rest = true;
// these pins may be different on different boards
// this is for the uno
//#define PIN_SS 8
#define PIN_MISO 12
#define PIN_MOSI 11
#define PIN_SCK 13
#define PIN_MOUSECAM_RESET 9
#define PIN_MOUSECAM_CS 10
#define ADNS3080_PIXELS_X 30
#define ADNS3080_PIXELS_Y 30
#define ADNS3080_PRODUCT_ID 0x00
#define ADNS3080_REVISION_ID 0x01
#define ADNS3080_MOTION 0x02
#define ADNS3080_DELTA_X 0x03
#define ADNS3080_DELTA_Y 0x04
#define ADNS3080_SQUAL 0x05
#define ADNS3080_PIXEL_SUM 0x06
#define ADNS3080_MAXIMUM_PIXEL 0x07
#define ADNS3080_CONFIGURATION_BITS 0x0a
#define ADNS3080_EXTENDED_CONFIG 0x0b
#define ADNS3080_DATA_OUT_LOWER 0x0c
#define ADNS3080_DATA_OUT_UPPER 0x0d
#define ADNS3080_SHUTTER_LOWER 0x0e
#define ADNS3080_SHUTTER_UPPER 0x0f
#define ADNS3080_FRAME_PERIOD_LOWER 0x10
#define ADNS3080_FRAME_PERIOD_UPPER 0x11
#define ADNS3080_MOTION_CLEAR 0x12
#define ADNS3080_FRAME_CAPTURE 0x13
#define ADNS3080_SROM_ENABLE 0x14
#define ADNS3080_FRAME_PERIOD_MAX_BOUND_LOWER 0x19
#define ADNS3080_FRAME_PERIOD_MAX_BOUND_UPPER 0x1a
#define ADNS3080_FRAME_PERIOD_MIN_BOUND_LOWER 0x1b
#define ADNS3080_FRAME_PERIOD_MIN_BOUND_UPPER 0x1c
#define ADNS3080_SHUTTER_MAX_BOUND_LOWER 0x1e
#define ADNS3080_SHUTTER_MAX_BOUND_UPPER 0x1e
#define ADNS3080_SROM_ID 0x1f
#define ADNS3080_OBSERVATION 0x3d
#define ADNS3080_INVERSE_PRODUCT_ID 0x3f
#define ADNS3080_PIXEL_BURST 0x40
#define ADNS3080_MOTION_BURST 0x50
#define ADNS3080_SROM_LOAD 0x60
#define ADNS3080_PRODUCT_ID_VAL 0x17
void mousecam_reset()
{
digitalWrite(PIN_MOUSECAM_RESET,HIGH);
delay(1); // reset pulse >10us
digitalWrite(PIN_MOUSECAM_RESET,LOW);
delay(35); // 35ms from reset to functional
}
int mousecam_init()
{
pinMode(PIN_MOUSECAM_RESET,OUTPUT);
pinMode(PIN_MOUSECAM_CS,OUTPUT);
digitalWrite(PIN_MOUSECAM_CS,HIGH);
mousecam_reset();
int pid = mousecam_read_reg(ADNS3080_PRODUCT_ID);
if(pid != ADNS3080_PRODUCT_ID_VAL)
return -1;
// turn on sensitive mode
mousecam_write_reg(ADNS3080_CONFIGURATION_BITS, 0x19);
return 0;
}
void mousecam_write_reg(int reg, int val)
{
digitalWrite(PIN_MOUSECAM_CS, LOW);
SPI.transfer(reg | 0x80);
SPI.transfer(val);
digitalWrite(PIN_MOUSECAM_CS,HIGH);
delayMicroseconds(50);
}
int mousecam_read_reg(int reg)
{
digitalWrite(PIN_MOUSECAM_CS, LOW);
SPI.transfer(reg);
delayMicroseconds(75);
int ret = SPI.transfer(0xff);
digitalWrite(PIN_MOUSECAM_CS,HIGH);
delayMicroseconds(1);
return ret;
}
struct MD
{
byte motion;
char dx, dy;
byte squal;
word shutter;
byte max_pix;
};
void mousecam_read_motion(struct MD *p)
{
digitalWrite(PIN_MOUSECAM_CS, LOW);
SPI.transfer(ADNS3080_MOTION_BURST);
delayMicroseconds(75);
p->motion = SPI.transfer(0xff);
p->dx = SPI.transfer(0xff);
p->dy = SPI.transfer(0xff);
p->squal = SPI.transfer(0xff);
p->shutter = SPI.transfer(0xff)<<8;
p->shutter |= SPI.transfer(0xff);
p->max_pix = SPI.transfer(0xff);
digitalWrite(PIN_MOUSECAM_CS,HIGH);
delayMicroseconds(5);
}
void setup()
{
Serial.begin(38400);
Serial.println("Init");
//pinMode(PIN_SS,OUTPUT);
pinMode(PIN_MISO,INPUT);
pinMode(PIN_MOSI,OUTPUT);
pinMode(PIN_SCK,OUTPUT);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV32);
SPI.setDataMode(SPI_MODE3);
SPI.setBitOrder(MSBFIRST);
if(mousecam_init()==-1)
{
Serial.println("Mouse cam failed to init");
while(1);
}
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
pinMode(A6, OUTPUT);
pinMode(A7, OUTPUT);
srvRx.attach(2);
srvRy.attach(3);
srvLx.attach(7);
srvLy.attach(6);
srvLid.attach(4);
srvShut.attach(5);
srvRx.write(posX);
srvLx.write(posX);
srvRy.write(posY);
srvLy.write(posY);
srvLid.write(posS);
srvShut.write(blinkMax);
}
char asciiart(int k)
{
static char foo[] = "WX86*3I>!;~:,`. ";
return foo[k>>4];
}
byte frame[ADNS3080_PIXELS_X * ADNS3080_PIXELS_Y];
void loop()
{
delay(loopDelay);
//Blink
if(!rest){
blinkTime = blinkTime - loopDelay;
Serial.println(blinkTime);
if(blinkTime <= 100){// open
srvShut.write(blinkMin);
blinkTime = random(2, 12) * 500;
}else if(blinkTime <= 200){// close
srvShut.write(blinkMax);
}
}
//End Blink
int val = mousecam_read_reg(ADNS3080_PIXEL_SUM);
MD md;
mousecam_read_motion(&md);
// LED Bar
// this section produces a bar graph of the surface quality that can be used to focus the camera
int ledLevel = map(md.squal/4, 0, 12, 0, ledCount);
//Serial.print("led level: ");
//Serial.println(ledLevel);
// loop over the LED array:
for (int thisLed = 0; thisLed < ledCount; thisLed++) {
if (thisLed <= ledLevel) { // if the array element's index is less than ledLevel turn the pin for this element on:
digitalWrite(ledPins[thisLed], HIGH);
}else { // turn off all pins higher than the ledLevel:
digitalWrite(ledPins[thisLed], LOW);
}
}
// End LED Bar
if((int)md.dx != 0){
if(rest){
srvShut.write(blinkMin);
rest = false;
}
posX -= (int)md.dx;
if(posX > xMax){
posX = xMax;
}else if(posX < xMin){
posX = xMin;
}
srvRx.write(posX);
srvLx.write(posX);
lastTrack = millis();
Serial.print("X: ");
Serial.println(posX);
}
if((int)md.dy != 0){
if(rest){
srvShut.write(blinkMin);
rest = false;
}
posY -= (int)md.dy;
if(posY > yMax){
posY = yMax;
}else if(posY < yMin){
posY = yMin;
}
srvRy.write(posY);
posYrev = map(posY, yMin, yMax, yMax, yMin);
srvLy.write(posYrev);
srvLid.write(posYrev);
lastTrack = millis();
Serial.print("Y: ");
Serial.println(posY);
}
if( millis() - lastTrack >= 3000){
Serial.println("reset");
rest = true;
posX = 90; //swing
posY = 90; // tilt
posS = 90; // shut
srvRx.write(posX);
srvRy.write(posY);
srvLx.write(posX);
srvLy.write(posY);
srvLid.write(posS);
srvShut.write(blinkMax);
}
}