Iron man motorised faceplate electronics tutorial!!!

I don't know if that kind of motor would have enough torque. It all depends on the weight and friction of what you are trying to slide. you also have to think about the return mechanism. You'd have to have a push as well as a pull. I'd suggest looking in to a small stepper motor (for better control over the movement), which drives some sort of spool that has some wound up high-tensile material (like strong fishing line). The fishing line would come off in two strands (the top end and the bottom end), then you could route that line through a couple of pieces of tubing, one for the push and the other for the pull.

Another option would be to look at small solenoids or other types of linear actuators.

Sorry I don't have specific parts or whatnot, but some quick googling should give you examples of solenoids, stepper motors, etc. I'm sure something will pop up that will work.

Thanks for the advice!

Funnily enough I've been doing a bit of research and came across stepper motors, so I'm glad to hear I might be heading along the right lines!

I'm not familiar with solenoids so I'll check those out.

Thanks again!

Gav
 
Also, I wonder if anyone has tried bending the circuit board, possibly with heat before soldering the components, to get a better fit in the curved interior of the helmet?

Would something like that be possible, do you think..?
 
can someone help?

hey guys i need your help.
i use a hs-125mg servo (only one!) so i want to remove all stuff which are for a second servo.. also i have a other servo mechanism. so the led is fading when faceplate is open? how can i change this?

Code:
#include <Servo.h>
//servo 1
Servo myservo;
Servo myservo1;
int val; // variable for reading the pin status
int val2; // variable for reading the delayed/debounced status
int buttonState;
int pos = 0;
int pos1 = 0;
int servostatus = 0;
int switchPin =2; // Switch connected to digital pin 2
int ledPin = 5;
int ledPin2 = 18;
void setup() // run once, when the sketch starts
{
//servo 1

myservo.attach(9);
myservo1.attach(10);
pinMode(switchPin, INPUT);
pinMode(ledPin, OUTPUT);
buttonState = digitalRead(switchPin);
myservo.write(90);
myservo1.write(90);
pinMode(ledPin2, OUTPUT);
}

void loop() // run over and over again

//servo 1
{
val = digitalRead(switchPin); // read input value and store it in val
delay(10); // 10 milliseconds is a good amount of time
val2 = digitalRead(switchPin); // read the input again to check for bounces
if (val == val2) { // make sure we got 2 consistant readings!
if (val != buttonState) { // the button state has changed!
if (val == LOW) { // check if the button is pressed
if (servostatus == 0) {
servostatus = 1;

digitalWrite(ledPin, LOW);
delay(15);
digitalWrite(ledPin2, LOW);

myservo.write(40); // servo helmet
myservo1.write(180); // servo faceplate

} else {
servostatus = 0;

myservo.write(90);
myservo1.write(90);
delay(1000);
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(100);
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(100);


// fading
for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) {
// sets the value (range from 0 to 255):
analogWrite(ledPin, fadeValue);
delay(30);


}

}
}
}
buttonState = val; // save the new state in our variable
}
}
 
Hi, i'm still debating on whether i should buy the arduino uno or nano. Can I use the nano for testing the same as the uno? So I can test and edit the code, and when I'm happy with it, build it into my helmet.
 
Excuse me,But ,Will the code be the same if the Mini pro is used with an accelerometer?


there is no accelerometer code in any of the sketches (code) posted in this tutorial...

I would image it wouldnt be too hard to add it in though,

- - - Updated - - -

Hi, i'm still debating on whether i should buy the arduino uno or nano. Can I use the nano for testing the same as the uno? So I can test and edit the code, and when I'm happy with it, build it into my helmet.


the nano only have 'holes' along the edges, so you'll have to solder to make a decent connection... where as the UNO has headers to put jumper wires..etc in, making it quicker/easier to prototype. However trying to put an Uno into a helmet might be a problem.

- - - Updated - - -

