Wednesday, April 8, 2015

Part Two: Setting up the random HP movement for R2

First, I owe everyone an apology for two things!

1.  For forgetting to write the Part Two segment (Part One is here )

2.  How technical this entry will read.  

Last time I spoke about the random holoprojector (HP) movement, I detailed the hardware setup.  Figuring out how to make two servos link up to the HP on a stable mount was quite the task.  



Now how to make it all work.

The software for the random movement was made by an Astromech member by the name of Micke Askernas  Using an Arduino microcontroller, you copy and paste his program into the compiler, adjust the settings as detailed in the commented out sections, compile and upload the sketch to the Arduino microcontroller.

Here's the program, cut and paste into a new Sketch with the Arduino software.

/*
* SARLACC For Holo Projectors v 0.3a
*
* - Simple
* - Arduino
* - Random Holoprojector
* - Location for
* - AstroMech Builders
* - Club
* - Control
*
* Micke Askernäs, 2012
*
*/

#include

/*
* User defined constants
* change these for finetuning your servos
* *NOTE* These values are set for my servos.
* In order to get your system running smooth, you need to
* set your own values. See test code at the bottom of code.
*/

const int Min1X = 45; // Min value for X1 
const int Max1X = 150; // Max value for X1
const int Min1Y = 0; // Min value for Y1
const int Max1Y = 130; // Max value for Y1

const int Min2X = 20; // Min value for X2
const int Max2X = 150; // Max value for X2
const int Min2Y = 45; // Min value for Y2
const int Max2Y = 160; // Max value for Y2

const int Min3X = 0; // Min value for X3
const int Max3X = 180; // Max value for X3
const int Min3Y = 40; // Min value for Y3
const int Max3Y = 170; // Max value for Y3

const int MinTime = 1000; // Minimum time to wait before another servo movement.
const int MaxTime = 6000; // Maximum time to wait before another servo movement.

/*
* Arduino Pin Configuration
* Change these if needed
*/

const int servo1Xpin = 8; // PIN on Arduino used for Servo1X
const int servo1Ypin = 9; // PIN on Arduino used for Servo1Y
const int servo2Xpin = 10; // PIN on Arduino used for Servo2X
const int servo2Ypin = 11; // PIN on Arduino used for Servo2Y
const int servo3Xpin = 12; // PIN on Arduino used for Servo3X
const int servo3Ypin = 13; // PIN on Arduino used for Servo3Y

/*
* End Arduino Pin Configuration
*/

/*
* End constants
*/


/* No more changes should be needed below this line. */ 

Servo servo1X; // Define X-Servo 1 (Front)
Servo servo1Y; // Define Y-Servo 1 (Front) 
Servo servo2X; // Define X-Servo 2 (Top)
Servo servo2Y; // Define Y-Servo 2 (Top)
Servo servo3X; // Define X-Servo 3 (Back)
Servo servo3Y; // Define Y-Servo 3 (Back)
unsigned long currentTime;
unsigned long loopTime;

void setup()
{
servo1X.attach(servo1Xpin); // Attaching servo to defined pin.
servo1Y.attach(servo1Ypin); // Attaching servo to defined pin.
servo2X.attach(servo2Xpin); // Attaching servo to defined pin.
servo2Y.attach(servo2Ypin); // Attaching servo to defined pin.
servo3X.attach(servo3Xpin); // Attaching servo to defined pin.
servo3Y.attach(servo3Ypin); // Attaching servo to defined pin.

randomSeed(analogRead(0)); // Feed unhooked analog input as seed for randomizer. Can be set to static number.
// randomSeed(3141592653); // Static number random Seed (for explanantion only)

currentTime = millis();
loopTime = currentTime;
}

