Introduction: Arduino Labyrinth

The goal of our project was to bread board an
Arduino micro controller to control two servo
motors on an “X” and “Y” axis with a joystick.
The program and servo’s would then be used to
control a wooden labyrinth, but can also be used
for a number of other projects such as a pan and
tilt camera. In addition we added a solenoid to
reload the ball to the start position.

Step 1: Materials Required

Arduino Bare Bones Board Kit with USB Bub.
The one used for the project was from:
www.moderndevice.com/products/bbb-bub-cable-package
But Any Arduino Can be used!

Additional Project Components
• 2 Hi-Tech 311 Servos - bought from a local hobby store or online at: For $10 -$13 a piece
www.hobbypeople.net/gallery/759310.asp
• Wii Nunchuck - You can buy online or at a number of stores for $20
www.bestbuy.com/site/Nintendo+-+Nunchuk+Controller+for+Nintendo+Wii/8054482.p
• Wooden Labyrinth - Bought on Amazon.com for $25-$35 depending on size
www.amazon.com/s/ref=nb_sb_noss
• Wood - We used 1/4 inch wood for the base and 1/2 inch for the servo and pipe supports
• Screws
• Relay - +5VDC to 120VAC Relay or other circuit isolation device $2-$10 like:
www.newark.com/jsp/search/productdetail.jsp
• Solenoid with Power-supply - The Solenoid we used was from my house's doorbell, we first tested it with a old power adapter taken apart to get the transformer but then we bought a stable 24VAC 1A power plug from radio shack.
• Pipe - we used an old easy-up pipe
• Wire
• Glue
• Tape
• Solder

Tools Required
• Skillsaw
• Sawsall
• Screw Gun
• Drill Bits
• Flat Drill Bit
• Tape Measure
• Pipe Cutters
• Pencil
• Computer
• Wire Cutters
• Camera
• Soldering Iron
• Metal Snips
• Jumpers for quick testing



Step 2: Build Arduino

Either Solder the components onto the provided PCB board or Bread board the Arduino using Revision E schematic and PCB as a reference. We added some details to the Schematic where we made our conections to the Arduino. We chose to power the Arduino with the USB for the convenience of working at home without a power supply. The Arduino is capible of being powered 4 different ways depending on the configuration of the power jumpers.The USB can supply 5VDC and 3.3VDC with about 500mA. The USB works fine to power the 2 servos and the Arduino but we experenced Current drain when we added the relay into the circuit. To prevent this from happening you will need to use another power source that has a higher capacity. Although we experienced current drain the project will still work with just the USB.
Download the Arduino programmer here:
arduino.cc/en/Main/Software
After installing the software upload a example program found in - File-Examples-Digital-Blink and connect a led from pin 13 to ground to test that the board is working.
You might need to configure the com port and install a couple of drivers when you first connect the USB uploader to your computer.
Additional information about the Arduino can be found here:
cdn.shopify.com/s/files/1/0038/9582/files/BBB_RevE_Instructions03.pdf

Step 3: Project Procedures

• Cut Wood
• Make Servo Supports
• Labyrinth Preparation
• Mounted Labyrinth
• Servo Mounting
• Test Solenoid Setup
• Solenoid Test Wiring
Remember to pre-drill all screw holes to prevent the wood from splitting.


Step 4: Arduino Code

The code can be modified so that the joystick or accelerometer can be default!
The code has a few un-needed elements that are negligible!


 #include     // Arduino Library Wire.h
 #include   // Arduino Library string.h
 #include    // Arduino Library Stdio.h
 #include    // Arduino Library Servo.h

Servo myservo;  // create servo object to control trigger servo

int pos = 90;    // variable to store the trigger servo position

 uint8_t outbuf[6];

 int cnt = 0;
 int ledPin = 13;
 int ledPin12 = 12;
 int Z_trig;

 int servoPin = 7;
 int servoPin2 = 6; 

 int pulseWidth = 0;