You're right there's not many tutorials, and code out there for it. I had to write my own code. It turned out pretty well Ironman helmet comission - YouTube


This thread -is- a fairly complete tutorial.. it may be long, but if you only focus on the posts by xl97 & memebr you wont have any problems.. there is a simple and direct diagram for both approaches, and unique for each as well..

itis tested/proven and works fine if followed. :)

(not to mention posted/shared for free too) ;
 
So I'm having trouble with my set up and hope to pick some1's brain for help. I'm using members code modified for one servo and one led array and what my friend tried to implement into my set up is a relay that cuts power to the motor after its moved and turns the power back on before it moves. but the problem is the code isn't actually sending power from the pin to the transistor to activate it. Tested the pins and they work fine just seems to be a coding error because when i check it with a volt meter once in a while it would send the 5v through the pin but it is rare. not sure how to paste code into its own box so here it is below:

#include <Servo.h>
Servo myservo; //servo1
int val; // variable for reading the pin status
int val2; // variable for to check consistency
int buttonState;
int servostatus = 0;
int switchPin =2; // Switch connected to digital pin 2
int ledPin = 5; // led array 1 to pin 5






void setup() // run once, when the sketch starts
{


myservo.attach(9); //link servo 1 to pin 9
pinMode(switchPin, INPUT); // button as input
pinMode(ledPin, OUTPUT); // led as output
pinMode(7, OUTPUT);
buttonState = digitalRead(switchPin);
myservo.write(0); // Closes the faceplate if forgot open when turning the circuit off.


}


void loop() //main body:


{
val = digitalRead(switchPin); // read input value and store it in val
delay(10);
val2 = digitalRead(switchPin); // read the input again to check for bounces
if (val == val2) { // make sure we got 2 consistant readings!
if (val != buttonState) { // the button state has changed!
if (val == LOW) { // check if the button is pressed
if (servostatus == 0) { //if leds off and faceplate open
servostatus = 1; // close the faceplate and turn leds on


myservo.write(0);


delay(1000);


//fade sequece
digitalWrite(ledPin, HIGH);
delay(50);
digitalWrite(ledPin, LOW);
delay(10);
digitalWrite(ledPin, HIGH);
delay(50);
digitalWrite(ledPin, LOW);
delay(10);




//change the value for a faster or slower fade effect
for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=10) {


analogWrite(ledPin, fadeValue);
delay(2000);
digitalWrite(7, LOW);


}


} else {
servostatus = 0;
digitalWrite(7, HIGH);
digitalWrite(ledPin, LOW);
delay(15);
myservo.write(170);




}
}
}
buttonState = val; // save the new state in our variable
}
}
 
the nano only have 'holes' along the edges, so you'll have to solder to make a decenction... where as the UNO has headers to put jumper wires..etc in, making it quicker/easier to protype. However the Uno into a helmet might be a problem.;

I have bought the nano. It has normal pins like the arduino uno. I'm happy to see you on the forum. I have a question for you. I used your code and it works great, however when i mirror the servo's as you suggested and then disconnect the batterypack and then reconnect the pack, one of the servo's turns back to a starting point. Is there a way to change the code so that both servo's have the same starting point when I reconnect the pack? Thanks.
 
You can try set the starting point of each servo. (int position)
My code is different than xl97's code, but the principle is the same.

I changed a few things like you suggested. Not really sure if the approach I took is the way to do it, but it works.Thank you.
 
Last edited:
Hi All

I've somehow managed to get xl97's code working with the ADXL335 accelerometer.

2014-05-27 12.17.01.jpg

I used pretty much the same circuit he described in http://www.therpf.com/f78/iron-man-...nics-tutorial-170853/index32.html#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.