void loop()
{
currentTime = millis();

/* Loop 1 for Servo1 */
if (currentTime >= (loopTime + random(MinTime,MaxTime))) {
servo1X.write(random(Min1X,Max1X)); // Turn X-Servo to random X value (0-180)
servo1Y.write(random(Min1Y,Max1Y)); // Turn Y-Servo to random X value (0-180)
loopTime = currentTime; 
}

/* Loop 2 for Servo2 */
if (currentTime >= (loopTime + random(MinTime,MaxTime))) {
servo2X.write(random(Min2X,Max2X)); // Turn X-Servo to random X value (0-180)
servo2Y.write(random(Min2Y,Max2Y)); // Turn Y-Servo to random X value (0-180)
loopTime = currentTime; 
}

/* Loop 3 for Servo3 */
if (currentTime >= (loopTime + random(MinTime,MaxTime))) {
servo3X.write(random(Min3X,Max3X)); // Turn X-Servo to random X value (0-180)
servo3Y.write(random(Min3Y,Max3Y)); // Turn Y-Servo to random X value (0-180)
loopTime = currentTime; 
}

/* 
* Loop for testing max and min values - Comment this out or remove for working program
* Recommended to take one servo at the time and test out the min/max values on X first, then Y
* and then move on to next servo.
*/

// servo1X.write(Min1X); // Turn Servo 1 to Min X value
// servo2X.write(Min2X); // Turn Servo 2 to Min X value
// servo3X.write(Min3X); // Turn Servo 3 to Min X value
//
// servo1Y.write(Min1Y); // Turn Servo 1 to Min Y value
// servo2Y.write(Min2Y); // Turn Servo 2 to Min Y value 
// servo3Y.write(Min3Y); // Turn Servo 3 to Min Y value
//
// delay (1000);
//
// servo1.write(Max1X); // Turn Servo 1 to Max X value
// servo1.write(Max2X); // Turn Servo 2 to Max X value
// servo1.write(Max3X); // Turn Servo 3 to Max X value
//
// servo1Y.write(Max1Y); // Turn Servo 1 to Max Y value
// servo2Y.write(Max2Y); // Turn Servo 2 to Max Y value 
// servo3Y.write(Max3Y); // Turn Servo 3 to Max Y value
//
// delay (1000);
}
If you have no idea what any of this means, let me break it down a little.  The comments are behind the // in most of the lines.  As you go thru, it will start to make sense, such as which pin controls which servo.



What is a little more difficult is the section that sets the min and max positions for the X and Y axis for each servo.  



(The bottom of his code has loop testing, which I didn't try out, simply because I found something else that I found interesting.)

You see, the hard part is "knowing" what position the servo is in.  You can easily remove the servo horn and put it on again in a different spot.  Much like you can remove the hands of clock from showing 6:00 and put them in the noon position.  Where does the servo think it is?

The Sketch I found allows a message box to pop open, you enter the position and the servo moves to it.  Essentially, from 0 to 180, you can use this to determine the servo limit values in your setup

#include  
Servo myservo;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);
  myservo.writeMicroseconds(1500); //set initial servo position if desired
  myservo.attach(7);  //the pin for the servo control 
  Serial.println("servo-test-22-dual-input"); // so I can keep track of what is loaded
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the string readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }

  if (readString.length() >0) {
    Serial.println(readString);  //so you can see the captured string 
    int n = readString.toInt();  //convert readString into a number

    // auto select appropriate value, copied from someone elses code.
    if(n >= 500)
    {
      Serial.print("writing Microseconds: ");
      Serial.println(n);
      myservo.writeMicroseconds(n);
    }
    else
    {   
      Serial.print("writing Angle: ");
      Serial.println(n);
      myservo.write(n);
    }

    readString=""; //empty for next input
  } 
}
 (Sorry if the code sections do not publish properly...Blogspot is a bit limiting)

The reason the ranges are so important is the shape of the shroud around the HP.  Depending on which HP you have, you may have more horizontal movement than vertical.  Or the reverse, depending on how you install it.

But ultimately, the goal of this is to have the data to feed into the Random Movement program.  This allowed me to test the minimal and maximum ranges for each axis.  By default, I was going beyond where the HP moved, causing strain on the motor that would eventually cause it to fail.

With the right values in place, Verify and Upload to the Arduino controller, then watch the HP move around.  

Having the HP movement really makes you wonder what R2 is thinking.  Of all the gadgets I have installed and made for R2, the random HP movement is the least expensive yet most convincing.  The caveat is that it quickly becomes a target of young hands grabbing it. However,  when you see R2 there, HP moving around, you really add some personality to the droid.  People think R2 is actively engaged in what's going on in the room and the HP moving around is similar to humans blinking their eyes...it's just natural and automatic.

I hope this wasn't too hard to follow along!