I've been looking for a while for information about integrating VRPN into iPhone. My objective was to enable an iPhone application as a VRPN client, but I didn't succeed in finding any tips about how to do it, so after I found out a way of integrating them I wanted to share this experience with other people, that's why I'm writing this tutorial
Making this work is not so complicated, anyway I'll detail a lot the process here, so you won't have any trouble following these steps.
These are the macro-steps to follow for achieving the integration:
The source code of this tutorial can be downloaded here:
I've splited this tutorial in two main parts:
In this first tutorial I'll show that you can connect to a VRPN server from iPhone Simulator. This tutorial has no Graphical User Interface.
The following is the expected outcome of this tutorial:
The first thing we should do is downloading the latest recommended version of VRPN following this link:
The file I downloaded is called: vrpn_07_26.zip.
In the following steps we're going to use extensively the command line console, I hope you're already familiarized with it. To open it follow: Finder + Applications + Utilities + Console
Now we've to locate "vrpn_07_26.zip" in the HOME directory and unzip it:
Now you'll have two different folders: “quat” and “vrpn”, and we must compile both. First let's go to “quat” and let's fix something inside the file named "Makefile". In this tutorial I'll be using “vi” but of course you can use any text editor you feel comfortable with.
Inside our Makefile we've to specify somehow that we're targeting a Mac OS X machine, so we've to locate and uncomment the following line:
HW_OS := universal_macosx
Look at the following image, our interest line is commented (it begins with a #):
All you have to do is uncomment it (strip only the # from the beginning of the line):
Now we save the file and execute “make” from inside the “quat” folder. This will compile the quat files that are necessary to VRPN.
It's possible that the following error shows up when executing "make":
This means either we've not installed "make" yet, or "make" executable file is not in the PATH environment variable. So let's search for make inside or system, and configure the PATH if we find it (if not, you're in trouble, have you already installed Xcode?):
After this configuration you can go on and execute "make" again. This time I hope there are not any problems. If "make" worked for you in first instance, then you need not to execute "make" again, but doing so will not harm your computer:
Ok, we're done in "quat". Let's enter the “vrpn” folder and repeat the former steps (modify the "Makefile" and compile using "make". Again, the line you have to modify is:
HW_OS := universal_macosx
This time “make” should just work, you need not to touch the PATH variable in this console window.
Ok, if everything went fine, now you have your library “libvrpn.a” and the header files “.h” inside your "vrpn" folder. That's all we need in the iPhone simulator.
But we've still not a VRPN server to work with, and that's because we are missing one extra "make". The server code is inside the "vrpn_server" folder. You should enter there and compile it. Again modifying the "Makefile" and using "make".
Maybe you'll be happy if a VRPN client were also provided, and if so, you can enter the "vrpn_print_devices" folder and compile it (This time the Makefile modification won't be that easy, so you have to work around a little to have it working, but as it's not necessary for this tutorial I'll not covering it here).
Ok, after compiling those 3 times, we have an executable file called "vrpn_server", a library called "libvrpn.a", and several ".h" files inside folders called "universal_macosx". For example in my system I finished with the server in: “vrpn/server_src/universal_macosx”.
Well, now we have to configure the vrpn_server so it can execute with no problems, to do so you only need to provide a configuration file called "vrpn.cfg". You can do so by copying this file from “vrpn/server_src” to “vrpn/server_src/universal_macosx”:
Now let's do a little modification to that file: we have to tell the server what to report and how often, so let's uncomment the line that starts with “vrpn_Tracker_NULL”, this line is among the first few lines of the file:
This "vrpn_Tracker_NULL" is a virtual device that can be used out-of-the-box with VRPN. So far I've seen you can not use the vrpn_Mouse or vrpn_Keyboard out-of-the-box with Mac OS X so we have to stick to the vrpn_Tracker_NULL. This device acts like a real Tracker, sending a default position and rotation each 2 seconds (or whatever time you tell it in the vrpn.cfg).
Now you can execute the server in “universal_macosx” this way:
Ok, that's perfect and it's all we've to do with our server. So you can leave it running in a new tab or console.
Now, let's find all the files we need for our Xcode project. I'll copy all of them in a different folder called “vrpn.07.26” for having it at the ease of the hand.
This is how I copied the files:
What I've copied is the “libvrpn.a” library and the “.h” header files.
Now we need to go to Xcode and create a new project using the “View application” template, I called it “VRPNClient” and you can do as well to follow my tutorial in an easier way:
Now let's tell our project that we have a “libvrpn.a” library and we want tit to be used during linking. Right click in the“Frameworks” folder/group inside Xcode (as you can see in the next picture) and select Add + Existing Files…:
Now browse to our “libvrpn.a” in the "vrpn.07.26":
And click “Add”:
We need also to add the header files, so go to Project + Edit Project Settings:
Filter to show only the “Header Search Paths” and “Library Search Paths” options, and configure them this way:
Now that we're done with configuring the project, let's add the Objective-C classes that encapsulate our C/C++ library:
I will choose “VRPN.mm” as the name of the new file, and don't forget to select “Also create VRPN.h” (it's very important to use “.mm” as the file extension instead of “.m”):
Now open the “VRPN.h” file and add the following methods: “init”, “startListening” and “stopListening”. There is where all our VRPN C-related code will go:
Provide the implementation for the method "init" in “VRPN.mm”. note thtat what this method does is just set the reference to the "vrpn_Tracker_Remote" C++ object to NULL, so we start with valid values for our variables:
Now provide the code for the "startListening" method. Here we are instantiating the VRPN C++ object telling VRPN to connect to the "Tracker0” device on the server located in “localhost”. The device name must be the same that we used in “vrpn.cfg”, and it's "Tracker0" by default. This method has to be called to allow our program to listen for VRPN events.
The use of the NSTimer will be cleared when you see the implementation of the private method "vrpnMainLoop" but what this does is to poll for VRPN events, and with the help of the NSTimer, this polling will occur every 0.01 seconds.
Note that we're registering the CALLBACK (the change handler) to be the function "handle_tracker".
Now provide the implementation for "stopListening", this method has to be called before exiting the application (in the applicationWillTerminate method for example).
This method is in charge of freeing the memory allocated by "startListening", this includes the creation of the NSTimer and the vrpn_Tracker_Remote objects. Always setting the references to NULL (or nil) is a good practice.
Note we've also unregistered the CALLBACK so it wont expect to be called again.
Now we've to provide the CALLBACK code (the one we're registering and unregistering), this is the C function that is to be executed each time our Tracker reports an update. Here I'm telling function because is a C/C++ function, not an Objective-C method.
Now our final step is calling these methods from somewhere. So we go to our “VRPNClientAppDelegate” class and fill in the method “applicationDidFinishLaunching” the call to both "init" and "startListening":
And in the "applicationWillTerminate" method fill in the call to "stopListening":
Ok, we're ready to test our program. First Open the Xcode console (Shift+Command+R) or in the menu:
Is in the console where we're going to see the outcome of the code.
Click the “Build and Go” button and here it is!:
That means that the connection has worked!
If you're not seeing the same thing in your console but instead you see something like the following, then your vrpn_server is not running. So go and execute it.
In the window that is running our vrpn_server there should be some text reflecting the connection attempts.
All the rest of the code that you write should work by now, even the use of CocoaTouch classes, this is because we're not blocking our application in the VRPN Main Loop, isntead, we've integrated it to the Main Run Loop of the application. If it weren't done this way we'd have ended with a blocked UI.
Bye and thanks for reading.