Here's the 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
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";
//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
  //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:
    if (analogRead(xpin) < tiltdown) {
         Serial.print("WAITING FOR TILTUP");
         state = S_ACTIVATE;
    }
    else{
          Serial.print(XHEADER + analogRead(xpin) + " IDLE");
          Serial.println();
          delay(200);
    }
    break;
    
  case S_ACTIVATE:
    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{
          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.write(0);
    //myservo1.write(100);
    state = S_IDLE;    
    break;
  case S_SERVODOWN:
    lastTime = millis();  // Remember the current time
    Serial.println("servo down.........");   
    myservo.write(180);
    //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;
  } 
}

There's a video of the system working here; https://www.youtube.com/watch?v=m_tY7OQTZcY
 
Last edited:
Hi All

I've somehow managed to get xl97's code working with the ADXL335 accelerometer.

View attachment 330642

I used pretty much the same circuit he described in http://www.therpf.com/f78/iron-man-...nics-tutorial-170853/index32.html#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.

Here's the 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
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";
//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
  //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:
    if (analogRead(xpin) < tiltdown) {
         Serial.print("WAITING FOR TILTUP");
         state = S_ACTIVATE;
    }
    else{
          Serial.print(XHEADER + analogRead(xpin) + " IDLE");
          Serial.println();
          delay(200);
    }
    break;
    
  case S_ACTIVATE:
    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{
          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.write(0);
    //myservo1.write(100);
    state = S_IDLE;    
    break;
  case S_SERVODOWN:
    lastTime = millis();  // Remember the current time
    Serial.println("servo down.........");   
    myservo.write(180);
    //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;
  } 
}

There's a video of the system working here; https://www.youtube.com/watch?v=m_tY7OQTZcY


You'll find false openings can be avoided by detecting the G as well as the tilt, so only when you flick your head it will open :) It allowed me to move my head anyway I wanted in any direction without triggering it until I wanted.
 
You'll find false openings can be avoided by detecting the G as well as the tilt, so only when you flick your head it will open :) It allowed me to move my head anyway I wanted in any direction without triggering it until I wanted.

Cool - I'll have a look at converting to acceleration.
 
I'll see if I can find my code. It would check both the angle and acceleration and
if (angleY >= tilt && force >= forceVar) {
state = S_ACTIVATE;

This isn't the exact way to do it, just roughly what is happening. It takes 5 mins to calibrate the angle you want and how much force you want to flip your head but its worth it not to have it flip whenever you look up :)
 
I'll see if I can find my code. It would check both the angle and acceleration and
if (angleY >= tilt && force >= forceVar) {
state = S_ACTIVATE;

This isn't the exact way to do it, just roughly what is happening. It takes 5 mins to calibrate the angle you want and how much force you want to flip your head but its worth it not to have it flip whenever you look up :)

Awesome! Thank you so much.
 
Hey guys, I skimmed through the thread looking to see if anyone answered this question but I don't think anyone did (unless I missed it). How do you determine how much torque the servo(s) will need to output to be able to lift your faceplate? Aside from possibly trial and error of buying different servos and testing them is there a way to calculate it? Or are there servos that are recommended for foam, bondo/fiberglass, and so forth? Thanks!
 
Hey guys, I skimmed through the thread looking to see if anyone answered this question but I don't think anyone did (unless I missed it). How do you determine how much torque the servo(s) will need to output to be able to lift your faceplate? Aside from possibly trial and error of buying different servos and testing them is there a way to calculate it? Or are there servos that are recommended for foam, bondo/fiberglass, and so forth? Thanks!

pretty sure I saw the answer to that somewhere in this thread....... Or maybe I dreamt it.
 
I bought the cheap blue servos off ebay, and they make an horribke sound, and sometimes they get very hot, i tested my code and everything worked great, but the servos got damaged easyli, i broke 2, so i ordered 2 mini hitec this time, lets see when they arrive
 
This thread is more than 4 years old.

Your message may be considered spam for the following reasons:

  1. This thread hasn't been active in some time. A new post in this thread might not contribute constructively to this discussion after so long.
If you wish to reply despite these issues, check the box below before replying.
Be aware that malicious compliance may result in more severe penalties.
Back
Top