Arduino Candygrabber

by odvratno.zgodan in Circuits > Arduino

73620 Views, 388 Favorites, 0 Comments

Arduino Candygrabber

Candygrabber_2.jpg
I've seen a lot of ways to communicate to arduino over the net, but none of them could handle pushing back the messages from arduino to the client(you) in real time and vice versa.

In this instructable you will learn how to connect to your arduino and control it over the net, set up a video stream, and how to control stuff with your arduino all in realtime. I'll try to show you on a concrete example how this could be done, but the code I used and wrote is going to be generic so you can use it for your projects. Note that I haven't discovered anything new but rather used code that I found lying around the net, built from it and changed it fit my needs.

In this example my arduino is going to control a candy grabbing machine. Do you remember when you were a kid and went to the carnival and there where those machines in which you put money, and it let you play with the crane, grabbing stuffed toys and all kinds of things, then if you were skilled enough you could grab the toy, drop it in a hole and go home with new furry friend?
The candy grabber is a desktop version of this carnival machine.

So how should it work? The idea is that there is a Flash AIR app on my home computer that when a remote client connects to it starts the video broadcast. The communication between the client and the AIR app would be through a PHP socket because it can instantly push messages from one to the other. The socket will handle all the clients and the queuing. The Red5 server is used to handle the video broadcast, stream the video and send the arduino commands from the client that is first in the queue to the AIR app (although it could do so much more... we'll talk about that in a later step). Finally TinkerProxy is used to send commands from the AIR app to the arduino that is connected to the same computer.

I'll try to keep it online as long possible but my internet provider is a little quirky so if you can't connect please come back later. Also my upload speed is quite slow so the video is relativly small but if your connection is faster you can easily adjust it to be bigger.

Seems complicated? Don't worry, I'll try to explain everything in detail on the next steps. 

UPDATE 2:
I decided if I win the MakerBot to give it away to my Arduino comunity that started in Croatia. I think that a afordable way to make parts is crutial to for the evolution of any kind of project, and as prototype fabrication in Croatia is absurdly expensive I think this would be of great help to all my friends.
Also I removed the 6 LEDs that were used for the light source. As I didn't make a LED driver I fried them. :-( That's the price for wanting to do something without first thinking how to get about it.
Of course the crapy chinese candygrabber mechanism broke down, so unfortunately the grabbing hand gets jamed and won't go up or down except if I jank it out. The MakerBot would be wery usefull to fabricate the broken part :-)

What You'll Need

toolbox.jpg
IMG_9158.jpg
IMG_9187.jpg
So here is the list of things you need for this project.

Hardware:
1.Candy grabber toy(or anything you would like to control) – you can get them online for around 30$ if I'm not mistaken
2.Arduino / Arduino Mega – bought mine online. I used the Mega because it had more free pins when I connected the motor controller
3.Motor controller – you need some way to control the motors in the candygrabber. I use Adafruit Motor/Stepper/Servo Shield for Arduino 20$ (http://www.adafruit.com/index.php?main_page=product_info&cPath=17_21&products_id=81 )
4.Breadboard
5.IR LED – I scavenged mine from an old remote
6.Photointerupter – took my out of an old PS/2 ball mouse. (It's used for the X and Y axis movement recognition of the mouse. Each axis has a one)
7.1kΩ resistors for the limit switches(4 pcs.)
8.670k Ω resistor for the Photointerupter
9.410 Ω resistor for the IR LED
10.Bunch of wires and jumper wires(they are practical as you can easily plug them in the arduino pins).
11.Shrink tube

Skills and tools:
1.Soldering iron, solder, soder wick and soldering skills
2.Screwdrivers
3.Dremel tool
4.Hot glue gun
5.Multimeter – Trust me, if you don't have one go and buy one. No seriously GO! If you're familiar with programming think of it as a kind of debugger for your circuitry. I wouldn't have finished this project if I didn't have it. Try to find out which of the 20 something wires is for what, and you will know what I'm talking about.
6.A fair knowledge of programing in ActionScript 3 (Flash)

Software:
1.Flash CS3 or higher
2.Some kind of Apache/PHP server installed on your computer(I use MAMP as it's free and easy to setup and use) - http://www.mamp.info/en/index.html
3.Red5 server – you need it to broadcast your video from the flash AIR and stream it to the flash client (free if you have your server, else hosting plans range from 30$ up, I used www.videowhisper.com/ ). You can find out more at http://www.red5.org/
4.NO-IP.ORG – as my service provider dosn't give me a static IP so I have to use it to connect to the PHP socket on my computer(also free, need to register) – www.no-ip.org
5.TinkerProxy – so flash can communicate with arduino - http://code.google.com/p/tinkerit/


Here you can download all the source codes:

UPDATE
I had some bugs with the queue in the PHP socket - SOLVED
Added some sounds to the client flash so the user is notified when it's his turn.
A few modifications to the XMLSocketAppController.as , Red5Broadcast.as and Red5SharedObject.as classes - it timeouts when there are no more users. Also this way I addresed the issue of the changing IP(I don't know why but my internet provider does that a few times a day) and you save bandwith.
Also I added  6 LEDs in the top cover to get rid of the annoying light reflection. 

Downloads

The Candy Grabber

Candygrabber_1.jpg
IMG_9153.jpg
IMG_9161.jpg
IMG_9163.jpg
IMG_9164.jpg
IMG_9165.jpg
IMG_9180.jpg
IMG_9173.jpg
IMG_9174.jpg
IMG_9175.jpg
IMG_9176.jpg
MotorSchematic.jpg
MotorSchematicAfterCutting.jpg
IMG_9170.jpg
IMG_9181.jpg
IMG_9182.jpg
IMG_9183.jpg
IMG_9185.jpg
arduinoSchematic.jpg
You can try to build your own candy grabber but this is not the scope of this project. I'm focusing on connecting and controlling the toy.
So in order to connect the arduino and the toy we have to open it up and take it's guts out. Use a screwdriver and unscrew the bottom and top of the toy. Looking at the bottom you'll see a bunch of wires connected to a PCB. Now the multimeter comes to play. Use it to find out which wire is for what. You can find a great tutorial on how to use a multimeter here (http://www.ladyada.net/learn/multimeter/ ).

I made a diagram how the motor and the limit switches are connected(picture 12). The thing is that the joysticks(potentiometer) changes the polarity on the motor and limit switches as you push it from one side to the other(In fact I'm not completely sure that the joysticks are potentiometers because I couldn't find any data sheets of this kind of potentiometer. If anybody knows what they are drop me a comment). Later will have to separate the motor from the switches by cutting the wires that go from the switches to the motor(picture 1). For now lets just find what is what.
 Power it up, insert a coin and push the first joystick ether way and hold it. Now start probing the wires in pairs for voltage. Start with the ones closest to the joystick. Take note that when it reaches the limit switch for the particular axis it will cut the power to the motor. If you are probing the X axis find it's limit switches(picture 8 & 9). On the PCB the switch wires should be close to the joystick(picture 7). There should be three wires for the 2 switches of the axis. One is +5V and the other two GND. When you find the corresponding switch wires turn the toy off and start probing the wires for continuity. Start with two wires and then press the limit switch for the corresponding axis from the top. If you loose the continuity that's one of your switches. Label it as SWITCH_1 . Labeling things will make it much easier later. Now continue and find the opposite switch and label it as SWITCH_2.
Now repeat the process for the other axis labeling the wires SWITCH_3, SWITCH_4.
The last motor that controls the up-down motion of the grabbing hand doesn't have a limit switch so you just have to find 2 wires of the motor.

When you know which switch is witch, you can open up the motor carriage(picture 11) and cut the wire of the X axis that go from the first switch to the motor and the wire that goes from the motor to the other limit switch. Connect the wires going from the first switch to the second. Also you should connect two long wires going from each wire of the motor and label them as AXIS_X. Repeat the process for the Y axis and label the motor wires as AXIS_Y. Picture 13 is the diagram of how the motor and switches should be connected after you have cut them.

Next find the LED and light sensor(picture 14). We'll use them to trigger an event in arduino that sends a message to the client that he won. They are mounted on the side of the chute where you drop the stuff that you grabbed. Take them out and replace them with a IR LED and photointerupter. The problem was when I used the light sensor the arduino interrupt fired randomly and slowly, so I decided to use the photointerupter and IR LED instead. If your photointerupter is from a mouse and has 3 pins it's safe to suppose that the middle pin is the 5V pin and the other two are GND pins. These photointerupters in fact have two photointerupter in them. It's because they need two values to calculate the position and speed of the mouse. It's called quadrature encoding. We'll be using only one. So solder one wire to the 5V pin and the other to a GND pin.

Take some jumper wires, cut and strip them. Next cut the labeled wires and strip them too, then connect a jumper wire to each and secure them with shrink tube.  Now connect the motor wires to the motor controller and the rest of the wires as shown in the diagram(picture 19).

Arduino

ArduinoLogo.jpg
arduinoSchematic.jpg
To connect the toy to the the arduino take a breadboard and connect everything as in the diagram in picture 1, and upload the sketch Candygrabber.pde that you can find in the zip file on the first step.Note that the photointerupter is defined as pin 5 because we use it as an interrupt. You can read more about interrupts at http://www.arduino.cc/en/Reference/AttachInterrupt .

The setup() function is called when a sketch starts. We use it to initialize variables, pin modes and the motors. The setup function will only run once, after each power up or reset of the Arduino board.
Next there is the loop function that starts, defines the inByte as a byte variable and assigns it the value 255 and starts a while loop which will run until it gets a zero value(0)through Serial.read(). This is important so it knows that the three next values it gets are the command values. If we didn't use the zero the commands would get mixed up(eg. sometimes the values shift for one place so instead of moving motorX it would move motorY ). In the while loop we also call the readInteruptors() function so it can check if the carriage has reached one of the limit switches and stop the motors.When it gets a zero value the while loop is exited and it begin reading the next three values, and when it gets all three of the values it calls the runMotors() function.
The runMotors() function checks which direction each motor should run and also if the carriage is at it's limits.The only remaining function is stateChange() which is triggered when something falls in the chute. It sends a message that you have won to the AIR app which then dispatches it to the user that is playing.



#include <AFMotor.h>

int pinLDR = 5;
int sensorPin=7;
int limitSwitch1[2];
int limitSwitch2[2];
int limitSwitch1PwrPIN=28;
int limitSwitch2PwrPIN=30;
int incomingByte[128];
int numBytes = 0;
int motorSpeed=0;

AF_DCMotor motorGrabber(1);
AF_DCMotor motorX(3);
AF_DCMotor motorY(4);


volatile int state = LOW;

void setup() {
  attachInterrupt(pinLDR, stateChange, FALLING);

  int i = 0;

  limitSwitch1[0] = 36;
  limitSwitch1[1] = 38;
  limitSwitch2[0] = 40;
  limitSwitch2[1] = 42;
  //Set pin modes
  for (i = 0; i < 2; i++){
    pinMode(limitSwitch1[i], INPUT);
    pinMode(limitSwitch2[i], INPUT);
  }
  pinMode(limitSwitch1PwrPIN,OUTPUT);
  digitalWrite(limitSwitch1PwrPIN,HIGH);
  pinMode(limitSwitch2PwrPIN,OUTPUT);
  digitalWrite(limitSwitch2PwrPIN,HIGH);

  for (i = 0; i < 3; i++){
    incomingByte[i]=6;
  }

  motorGrabber.setSpeed(255);
  motorGrabber.run(RELEASE);
  motorX.setSpeed(255);
  motorX.run(RELEASE);
  motorY.setSpeed(255);
  motorY.run(RELEASE);

  Serial.begin(9600);
} 

void loop() {
  int i = 0;
  byte inByte = 255;

  while(inByte != 0) {
    inByte = Serial.read();
    readInteruptors();
  }

  if (inByte == 0){
    while(Serial.available() < 3) {
      ;
    }
    //Read all the data in the buffer
    for(i = 0; i < 3; i++){
      incomingByte[i] = Serial.read();
    }   
    Serial.flush();
  }
  runMotors();
}

void readInteruptors()
{
  if((incomingByte[0]<6 && digitalRead(limitSwitch1[0])==LOW) ||
  (incomingByte[0]>6 && digitalRead(limitSwitch1[1])==LOW)){
    incomingByte[0]=6;
    motorX.run(RELEASE);
  }
  if((incomingByte[1]<6 && digitalRead(limitSwitch2[0])==LOW) ||
  (incomingByte[1]>6 && digitalRead(limitSwitch2[1])==LOW)){
    incomingByte[1]=6;
    motorY.run(RELEASE);
  }
}

void runMotors()
{
  if(incomingByte[0]<6 && digitalRead(limitSwitch1[0])==HIGH){
    motorSpeed = map(incomingByte[0], 5, 1, 0, 255);
    motorX.run(BACKWARD);
    motorX.setSpeed(motorSpeed);
  }
  else if(incomingByte[0]>6 && digitalRead(limitSwitch1[1])==HIGH){
    motorSpeed = map(incomingByte[0], 7, 11, 0, 255);
    motorX.run(FORWARD);
    motorX.setSpeed(motorSpeed);
  }
  else{
    incomingByte[0]=6;
    motorX.run(RELEASE);
  }
  if(incomingByte[1]<6 && digitalRead(limitSwitch2[0])==HIGH){
    motorSpeed = map(incomingByte[1], 5, 1, 0, 255);
    motorY.run(BACKWARD);
    motorY.setSpeed(motorSpeed);
  }
  else if(incomingByte[1]>6 && digitalRead(limitSwitch2[1])==HIGH){
    motorSpeed = map(incomingByte[1], 7, 11, 0, 255);
    motorY.run(FORWARD);
    motorY.setSpeed(motorSpeed);
  }
  else{
    incomingByte[1]=6;
    motorY.run(RELEASE);
  }  
  if(incomingByte[2]<6){
    motorSpeed = map(incomingByte[2], 5, 1, 0, 255);
    motorGrabber.run(BACKWARD);
    motorGrabber.setSpeed(motorSpeed);
  }
  else if(incomingByte[2]>6){
    motorSpeed = map(incomingByte[2], 7, 11, 0, 255);
    motorGrabber.run(FORWARD);
    motorGrabber.setSpeed(motorSpeed);
  }
  else{
    incomingByte[2]=6;
    motorGrabber.run(RELEASE);
  }
}



void stateChange()
{
  Serial.println("WIN");
  Serial.flush();
}

Downloads

The PHP Socket

PHPlogo.jpeg
So the first thing you will need to set up a PHP Socket is a Apache/PHP server set up on your local machine. I work on a Mac and I use MAMP (http://www.mamp.info/en/index.html ) for all my development needs. It's easy to setup and use and I would recommend it to anybody that needs a Apache/PHP/mySQL server. You'll ask me, as I'm a Mac user, why don't I use the Apache server that comes bundled with Mac OSX 10.5? Well I find MAMP much more user friendly and easy to use.Lets continue. The tutorial that helped me the most and that I used is “PHP5 Sockets with Flash 8” at Kirpua.com (http://www.kirupa.com/developer/flash8/php5sockets_flash8.htm ). I wanted to make it more usable and up to date so I decided to write in ActionScript 3 (instead of AS2 as in the example) a few classes that would handle the connection.
But as soon as I started coding I hit a problem. The thing is that MAMP uses a special port number on your local machine instead of port 80 as usually for http servers. MAMP's default port is 8888 (eg. Funkyzeitmac.local:8888) and the port of the socket will be 8890 so when Flash trys to connect to the socket it ALWAYS looks for a crossdomain policy before anything else. This is why it didn't work. So I made a crossdomain policy and tried to put it all around the server but I had no luck. Finally searching the web I found what looked like the answer (and of course I didn't find it on adobe's support pages). The thing is, when flash connects to the socket, the php code should send the crosdomain policy before anything else. So put make your crossdomain policy, copy it's code and paste it in the PHP code . After flash receives this crossdomain policy it works like a charm.

You can download the file at the end of this step.

As you can see I used XML like syntax for the messages that are sent to flash. This makes it easier to parse the incoming data in the flash client and AIR app. There are a few server messages that are sent when a new socket is connected,when a socket disconnects, getting the sockets count, and the queue for all the client sockets. As this is going to be a online game we want to have a timer in the client flash that will end it's turn after a minute and a half and go to the end of the queue. That is what is the queue for.Save the file in the MAMP folder where your project will reside. To get to the root folder of the MAMP server go to /Applications/MAMP/htdocs create a new folder and call it Candygrabber and save your file here. Now open a new Terminal window(/Applications/Utilities/Terminal) and type

/Applications/MAMP/bin/php5/bin/php    /Applications/MAMP/htdocs/Candygrabber/socketShell.php

 and then hit return. This tells php to run the file like a server script. If everything went well you should see something like this in the terminal window:

1 socket bound to 192.168.1.119:8890
1 listening...


 Don't close the terminal window because it will end the session and close the php socket.
Now let's move forward to the flash part. 

Red5 Server

red5.png
If you want you can download Red5 and install it on your local machine for testing purposes but at the end I recommend using a hosting plan which has Red5 by default. It will save you some time and make things lot easier. Get the Red5 app at the end of this step, and upload it to the webapps folder on your Red5 server. The app was created by the Red5 team to show the possibilities of the video streaming. So there is no need to reinvent the wheel for this part of the project.
You are done with this part... but wait. There is a few thing s that I'd like to say about Red5. It's a Java server and it's my opinion that this will be the technology of future. It has the possibilities of Flash Media Server, even much more. PHP is in fact a scripting language not a full fledged programming language. So you could ask why I used PHP sockets? The answer is that when I started this project I couldn't even imagine all the things Red5 could do. I didn't have to use PHP sockets at all, and my plan is, as soon as I get more familiar with Red5, to write an app that will handle the queue, messaging between clients, etc.

Already I moved the commands that the Flash client sends to the AIR app, from the PHP socket to Red5 and I got an enormous speed boost. The PHP socket started to lag when a few users connected, and the communication to arduino degraded. It's because Flash was trying to send a command to the AIR app every 30-40 ms. The slowing down accumulated and at one point arduino was falling behind the commands for 10 seconds! That would kill the whole project as the idea was to control it in real time. The problem was solved by using the SharedObject.

Now after all the praise about Red5 there are a few things to mention. The documentation is awful and almost all the examples for flash are written in ActionScript 2. WHAT? Action Script 3 was launched a few years ago and still they use AS2. And good luck finding a tutorial that could help you.
But maybe we should forgive them. The thing is that the version 1.0 RC was launched a few days ago. So I hope that things will get in place as soon as the community grows and people start using it more and more.

One last thing. Did I mention it's FREE!!!!! Yes! That is the decisive thing that could make it gain momentum. Remember the infancy of PHP? It was also free and today it is the standard.
And on the other hand there is Flash Media Server that costs 2500$!!! What? Yust to do some video streaming/broadcasting and communication?

If you're interested in Red5 more than on a need to know basis here is a list of links I found useful:
- A three part tutorial about installing and running Red5
http://lelandcope.com/beginner-red5-streaming-tutorial-part-1-of-3/
http://lelandcope.com/beginner-red5-streaming-part-2-of-3/
http://lelandcope.com/beginner-red5-streaming-tutorial-–-part-3-of-3-2/

- Dominick Accattato – one of the developers and creators of Red5
http://www.youtube.com/user/dominickaccattato#p/c/9B94807E1D0AF2DE

- And here is the Red5 documentation
http://build.xuggle.com/job/red5_jdk6_stable/javadoc/ 

Downloads

Tinker Proxy

tinkerproxy.jpg
You can get Tinker Proxy here(http://code.google.com/p/tinkerit/Install) and start Tinker Proxy. Check if arduino is connected to the computer. The port nuber should be 5333. Select your serial port and set the speed to 9600, then click start.

Flash Client and Application

Adobe_Flash_cs3.png
Now that we have our socket ready we can get down and dirty with the ActionScript 3.0 code. You can download the code at the end of this step.After giving it a lot of thought I decided not to go to detail and explain how I wrote the class and what it does. The scope of this instructable is not to teach you about classes, design patterns and OOP(object oriented programming). I'll rather focus on how to use it. When I started coding I decided to use a MVC (Model/View/Controller) design pattern for the class and as it grew a realized that maybe it wasn't the best idea and that I should have used another more simple and scalable design pattern. But being eager to continue with the project I decided to stick to it. Don't worry the class will work anyway. I'll be posting the new classes as soon as I finish them.

So open Flash and create two new flash files. One as ActionScript 3.0 and name it Client.fla, and the other for Adobe AIR with the name ArduinoAIR.fla. Then create two ActionScript files and call them ClienDocument.as and ArduinoAIRDocument.as .The client contains a TextArea component named “msgArea”, InputText component named “inputMessage”, two buttons component named “sendButton” and “reconnectButton”, three slider components called “motorX”, “motorY”, “motorZ”, and four dynamic TextFields called "red5StatusTxt", "sharedStatusTxt","socketStatusTxt" and "queueStatus".
The AIR app has the same components, except it also has one extra button component called “sendArduinoButton”. When you have these set up you have to point each flash file to it's document class. Document classes in plain terms are used to move your code from the timeline to an external acrionscript file. So for the Client.fla the document class should be ClientDocument.as, and for ArduinoAIR.fla should be ArduinoAIRDocument.as .OK. Now open ClientDocument.as and lest see what we've got here.

package
{
    import flash.display.*;
    import flash.events.*;
    import flash.net.URLRequest;
    import flash.text.*;
    
    import com.SocketsConnection.XMLSocketModel;
    import com.SocketsConnection.XMLSocketView;
    import com.SocketsConnection.XMLSocketController;
    import com.Red5Link.Red5Broadcast;
    
    public class ClientDocument extends MovieClip
    {
        public var xmlSocketModel:XMLSocketModel;
        public var xmlSocketView:XMLSocketView;
        public var xmlSocketController:XMLSocketController;
        public var broadcast:Red5Broadcast;
        
        public function ClientDocument(){
            msgArea.visible=false;
            inputMessage.visible=false;    
            winnerStamp.visible=false;
            broadcast = new Red5Broadcast("rtmp://yourdomain.com",
                "red5BroadcastDemo",red5StatusTxt);
                addChild(broadcast);
            xmlSocketModel = new XMLSocketModel("arduinoproject.no-ip.org",
                8890,"client");
            xmlSocketView = new XMLSocketView(msgArea,socketStatusTxt);
            xmlSocketView.socketsModel = xmlSocketModel;
            xmlSocketController = new XMLSocketController();
            xmlSocketController.socketsModel=xmlSocketModel;
            xmlSocketController.videoBroadcast=broadcast;
            xmlSocketController.addSendButton(sendButton,inputMessage);
            xmlSocketController.addReconnectButton(reconnectButton);
            xmlSocketController.addMotorButtons(motorX,motorY,motorZ);    
            xmlSocketController.addQueueStatus(queueStatus);
            xmlSocketController.addWinnerStamp(winnerStamp);
            xmlSocketController.sharedObject=new Array(
                "rtmp://yourdomain.com","motors",sharedStatusTxt);
        }        
    }
}


In the first few lines we're defining the classes we're going to use.
The things we are interested are inside the public funcion ClientDocument() so lets go through each of them and explain what they do.

public function ClientDocument(){
    msgArea.visible=false;
    inputMessage.visible=false;    
    winnerStamp.visible=false;
    broadcast = new Red5Broadcast("rtmp://yourdomain.com",
        "red5BroadcastDemo",red5StatusTxt);
        addChild(broadcast);
    xmlSocketModel = new XMLSocketModel("arduinoproject.no-ip.org",
        8890,"client");
    xmlSocketView = new XMLSocketView(msgArea,socketStatusTxt);
    xmlSocketView.socketsModel = xmlSocketModel;
    xmlSocketController = new XMLSocketController();
    xmlSocketController.socketsModel=xmlSocketModel;
    xmlSocketController.videoBroadcast=broadcast;
    xmlSocketController.addSendButton(sendButton,inputMessage);
    xmlSocketController.addReconnectButton(reconnectButton);
    xmlSocketController.addMotorButtons(motorX,motorY,motorZ);    
    xmlSocketController.addQueueStatus(queueStatus);
    xmlSocketController.addWinnerStamp(winnerStamp);
    xmlSocketController.sharedObject=new Array(
        "rtmp://yourdomain.com","motors",sharedStatusTxt);
}


The first three lines hide the TextAreas and winner trophy. The 4. line initializes the Red5Broadcast class that handles the streaming and broadcasting of the video. We have to give it the location of the red5 server, the red5 application name and the TextField in which the stream status is displayed. Then we have to add it to the display list otherwise it wouldn't show the video stream.
Next, Flash communicates with the php socket over an XMLSocket class that is part of flash. I created a Model class that will handle all the necessary listeners and dispatch events when the data is received. It is called XMLSocketModel and we initialize it this way:

xmlSocketModel = new XMLSocketModel("arduinoproject.no-ip.org",
    8890,"client");


We have to pass the URL where is our socket, our socket number, and as the last parameter the app type. The URL I use is arduinoproject.no-ip.org . Yes I use www.no-ip.org service. This way I have the possibility to have a hostname for my dynamic IP. Just register, pick a host name and install their program on your computer. The last thing we pass is "client" because we are now working on our client flash file. Note that all of the parameters must be filled in.

The next line initializes the View class. It is used to display the incoming data and it changes when it receives the events dispatched from the Model class.

xmlSocketView = new XMLSocketView(msgArea);


When we initialize the xmlSocketView we pass to it the TextArea called “msgArea” as a parameter. That tells it where to display our incoming data. The next line tells which Model it should listen for events.

xmlSocketView.socketsModel = xmlSocketModel;

So xmlSocketView should listen xmlSocketModel for events.

Next we have to initialize our Controller class. This is where all of the magic happens. The Controller class is where all the decisions and are made and all of the command are issued. Also the buttons that we put on the stage are going to have listeners in the controller firing commands when we press them, the controller also changes when it receives the events dipatched from the Model class. So, first we initialize the Controler. In the next line we tell it which Model it should listen to. Again as with the View class we tell it the Model is xmlSocketModel .Then we tell it that it's videoBroadcast = broadcast .  We add the buttons, the "queueStatus" TextField for displaying the queue, the "winnerStamp" MovieClip that shows if the client wins.
Finaly we initialize the sharedObject which will exchange the commands for the motor with the AIR app. The parameters are your domain path, the name for the shared object and the "sharedStatusTxt" TextField where the status of the shared connection is displayed. 
xmlSocketController = new XMLSocketController();
xmlSocketController.socketsModel=xmlSocketModel;
xmlSocketController.videoBroadcast=broadcast;
xmlSocketController.addSendButton(sendButton,inputMessage);
xmlSocketController.addReconnectButton(reconnectButton);
xmlSocketController.addMotorButtons(motorX,motorY,motorZ);    
xmlSocketController.addQueueStatus(queueStatus);
xmlSocketController.addWinnerStamp(winnerStamp);
xmlSocketController.sharedObject=new Array(
    "rtmp://yourdomain.com","motors",sharedStatusTxt);



Now we're going to take a look at the code for the AIR app.

package
{
    import flash.display.*;
    import flash.events.*;
    import flash.net.URLRequest;
    import flash.text.*;
    import fl.controls.Slider;
    
    import com.SocketsConnection.XMLSocketModel;
    import com.SocketsConnection.XMLSocketView;
    import com.SocketsConnection.XMLSocketAppController;    
    import com.SocketsConnection.SocketModel;
    import com.SocketsConnection.SocketView;
    import com.SocketsConnection.SocketAppController;
    import com.Red5Link.Red5Broadcast;
    
    public class ArduinoAIRDocument extends MovieClip
    {
        public var xmlSocketModel:XMLSocketModel;
        public var xmlSocketView:XMLSocketView;
        public var xmlSocketAppController:XMLSocketAppController;
        public var socketModel:SocketModel;
        public var socketView:SocketView;
        public var socketAppController:SocketAppController;
        public var broadcast:Red5Broadcast;
        
        public function ArduinoAIRDocument(){
            broadcast = new Red5Broadcast("rtmp://yourdomain.com",
                "red5BroadcastDemo",red5StatusTxt);
            addChild(broadcast);
            
            xmlSocketModel = new XMLSocketModel("localhost",
                8890,"AIR");
            xmlSocketView = new XMLSocketView(msgArea,socketStatusTxt);
            xmlSocketView.socketsModel = xmlSocketModel;
            
            socketModel = new SocketModel("localhost",
                5333,"arduino");
            socketView = new SocketView(msgArea);
            socketView.socketsModel = socketModel;
            
            xmlSocketAppController = new XMLSocketAppController();
            xmlSocketAppController.socketsModel=xmlSocketModel;
            xmlSocketAppController.colaboratingModel=socketModel;
            xmlSocketAppController.videoBroadcast=broadcast;
            xmlSocketAppController.addSendButton(sendButton,inputMessage);
            xmlSocketAppController.addReconnectButton(reconnectButton);
            xmlSocketAppController.addSendArduinoButton(sendArduinoButton);
            xmlSocketAppController.addMotorButtons(motorX,motorY,motorZ);
            xmlSocketAppController.sharedObject=new Array(
                "rtmp://yourdomain.com","motors",sharedStatusTxt);
            
            
            socketAppController = new SocketAppController();
            socketAppController.socketsModel=socketModel;
            socketAppController.colaboratingModel=xmlSocketModel;
        }        
    }
}


Take a careful look at public function ArduinoAIRDocument().

public function ArduinoAIRDocument(){
    broadcast = new Red5Broadcast("rtmp://yourdomain.com",
        "red5BroadcastDemo",red5StatusTxt);
    addChild(broadcast);
    
    xmlSocketModel = new XMLSocketModel("localhost",
        8890,"AIR");
    xmlSocketView = new XMLSocketView(msgArea,socketStatusTxt);
    xmlSocketView.socketsModel = xmlSocketModel;
    
    socketModel = new SocketModel("localhost",
        5333,"arduino");
    socketView = new SocketView(msgArea);
    socketView.socketsModel = socketModel;
    
    xmlSocketAppController = new XMLSocketAppController();
    xmlSocketAppController.socketsModel=xmlSocketModel;
    xmlSocketAppController.colaboratingModel=socketModel;
    xmlSocketAppController.videoBroadcast=broadcast;
    xmlSocketAppController.addSendButton(sendButton,inputMessage);
    xmlSocketAppController.addReconnectButton(reconnectButton);
    xmlSocketAppController.addSendArduinoButton(sendArduinoButton);
    xmlSocketAppController.addMotorButtons(motorX,motorY,motorZ);
    xmlSocketAppController.sharedObject=new Array(
        "rtmp://yourdomain.com","motors",sharedStatusTxt);    
    socketAppController = new SocketAppController();
    socketAppController.socketsModel=socketModel;
    socketAppController.colaboratingModel=xmlSocketModel;
}


The code is almost the same as in the client flash file except when we initialize the xmlSocketModel class we have to pass “AIR” as the last parameter.

The new thing that we have here is happening in lines 8 through 10.

socketModel = new SocketModel("localhost",5333,"arduino");
socketView = new SocketView(msgArea);
socketView.socketsModel = socketModel;


Here we initialize the socketModel. The socketModel is the Model class for communicating with arduino. It uses flash's Socket class. Line 9 initializes the socketView which is the View class for the socketModel. When we initialze it we have to pass the TextArea “msgArea” because that is also where we'll display the commands we send to arduino and what arduino returns to the AIR app. Line 10 tells the socketView to listen for events from the socketModel. 

The xmlSocketAppController extends from the xmlSocketController so we initialize it almost the same way.

The last three lines of code initialize the socketAppController which is the controller for the socketModel. It will handle the communication between the AIR app and arduino through port 5333. Port 5333 will be opened by TinkerProxy.

Now we have to publish our files. Publish the Client.fla for Flash Player 10 and the AIR app.

Downloads

Testing

testing.jpg
We're ready so lets start testing.
Open a terminal window and if you have installed MAMP in the default location type:

/Applications/MAMP/bin/php5/bin/php /Applications/MAMP/htdocs/Candygrabber/socketShell.php

it should say something like:

1 socket bound to 192.168.1.119:8890
1 listening...


Start the NO-IP.ORG dynamic updater. Plug the USB cable connected to arduino into the computer and then open Tinker Proxy. Select your network port number(should be 5333), the serial port and the speed(set it to 9600), and then click "Start".
If everything went ok start your AIR app.
If the AIR app establish all three connections you're done. Now you can launch your favorite browser and browse to the Client flash file. In my case it is www.pimedius.com/Candygrabber/ as I'm hosting it online.

Conclusion

bye-bye.jpg
I hope that you enjoyed this instructable. This is my first so if there is anything unclear send me a PM or post a comment. I'll try to clarify anything that you don't understand.
You can play it here. I'll try to keep it online as long possible but my internet provider is a little quirky so if you can't connect please come back later.

Also as soon as I get some more time and understanding of Red5 I'll try to rewrite the code to eliminate the need for a php socket.

Thanks for reading, and if you enjoyed this instructable please vote!!!


Peace, love, unity!