/
softserial_srvshield_command.ino
267 lines (221 loc) · 7.52 KB
/
softserial_srvshield_command.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
//Accepts commands to control two LED's and two servos over the serial port.
//This version uses the Softserial connection and Adafruit ServoShield
//(c) Simen Sommerfeldt, @sisomm, simen.sommerfeldt@gmail.com Licensed as CC-BY-SA
//#include <Servo.h>
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
//#include <SoftwareSerial.h>
const int bSize = 40; // Command Buffer size
const int ledPin0 = 12; // the LEDS that control the eyes
const int ledPin1 = 13;;
// The code assumes that you have servos connected at position 0 and 1 for the skull (pan/tilt),
// and position 4 for the jaw
const int jawServo = 4; // which servo controls the jaw
const int servo0Neutral = 350; // My calibrated values for neutral positions
const int servo1Neutral = 320;
const int jawOpen=270; // Values for the third servo that opens and closes the mouth
const int jawClosed=470;
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); // called this way, it uses the default address 0x40
const int nServos=16;
int lastServoPos[nServos]; // Array to remember the last servo positions
//SoftSerial to communicate with host over GPIO using pings 3,2
//SoftwareSerial mySerial(3, 2); // RX, TX
//Commands that are populated by the serialParser. Should be in an class
String theCommand;
String arg1;
String arg2;
String arg3;
int serialParser(void) {
//Reads and parses commands from the serial port
//The end of commmand token is '|', since the cr/lf is confusing on mac/raspi
char buffer[bSize]; // Serial buffer
char command[15]; // Arbitrary Value for command size
char data1[15]; // ditto for data size
char data2[15];
char data3[15];
int byteCount=0; // how many bytes that were read
int finished=0;
while(finished==0){
char c = Serial.read();
if(c>=0){
if(c=='|' || byteCount==(bSize-1)) {
finished=1;
buffer[byteCount]=0;
} else {
buffer[byteCount++]=c;
}
}
}
if (byteCount > 0) { // Really simple parsing
strcpy(command,strtok(buffer,","));
strcpy(data1,strtok(NULL,","));
strcpy(data2,strtok(NULL,","));
strcpy(data3,strtok(NULL,","));
theCommand=String(command);
arg1=String(data1);
arg2=String(data2);
arg3=String(data3);
//mySerial.flush();
}
memset(buffer, 0, sizeof(buffer)); // Clear contents of Buffer
return byteCount;
}
void setup() {
Serial.begin(9600);
// mySerial.begin(9600);
pinMode(ledPin0,OUTPUT);
pinMode(ledPin1,OUTPUT);
lastServoPos[0]=servo0Neutral;
lastServoPos[1]=servo1Neutral;
pwm.begin();
pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates
}
void cmd_blink_times(int times){ // blinks the "eyes" during "speech"
for(int i=1;i<=times;i++){
digitalWrite(ledPin0,HIGH);
digitalWrite(ledPin1,LOW);
delay(50);
digitalWrite(ledPin0,LOW);
digitalWrite(ledPin1,HIGH);
delay(50);
}
digitalWrite(ledPin1,LOW);
}
void cmd_blink(){ // default
cmd_blink_times(9);
}
void cmd_led(int ledPin, int toState){ // Set a led to a state
char state;
if(toState==1){ // Find out the desired state
state=HIGH;
}
else {
state=LOW;
}
if (ledPin>ledPin1)
Serial.println("Wrong LED pin argument");
else{
digitalWrite(ledPin,state);
}
}
void cmd_servoSlow(int servoPin, int servoStart, int servoStop){ // move a servo from one pos to another
lastServoPos[servoPin]=servoStop;
if(servoStop>servoStart){
for(int position=servoStart;position<servoStop;position+=2){
pwm.setPWM(servoPin, 0, position);
delay(20);
}
}
else {
for(int position=servoStart;position>servoStop;position-=2){
pwm.setPWM(servoPin, 0, position);
delay(20);
}
}
}
void cmd_jawPosition(int pos){ // moves the jaw in the skull to open (1) or shut(0)
int thePosition;
if(pos>0) {
thePosition=jawOpen;
} else {
thePosition=jawClosed;
}
pwm.setPWM(jawServo, 0, thePosition);
lastServoPos[jawServo]=thePosition;
}
void cmd_jawMotion(int times, int do_blink){ // moves the jaw in the skull
for(int i=1;i<=times;i++){
pwm.setPWM(jawServo, 0, jawOpen);
if(do_blink>0){
cmd_blink_times(3);
} else {
delay(300);
}
pwm.setPWM(jawServo, 0, jawClosed);
if(do_blink>0){
cmd_blink_times(3);
} else {
delay(300);
}
}
lastServoPos[jawServo]=jawClosed;
}
void cmd_Servo(int servoPin,int servoPos){ // Set a servo to a position
pwm.setPWM(servoPin, 0, servoPos);
lastServoPos[servoPin]=servoPos;
}
void cmd_servosMove(int servo0To,int servo1To,int delayTime){ // Move the servos to a new position, remembering the old
// This commmand is special and works only on pins 0 and 1 as a pair. Change if other pins
int increment0=(servo0To>lastServoPos[0]?+2:-2);
int increment1=(servo1To>lastServoPos[1]?+2:-2);
int repetitions=max(abs(servo0To-lastServoPos[0]),abs(servo1To-lastServoPos[1]))/2; // We move servos two steps at a time
for(int i=0;i<repetitions;i++){
if(abs(servo0To-lastServoPos[0])>2){ // Stop moving the servo that has reached the position
pwm.setPWM(0,0,lastServoPos[0]+=increment0);
}
if(abs(servo1To-lastServoPos[1])>2){
pwm.setPWM(1,0,lastServoPos[1]+=increment1);
}
delay(delayTime); // Allow the move to complete
}
}
void loop() {
//Implements a ping-pong protocol with the other end. All commands must be acknowledged
//TODO make the code more robust and check for valid parameters
if (serialParser() > 0) {
if(theCommand.equalsIgnoreCase("LEDS_ON")){
digitalWrite(ledPin0,HIGH);
digitalWrite(ledPin1,HIGH);
}
else if(theCommand.equalsIgnoreCase("LEDS_OFF")){
digitalWrite(ledPin0,LOW);
digitalWrite(ledPin1,LOW);
}
else if(theCommand.equalsIgnoreCase("LED")){
int ledPin=ledPin0+arg1.toInt();
int toState=arg2.toInt();
cmd_led(ledPin, toState);
}
else if(theCommand.equalsIgnoreCase("BLINK")){
cmd_blink();
}
else if(theCommand.equalsIgnoreCase("JAW_MOTION")){
int times=arg1.toInt();
int do_blink=arg2.toInt();
cmd_jawMotion(times,do_blink);
}
else if(theCommand.equalsIgnoreCase("JAW_POSITION")){
int pos=arg1.toInt();
cmd_jawPosition(pos);
}
else if(theCommand.equalsIgnoreCase("SERVO_SLOW")){
int servoPin=arg1.toInt();
int servoStart=arg2.toInt();
int servoStop=arg3.toInt();
cmd_servoSlow(servoPin, servoStart, servoStop);
}
else if(theCommand.equalsIgnoreCase("SERVOS_MOVE")){
int servo0To=arg1.toInt();
int servo1To=arg2.toInt();
int delayTime=arg3.toInt();
if (delayTime==0){
delayTime=3;
}
cmd_servosMove(servo0To,servo1To,delayTime);
}
else if(theCommand.equalsIgnoreCase("SERVO")){
int servoPin=arg1.toInt();
int servoPos=arg2.toInt();
cmd_Servo(servoPin,servoPos);
}
else if(theCommand.equalsIgnoreCase("SERVO_NEUTRAL")){
cmd_Servo(0,servo0Neutral);
cmd_Servo(1,servo1Neutral);
}
//these statements allow the host to understand that the command is finished
Serial.println(theCommand);
// mySerial.print(theCommand);
// mySerial.print('\n');
// mySerial.flush();
}
}