int pulseWidth2 = 0;

 long lastPulse = 0;
 long lastPulse2 = 0;

 int z_button = 0;
 int c_button = 0;

 int refreshTime = 20;  //tweaked for Hi-tech servos

 int minPulse = 300;  //tweaked for Hi-tech 3-11 servos
 int minPulse2 = 300;  //tweaked for Hi-tech 3-11 servos
 int maxPulse     =  2500; // maximum servo position
 int maxPuls2e     =  2500; // maximum servo position

 int dtime=10;

 #define pwbuffsize 10
 long pwbuff[pwbuffsize];
 long pwbuffpos = 0;
 long pwbuff2[pwbuffsize];
 long pwbuffpos2 = 0;

 void setup()
 {
    myservo.attach(8); 

     Serial.begin (9600);
     Wire.begin ();
     nunchuck_init ();
     pinMode(servoPin, OUTPUT);
     pinMode(servoPin2, OUTPUT);

     pulseWidth = minPulse;
     pulseWidth2 = minPulse2;

     Serial.print ("Finished setup\n");
 }

 void nunchuck_init() // Wii Nun-chuck handshaking
 {
     Wire.beginTransmission (0x52);
     Wire.send (0x40);
     Wire.send (0x00);  
     Wire.endTransmission ();
 }

 void send_zero() // Wii Nun-chuck handshaking
 {
     Wire.beginTransmission (0x52);
     Wire.send (0x00);
     Wire.endTransmission ();
 }

 int t = 0;

 void loop()
 {
   pinMode(ledPin12, OUTPUT); // sets pin 12 as a output so that the solenoid can be controled by the Wii Nunchuck Z button 
     t++;
     long last = millis();

     if( t == 1) {

         t = 0;

         Wire.requestFrom (0x52, 6);

         while (Wire.available ()) {
             outbuf[cnt] = nunchuk_decode_byte (Wire.receive ());
             digitalWrite (ledPin, HIGH);
             cnt++;
         }

         if (cnt >= 5) {

             int z_button = 0; // initializes Z to zero
             int c_button = 0; // initializes C to zero

             if ((outbuf[5] >> 0) & 1) // Examines Byte five From the Wii-Nunchuck for position of Z button
                 z_button = 1; // sets Z to 1
             if ((outbuf[5] >> 1) & 1) // Examines Byte five From the Wii-Nunchuck for position of Z button
                 c_button = 1; // sets C to 1

             switch (c_button) { // Case statment For C button state
             case 1:

             muovi( outbuf[1]/2+0x3E ,outbuf[0]/2+0x3E ); // Activates Accelromiter Control for Wii-Nunchuck
                 break;
             case 0:
             muovi( outbuf[3] ,outbuf[2] ); // defalt Joystick control for Wii-nunchuck
                 break;
             }

            switch (z_button) { // Case statment For Z button state
                case 1:{
                      digitalWrite (ledPin12, LOW);   // default solenoid is off
                      Z_trig = 0;}
                break;
                case 0:{
                      if (Z_trig == 0){
                        digitalWrite (ledPin12, HIGH);  // Activates the solenoid
                        delay (20);
                        digitalWrite (ledPin12, LOW); // deactivates the solenoid if Z button held to protect from breaking
                        Z_trig = 1;}}

                break;
       }

       }

         cnt = 0;
         send_zero();

   }

     updateServo();

     delay(dtime);
 }


 void updateServo()
 {

     if (millis() - lastPulse >= refreshTime) {

         digitalWrite(servoPin, HIGH);
         delayMicroseconds(pulseWidth);
         digitalWrite(servoPin, LOW);

         digitalWrite(servoPin2, HIGH);
         delayMicroseconds(pulseWidth2);
         digitalWrite(servoPin2, LOW);

         lastPulse = millis();
     }
 }

 int i=0;


 char nunchuk_decode_byte (char x)
 {
     x = (x ^ 0x17) + 0x17;
     return x;
 }

 void muovi ( uint8_t x, uint8_t y){
     float tilt = (700 - x*2*2);
     float tilt2 = (0x7E - y + 0x7E) *2*2;

     tilt = (tilt);
     pulseWidth = (tilt * 5) + minPulse;

     tilt2 = (tilt2-288);
     pulseWidth2 = (tilt2 * 5) + minPulse2;

     pwbuff[pwbuffpos] = pulseWidth;
     pwbuff2[pwbuffpos2] = pulseWidth2;

     if( ++pwbuffpos == pwbuffsize ) pwbuffpos = 0;
     if( ++pwbuffpos2 == pwbuffsize ) pwbuffpos2 = 0;


     pulseWidth=0;
     pulseWidth2=0;

     for( int p=0; p         pulseWidth += pwbuff[p];
        pulseWidth2 += pwbuff2[p];
    }

    pulseWidth /= pwbuffsize;
    pulseWidth2 /= pwbuffsize;
 }