ShaunDark80
Well-Known Member
Hi all
I've been playing around a bit, and this is what I've added to the xl97's code;
Here's where I got to with my previous version;
I've now added the timer using millis (lines 55, 56, 57, 101, 130, 131 & 132). This only keeps the state as active for 5 seconds (line 56) before going back to idle.
I've also added an LED to pin 4, which lights up when the state is set to active - This will give me visual confirmation when wearing the helmet that it's ready to open (lines 20, 99 and 113).
Finally (for now), I detached the servo after each rotation (lines 60, 76, 77, 78, 209, 210, 211, 212, 220, 221, 222 & 223). I was getting a lot of jitter from the servo (apparently a common problem) which was not only causing an annoying noise, but was also causing the servo to heat up, and was also giving false readings to the accelerometer. Detaching the servo solved this. Once I have installed everything in the helmet, I will decide if I need to employ the xrobots servo braking system - https://www.youtube.com/watch?v=izr0zu-_Lyo
I'm happy for now - Though I'm sure someone smarter will offer a far better solution.
I've been playing around a bit, and this is what I've added to the xl97's code;
Code:
// IronMan Helmet: eye blink sequence_v1.0
// created by: xl97
//import servo lib
#include <Servo.h>
//servo object names
Servo myservo; // create servo object to control a servo
//Servo myservo1;
const int buttonPin = 2; // the pin that the pushbutton is attached to
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
// led control pins (need to be PWM enabled pins for fading)
const int leftEye = 6; // the number of the left eye/pcb LEDs
const int rightEye = 3; // the number of the right eye/pcb LEDs
const int readyLED = 4; // the number of the Activate state LED
unsigned long fadeDelay = .5; //speed of the eye 'fade'
unsigned long callDelay = 700; //length to wait to start eye flicker after face plate comes down
unsigned long blinkSpeed = 100; //delay between init blink on/off
unsigned long currentPWM = 0;
boolean isOpen = true;
#define S_IDLE 1
#define S_ACTIVATE 12
#define S_LEDON 2
#define S_WAITON 3
#define S_LEDOFF 4
#define S_WAITOFF 5
#define S_INITON 6
#define S_INITWAIT 7
#define S_BLINKON 8
#define S_SERVOUP 9
#define S_SERVODOWN 10
#define S_SERVOWAIT 11
/*
This short program reads data from the ADXL335 axis accelerometer
*/
const int groundpin = 18; // analog input pin 4 -- ground
const int powerpin = 19; // analog input pin 5 -- voltage
const int zpin = A3; // z-axis of the accelerometer
const int ypin = A2; // y-axis
const int xpin = A1; // x-axis
int tiltdown = 460;
int tiltup = 560;
const String XHEADER = "X: ";
const String YHEADER = "Y: ";
const String ZHEADER = "Z: ";
const String TAB = "\t";
long previousMillis = 0; // will store last time the ACTIVATE state was triggered.
long interval = 5000; // the time spent in the active state waiting for tilt up before returning to idle.
long currentMillis = 0; // will store the current time.
int faceUP = 0; // servo up position
int faceDOWN = 180; // servo down position
int servoDelay = 400; // delay required for servo to complete rotation before being disconnected.
//FSM init vars
static int state = S_IDLE; // initial state is 1, the "idle" state.
static unsigned long lastTime; // To store the "current" time in for delays.
void setup() {
// Set up serial port
Serial.begin(9600);
//start it off
//state = S_BLINKON;
Serial.print("INTIT STATE: ");
Serial.println(state);
myservo.attach(9); // attaches the servo on pin 9 to the servo object
myservo.write(faceUP); // starts the servo in the Up position
delay(servoDelay); // gives time for servo to complete rotation
myservo.detach(); // detaches the servo to reduce jitter
//myservo1.attach(10); // attaches the servo on pin 10 to the servo object
pinMode(buttonPin, INPUT); // initialize the button pin as a input
digitalWrite(buttonPin, HIGH); //use interal pull up resistors
// initialize the serial communications:
Serial.begin(9600);
// Power and ground the necessary pins. Providing power to both
// the analog and digital pins allow me to just use the breakout
// board and not have to use the normal 5V and GND pins
pinMode(groundpin, OUTPUT);
pinMode(powerpin, OUTPUT);
digitalWrite(groundpin, LOW);
digitalWrite(powerpin, HIGH);
}
void loop() {
switch(state)
{
case S_IDLE:
analogWrite(readyLED, 0);
if (analogRead(xpin) < tiltdown) {
previousMillis = millis(); // record the time the state changed
Serial.print("WAITING FOR TILTUP");
state = S_ACTIVATE;
}
else{
Serial.print(XHEADER + analogRead(xpin) + " IDLE");
Serial.println();
delay(200);
}
break;
case S_ACTIVATE:
analogWrite(readyLED, 255);
currentMillis = millis(); // determine the current time
if (analogRead(xpin) > tiltup) {
if(isOpen == true){
Serial.print("CLOSING FACE PLATE: ");
Serial.println(isOpen, DEC);
state = S_SERVODOWN;
}
else{
Serial.print("OPENING FACE PLATE: ");
Serial.println(isOpen, DEC);
//state = S_SERVOUP;
state = S_LEDOFF;
}
isOpen = !isOpen;
}
else{
if(currentMillis - previousMillis > interval) {
Serial.print("Timed Out");
state = S_IDLE;
}
Serial.print(XHEADER + analogRead(xpin) + " ACTIV");
Serial.println();
delay(200);
}
break;
case S_BLINKON:
Serial.println("init blink.........");
//do blink routine here
//one blink
analogWrite(leftEye, 155);
analogWrite(rightEye, 155);
delay(blinkSpeed);
analogWrite(leftEye, 0);
analogWrite(rightEye, 0);
delay(10);
//two blinks
/*
analogWrite(leftEye, 155);
analogWrite(rightEye, 155);
delay(blinkSpeed);
analogWrite(leftEye, 0);
analogWrite(rightEye, 0);
delay(10);
*/
state = S_LEDON;
break;
case S_LEDON:
Serial.println("increase........");
lastTime = millis(); // Remember the current time
analogWrite(leftEye, currentPWM);
analogWrite(rightEye, currentPWM);
state = S_WAITON; // Move to the next state
break;
case S_WAITON:
// If one second has passed, then move on to the next state.
if(millis() > (lastTime + fadeDelay)){
if(currentPWM < 255){
currentPWM += 5;
state = S_LEDON;
}
else{
Serial.println("@ 255 done........");
state = S_IDLE;
//state = S_LEDOFF; //no auto turn off.. set to idle state
}
}
break;
case S_LEDOFF:
Serial.println("........decrease");
lastTime = millis(); // Remember the current time
analogWrite(leftEye, currentPWM);
analogWrite(rightEye, currentPWM);
state = S_WAITOFF;
break;
case S_WAITOFF:
// If one second has passed, then move on to the next state.
if(millis() > (lastTime + fadeDelay)){
if(currentPWM > 0){ //change 0 to higher number to init face 'up' function sooner.
currentPWM -= 5;
state = S_LEDOFF;
}
else{
Serial.println("@ 0 done........");
state = S_SERVOUP; //leds off..raise faceplate
}
}
break;
case S_SERVOUP:
Serial.println("servo up.........");
myservo.attach(9); // attaches the servo on pin 9 to the servo object
myservo.write(faceUP);
delay(servoDelay); // gives time for servo to complete rotation
myservo.detach(); // detaches the servo to reduce jitter
//myservo1.write(100);
state = S_IDLE;
break;
case S_SERVODOWN:
lastTime = millis(); // Remember the current time
Serial.println("servo down.........");
myservo.attach(9); // attaches the servo on pin 9 to the servo object
myservo.write(faceDOWN);
delay(servoDelay); // gives time for servo to complete rotation
myservo.detach(); // detaches the servo to reduce jitter
//myservo1.write(0);
state = S_SERVOWAIT;
break;
case S_SERVOWAIT:
// If enough time has passed, call the eye flicker routine
if(millis() > (lastTime + callDelay)){
Serial.println("start eye flicker routine");
state = S_BLINKON;
}
else{
Serial.println("waiting........");
}
break;
default:
state = S_IDLE;
break;
}
}
Here's where I got to with my previous version;
I used pretty much the same circuit he described in http://www.therpf.com/f78/iron-man-m...ml#post2936077 but as I'm using just one servo, I commented out all references to "myservo1" and both increased and reversed the values for "myservo".
As I didn't want my faceplate opening every time I looked up, I set the idle state to wait for me to look down first. This then triggers the activate state which waits for me to look up before either opening or closing the faceplate. It would be nice if this could time out so that I'd have to look down, then up within a few seconds to trigger the event, but I've not figured that bit out yet.
The amount I have to tilt my head can be adjusted with the "tilitdown" and "tiltup" values on lines 48 and 49.
I've now added the timer using millis (lines 55, 56, 57, 101, 130, 131 & 132). This only keeps the state as active for 5 seconds (line 56) before going back to idle.
I've also added an LED to pin 4, which lights up when the state is set to active - This will give me visual confirmation when wearing the helmet that it's ready to open (lines 20, 99 and 113).
Finally (for now), I detached the servo after each rotation (lines 60, 76, 77, 78, 209, 210, 211, 212, 220, 221, 222 & 223). I was getting a lot of jitter from the servo (apparently a common problem) which was not only causing an annoying noise, but was also causing the servo to heat up, and was also giving false readings to the accelerometer. Detaching the servo solved this. Once I have installed everything in the helmet, I will decide if I need to employ the xrobots servo braking system - https://www.youtube.com/watch?v=izr0zu-_Lyo
I'm happy for now - Though I'm sure someone smarter will offer a far better solution.
Last edited: