Search Unity

standard way to communicate with hardware (arduino)

Discussion in 'Formats & External Tools' started by wimeck, Oct 17, 2009.

  1. wimeck

    wimeck

    Joined:
    May 26, 2008
    Posts:
    50
    Hi all,

    Being able to easily read data from sensors or input from buttons/switches/sliders, together with having the ability to control hardware like motors/lights is in my opinion an important step for Unity. This makes it possible for Unity to be used to make for example interactive installations or your own custom input devices like joysticks. A nice example of an installation made together with Unity can be seen here:

    http://forum.unity3d.com/viewtopic.php?t=28892&highlight=arduino

    Probably the easiest, cheapest and most popular way right now to interface with hardware is the arduino platform ( www.arduino.cc ). There is already a possibility for Unity to talk to this platform by using myu ( http://forum.unity3d.com/viewtopic.php?t=19567&postdays=0&postorder=asc&start=0 ), but this requires Max/MSP, which costs around $699.00. For many artists/students this might be too expensive, and do you really need an external program to do this? So my question is, is there a easier/cheaper way to communicate with Arduino? I have the impression there are already quite some people/institutes who made there own connections, it would be great if they could share their code/setup, so we could make a “standard” way to connect to Arduino, and put it on the wiki.

    Preferably it shouldn’t be limited to Unity3d Pro (again, to make it more accessible for artists/students), or there could be two versions. And it would be nice to have it working on both Windows and OSX.
    I am not a great programmer myself, so I am afraid I can not really contribute to this project, besides trying to set it in motion… Hope you can help!

    Wim
     
  2. Whimsical

    Whimsical

    Joined:
    Mar 29, 2008
    Posts:
    155
    You are right that it would be nice to have a built in possibility to connect to Arduinos and such. But: We just did such a connection to an Arduino all by ourselves and it was not very hard to do. Though I have to admit that it is a custm plug-in and therefore needs Unity Pro to run. But again: If you have Unity Pro available and are able to throw in a few C# lines, everything will be running just fine.

    Though I have to admit that Arduinos aren't the best value for money. They're incredibly slow. Ok, they give you the ability to program them by using a higher language. But you pay this with a considerable speed decrease compared with micro controllers programmed by using assembler. And yes, I know how hard assembler is, I hate it myself. But even the Arduino Mega is not able to handle software PWM for 120 LEDs plus some minimalistic serial communication.
     
  3. wimeck

    wimeck

    Joined:
    May 26, 2008
    Posts:
    50
    Hi Whimsical,

    Thanks for your reply. As with many things, it's easy when you know how to do it... I started this thread to try to accomplish a 'standard' way to connect Unity with Arduino, so it would also be available for people who are not great at programming. Would you mind sharing you code here?

    I know Arduino might not be the solution for every project, but in general I think it's the easiest to use solution. And since it became so popular there is a huge community behind it, resulting in many forums/tutorials/books to help you using it.

    Wim
     
  4. bryanleister

    bryanleister

    Joined:
    Apr 28, 2009
    Posts:
    130
    I'm sure it's slower, but like you I am no programmer but am able to get the Arduino up and running with little effort.

    I recently did an installation using Unity on a MacMini, hooked to an Arduino and also using Twitter feeds to populate some textures. The Arduino used a PING Ultrasonic sensor to read proximity data and I used that to operate a 'Player' object in Unity. The player roughly mimicked the person standing in front of the projection and their movement would cause a collision with objects in the scene.

    My approach was pretty low-tech. I tried the Max/MSP technique, but found it buggy (like Max!). So, I wrote a program in Processing to read in the sensor data and then write that to a text file. It's very similar to the technique I read in this forum for writing Wii information to a text file. Bluetooth from the Wii I also found to be buggy.

    This worked surprisingly well. My Unity game would run for 5 hours before crashing, and then I would have it automatically restart. Some kind of memory leak, probably related to the Twitter feed...

    Anyway, here is javascript code I attached to the Player object in Unity:

    Code (csharp):
    1.  
    2. import System;
    3. import System.IO;
    4.  
    5. var minimumHeight : float;
    6. var delaySeconds = 2.0;
    7. var posvalues : Array;
    8.  
    9. function Start (){
    10.    
    11.     InvokeRepeating("mover", .1, .5);
    12. }
    13.  
    14. function mover () {
    15.     var poscoordinates = (Application.dataPath + "/positions.txt");
    16.   //var poscoordinates = (Application.dataPath + "/Scripts/" + "positions.txt");
    17.   //var poscoordinates = "/positions.txt";
    18.    
    19.  if (File.Exists(poscoordinates)){    
    20.       var sr = new StreamReader(poscoordinates);
    21.       var txt = sr.ReadToEnd();
    22.       posvalues = txt.ToString().Split("\n"[0]);
    23.    }
    24.    
    25.    zPosition = float.Parse(posvalues[0]);
    26.    
    27.    move(zPosition);
    28.    
    29.    
    30.     //Debug.Log(values);
    31. }
    32.  
    33.  function move(zpositionTarget : float)
    34. {
    35.    for (var n: int = 0 ; n < 1 ; n++)
    36.    {
    37.    
    38.       // Lerp to the selected target position in 2 seconds
    39.       var fStartTime: float = Time.time;
    40.       var fCurrLerp: float = (Time.time - fStartTime) / delaySeconds;
    41.       while (fCurrLerp <= 1.0)
    42.       {
    43.         fCurrLerp = (Time.time - fStartTime) / delaySeconds;
    44.         transform.localPosition.z = Mathf.Lerp(transform.localPosition.z, zpositionTarget, fCurrLerp);  
    45.         yield;
    46.       }
    47.    }
    48. }
    49.  
    And here is the Processing code. Note that I am writing the text file into the Contents folder of the Unity application. Makes it convenient since I need both applications running at the same time.

    BTW, I did not write most of the Processing code, that is coming from the Arduino.cc forums.

    Code (csharp):
    1.  
    2.  
    3.  
    4. // import the serial libary for Processing
    5. import processing.serial.*;
    6.  
    7. // define a new port object
    8. Serial port;
    9.  
    10.  
    11. PrintWriter output;
    12. PrintWriter outputPos;
    13.  
    14.  
    15. void setup(){
    16.   size(48,48);
    17.   port = new Serial(this, Serial.list()[1], 9600);
    18. }
    19.  
    20. void draw(){
    21.  
    22.     // delay 100 milliseconds - this must be the same delay used in the Arduino sketch.
    23.   delay(100);
    24.   getSerialData();
    25.  
    26. }
    27.  
    28. void getSerialData(){
    29.  
    30.  
    31.   // create a string to store the value from reading the serial port
    32.   String serialBuffer = port.readString();
    33.  
    34.   // check if the value is not null, that the value is greater that 2 and no more than 4 characters
    35.   if (serialBuffer != null  serialBuffer.length() >= 2  serialBuffer.length() <= 4) {
    36.  
    37.     // check that the first character in the string is A
    38.     // we add A to our output to cast the serial value to a string type.
    39.     // Its also handy as the A is doubled up as a marker for a new value in the serial log
    40.     if (serialBuffer.indexOf("A") == 0) {    
    41.       // if this is true then remove A
    42.       serialBuffer =  serialBuffer.substring(1,serialBuffer.length());
    43.     }
    44.     // double check to make sure there are no more A's in our string - otherwise we can't convert to a number
    45.     if (serialBuffer.indexOf("A") == -1) {
    46.       // convert the string to an integer
    47.       int i = Integer.parseInt(serialBuffer);
    48.       //map to our input range
    49.       float m = map(i, 0, 150, 0, 40);
    50.       // print our integer
    51.       //println(m);
    52.       //Code below writes incoming numbers to a file
    53.       outputPos = createWriter(sketchPath("Uhypocenter.app/Contents/positions.txt"));
    54.       //outputPos = createWriter(sketchPath("Assets/positions.txt"));
    55.       //outputPos = createWriter("positions.txt");
    56.       outputPos.println(m);
    57.       outputPos.flush();
    58.       outputPos.close(); // Finishes the file
    59.     }
    60.   }
    61.  
    62. }
    63.  
    64.  
    65.  
     
  5. Raptor Claw

    Raptor Claw

    Joined:
    Jan 24, 2010
    Posts:
    11
    I'm having trouble implementing your scripts above. They both are working fine separately but when ever I try and run processing and Unity at the same time processing gives me and error.
    "Couldn't create a writer for C:\blah blah blah" then in says "(The process cannot access the file because it is being used by another process)"

    How do you allow both of these scripts to access the same text file at the same time without having a conflict?

    Thanks your help is much appreciated.
     
  6. bryanleister

    bryanleister

    Joined:
    Apr 28, 2009
    Posts:
    130
    It must be a mac thing, I did not run into any problems having it read/write at the same time. Make sure your path to the text file is correct, that's the hardest thing to get right.
     
  7. daft

    daft

    Joined:
    Mar 24, 2010
    Posts:
    6
  8. swenson5559

    swenson5559

    Joined:
    Oct 11, 2010
    Posts:
    10
    I might be oversimplifying, but a good way of going about this would be to interface Arduino or any other microcontroller with Processing or OpenFrameworks, then sending the serial data to Unity via OSC. I've used this method before and it's surprisingly responsive.