Commit 989a8106 authored by Alexis Girault's avatar Alexis Girault
Browse files

ENH: Refactor VRPN Server/Client API

Allows for the following workflow :
1) Create a `VRPNDeviceClient` by specifying its URL (name@ipadress)
and its type (see `DeviceType` class). The subclass `VRPNForceDevice`
is setting the style to `PHANTOM_OMNI` by default for now.
2) Create a `VRPNDeviceServer`
3) Call `VRPNDeviceServer::addDeviceClient()` to add the client created
on step 1). This will analyse the IP, name, and type of the device
client to instantiate a VRPN device connection. The added devices are
then stored in three `std:map` so the `mainloop()` can be called during
the execution.

Updated their use in `FEMSimulator` and `LaparoscopicCamera` examples.
parent f5bfeb74
......@@ -21,8 +21,9 @@
#include <vrpn_Tracker.h>
#include <vrpn_Analog.h>
VRPNDeviceClient::VRPNDeviceClient()
: deviceURL("Device0@localhost")
VRPNDeviceClient::VRPNDeviceClient(DeviceType deviceType, std::string deviceURL)
: deviceType(deviceType),
deviceURL(deviceURL)
{
this->name = "VRPNDeviceClient";
}
......@@ -70,6 +71,18 @@ void VRPNDeviceClient::exec()
this->terminationCompleted = true;
}
//---------------------------------------------------------------------------
void VRPNDeviceClient::setDeviceType(const DeviceType t)
{
this->deviceType = t;
}
//---------------------------------------------------------------------------
const DeviceType &VRPNDeviceClient::getDeviceType() const
{
return this->deviceType;
}
//---------------------------------------------------------------------------
void VRPNDeviceClient::setDeviceURL(const std::string s)
{
......@@ -87,12 +100,15 @@ void VRPNDeviceClient::processChanges()
{
this->vrpnButton->mainloop();
this->vrpnTracker->mainloop();
this->vrpnAnalog->mainloop();
}
//---------------------------------------------------------------------------
void VRPN_CALLBACK
VRPNDeviceClient::buttonChangeHandler(void *userData, const vrpn_BUTTONCB b)
{
//std::cout<<"- Button "<< b.button << " : " << b.state << std::endl;
auto handler = reinterpret_cast<VRPNDeviceClient*>(userData);
if (b.button < vrpn_int32(handler->buttons.size()))
......@@ -106,6 +122,8 @@ VRPNDeviceClient::buttonChangeHandler(void *userData, const vrpn_BUTTONCB b)
void VRPN_CALLBACK
VRPNDeviceClient::velocityChangeHandler(void *userData, const vrpn_TRACKERVELCB v)
{
//std::cout<<"- Velocity : ["<< v.vel[0] <<", "<< v.vel[1]<<", "<< v.vel[2] <<"]"<< std::endl;
auto handler = reinterpret_cast<VRPNDeviceClient*>(userData);
handler->velocity << v.vel[0], v.vel[1], v.vel[2];
......@@ -116,6 +134,9 @@ VRPNDeviceClient::velocityChangeHandler(void *userData, const vrpn_TRACKERVELCB
void VRPN_CALLBACK
VRPNDeviceClient::trackerChangeHandler(void *userData, const vrpn_TRACKERCB t)
{
//std::cout<<"Position : ["<< t.pos[0] <<", "<< t.pos[1] <<", "<< t.pos[2] <<"]"<< std::endl;
//std::cout<<"Orientation : ["<< t.quat <<", "<< t.quat <<", "<< t.quat <<"]"<< std::endl;
auto handler = reinterpret_cast<VRPNDeviceClient*>(userData);
handler->position << t.pos[0], t.pos[1], t.pos[2];
......@@ -132,6 +153,10 @@ VRPNDeviceClient::trackerChangeHandler(void *userData, const vrpn_TRACKERCB t)
void VRPN_CALLBACK
VRPNDeviceClient::analogChangeHandler(void* userData, const vrpn_ANALOGCB a)
{
//std::cout << "Analog : ";
//for( int i=0; i < a.num_channel; i++ ) std::cout << a.channel[i] << " ";
//std::cout << std::endl;
auto handler = reinterpret_cast< VRPNDeviceClient * >( userData );
if(a.num_channel > 0)
......
......@@ -49,13 +49,21 @@ typedef struct _vrpn_TRACKERVELCB vrpn_TRACKERVELCB;
typedef struct _vrpn_TRACKERCB vrpn_TRACKERCB;
typedef struct _vrpn_ANALOGCB vrpn_ANALOGCB;
enum class DeviceType { SPACE_EXPLORER_3DCONNEXION,
NAVIGATOR_3DCONNEXION,
RAZER_HYDRA,
XKEYS_XK3,
PHANTOM_OMNI,
OSVR_HDK
};
class VRPNDeviceClient: public DeviceInterface
{
public:
///
/// \brief Constructor/Destructor
///
VRPNDeviceClient();
VRPNDeviceClient(DeviceType deviceType, std::string deviceURL);
virtual ~VRPNDeviceClient();
///
......@@ -72,6 +80,19 @@ public:
///
virtual DeviceInterface::Message closeDevice() override;
///
/// \brief Set the type used to instantiate the VRPN device
/// \detail Check DeviceType enumeration for more information
/// \param t The new device type to use.
///
void setDeviceType(const DeviceType t);
///
/// \brief Get the phantom's device type
/// \return The current device type used to instantiate the VRPN device
///
const DeviceType &getDeviceType() const;
///
/// \brief Set the url used to connect to the VRPN server
/// \detail Example URLs: Phantom0@localhost, PHANToM2@10.0.0.13
......@@ -135,12 +156,13 @@ private:
static void VRPN_CALLBACK analogChangeHandler(void *userData, const vrpn_ANALOGCB a);
protected:
DeviceType deviceType; //!< Device type
std::string deviceURL; //!< Connection device URL
private:
std::shared_ptr<vrpn_Button_Remote> vrpnButton; //!< VRPN button interface
std::shared_ptr<vrpn_Tracker_Remote> vrpnTracker; //!< VRPN position/orientation interface
std::shared_ptr<vrpn_Analog_Remote> vrpnAnalog; //!< VRPN position/orientation interface
std::shared_ptr<vrpn_Analog_Remote> vrpnAnalog; //!< VRPN analog interface
};
#endif // VRPNDEVICE_H
......@@ -21,76 +21,147 @@
// VRPN includes
#include <vrpn_Connection.h>
#include <vrpn_3DConnexion.h>
#include <vrpn_Tracker_Filter.h>
#include <vrpn_3DConnexion.h>
#include <vrpn_Tracker_RazerHydra.h>
#include <vrpn_Xkeys.h>
#include <vrpn_Tracker_OSVRHackerDevKit.h>
#ifdef VRPN_USE_PHANTOM_SERVER
#include <server_src/vrpn_Phantom.h>
#endif
VRPNDeviceServer::VRPNDeviceServer() : connection(nullptr)
VRPNDeviceServer::VRPNDeviceServer()
{
this->name = "VRPNDeviceServer";
this->connection = vrpn_create_server_connection();
}
//---------------------------------------------------------------------------
void VRPNDeviceServer::exec()
bool VRPNDeviceServer::addDeviceClient(
const std::shared_ptr<VRPNDeviceClient> newDeviceClient,
const bool addFiltering)
{
connection = vrpn_create_server_connection();
std::string newDeviceURL = newDeviceClient->getDeviceURL();
if(!connection)
// Check that it is localhost
std::string newDeviceIP = newDeviceURL.substr(newDeviceURL.find_last_of("@") + 1);
if (newDeviceIP != "localhost")
{
this->terminateExecution = true;
this->terminationCompleted = true;
return;
std::cerr<< "addDeviceClient error: VRPNDeviceServer can only communicate "
<< "with devices connected locally (devicename@localhost)." << std::endl;
return EXIT_FAILURE;
}
// Create the various device objects
std::shared_ptr<vrpn_3DConnexion_SpaceExplorer> explorer =
std::make_shared<vrpn_3DConnexion_SpaceExplorer>("explorer",
this->connection);
std::shared_ptr<vrpn_3DConnexion_Navigator> navigator =
std::make_shared<vrpn_3DConnexion_Navigator>("navigator",
this->connection);
std::shared_ptr<vrpn_Tracker_RazerHydra> razer =
std::make_shared<vrpn_Tracker_RazerHydra>("razer", this->connection);
std::shared_ptr<vrpn_Tracker_FilterOneEuro> razerFiltered =
std::make_shared<vrpn_Tracker_FilterOneEuro>("razer_filtered",
this->connection,
"*razer",
7);
std::shared_ptr<vrpn_Xkeys_XK3> xkeys =
std::make_shared<vrpn_Xkeys_XK3>("xkeys", this->connection);
// Check that name not already use by a deviceClient
std::string newDeviceName = newDeviceURL.substr(0, newDeviceURL.find_last_of("@"));
if( this->analogDevicesList.find(newDeviceName) != this->analogDevicesList.end()
&& this->trackerDevicesList.find(newDeviceName) != this->trackerDevicesList.end()
&& this->buttonDevicesList.find(newDeviceName) != this->buttonDevicesList.end()
)
{
std::cerr<< "addDeviceClient error: name already use by another client ("
<< newDeviceName << ")" << std::endl;
return EXIT_FAILURE;
}
#ifdef VRPN_USE_PHANTOM_SERVER
std::shared_ptr<vrpn_Phantom> phantom =
std::make_shared<vrpn_Phantom>("Phantom0",
this->connection,
60.0f,
"Default PHANToM");
std::shared_ptr<vrpn_Tracker_FilterOneEuro> phantomFiltered =
std::make_shared<vrpn_Tracker_FilterOneEuro>("phantom_filtered",
this->connection,
"*phantom",
7);
#endif
// Instantiate a VRPN device depending on the device type
std::shared_ptr<vrpn_Analog> vrpnAnalogDevice;
std::shared_ptr<vrpn_Tracker> vrpnTrackerDevice;
std::shared_ptr<vrpn_Button> vrpnButtonDevice;
switch( newDeviceClient->getDeviceType() )
{
case DeviceType::SPACE_EXPLORER_3DCONNEXION:
vrpnAnalogDevice = std::make_shared<vrpn_3DConnexion_SpaceExplorer>
(newDeviceName.c_str(), this->connection);
break;
case DeviceType::NAVIGATOR_3DCONNEXION:
vrpnAnalogDevice = std::make_shared<vrpn_3DConnexion_Navigator>
(newDeviceName.c_str(), this->connection);
break;
case DeviceType::RAZER_HYDRA:
vrpnTrackerDevice = std::make_shared<vrpn_Tracker_RazerHydra>
(newDeviceName.c_str(), this->connection);
break;
case DeviceType::XKEYS_XK3:
vrpnButtonDevice = std::make_shared<vrpn_Xkeys_XK3>
(newDeviceName.c_str(), this->connection);
break;
// case DeviceType::PHANTOM_OMNI:
// vrpnDevice = std::make_shared<vrpn_Phantom> // TODO
// (newDeviceName.c_str(), this->connection, 60.0f, "Default PHANToM");
// break;
case DeviceType::OSVR_HDK:
vrpnTrackerDevice = std::make_shared<vrpn_Tracker_OSVRHackerDevKit>
(newDeviceName.c_str(), this->connection);
break;
default:
std::cerr<< "addDeviceClient error: unknown device type."
<< std::endl;
return EXIT_FAILURE;
}
while(!this->terminateExecution)
// Add vrpn device in list
if(vrpnAnalogDevice != nullptr)
{
this->analogDevicesList[newDeviceName] = vrpnAnalogDevice;
std::cout<<newDeviceName<<" successfully added."<<std::endl;
}
else if(vrpnTrackerDevice != nullptr)
{
this->trackerDevicesList[newDeviceName] = vrpnTrackerDevice;
std::cout<<newDeviceName<<" successfully added."<<std::endl;
}
else if(vrpnButtonDevice != nullptr)
{
this->buttonDevicesList[newDeviceName] = vrpnButtonDevice;
std::cout<<newDeviceName<<" successfully added."<<std::endl;
}
else
{
explorer->mainloop();
navigator->mainloop();
razer->mainloop();
razerFiltered->mainloop();
xkeys->mainloop();
std::cerr<< "addDeviceClient error: could not instantiate VRPN device."
<< std::endl;
return EXIT_FAILURE;
}
#ifdef VRPN_USE_PHANTOM_SERVER
phantom->mainloop();
phantomFiltered->mainloop();
#endif
// Add One Euro Filter
if( addFiltering && vrpnTrackerDevice != nullptr)
{
std::string filterName = newDeviceName +"_Filter";
std::shared_ptr<vrpn_Tracker_FilterOneEuro> filter =
std::make_shared<vrpn_Tracker_FilterOneEuro>
(filterName.c_str(), this->connection, newDeviceName.c_str(), 7);
this->trackerDevicesList[filterName] = filter;
std::cout<<filterName<<" successfully added."<<std::endl;
}
else if( addFiltering )
{
std::cerr<< "addDeviceClient warning: can not filter device which is not a tracker."
<< std::endl;
}
return EXIT_SUCCESS;
}
//---------------------------------------------------------------------------
void VRPNDeviceServer::exec()
{
while(!this->terminateExecution)
{
for( auto& device : this->analogDevicesList )
{
device.second->mainloop();
}
for( auto& device : this->trackerDevicesList )
{
device.second->mainloop();
}
for( auto& device : this->buttonDevicesList )
{
device.second->mainloop();
}
this->connection->mainloop();
std::this_thread::sleep_for(this->pollDelay);
......@@ -98,7 +169,7 @@ void VRPNDeviceServer::exec()
// connections allocated with vrpn_create_server_connection()
// must decrement their reference to be auto-deleted by VRPN
connection->removeReference();
this->connection->removeReference();
this->terminationCompleted = true;
}
......@@ -20,6 +20,10 @@
#include<vector>
#include "Devices/DeviceInterface.h"
#include "VRPNDeviceClient.h"
#include <vrpn_Analog.h>
#include <vrpn_Tracker.h>
#include <vrpn_Button.h>
class vrpn_Connection;
......@@ -32,10 +36,23 @@ public:
VRPNDeviceServer();
~VRPNDeviceServer() = default;
bool addDeviceClient(const std::shared_ptr<VRPNDeviceClient> deviceClient,
const bool addFiltering=false);
void exec() override;
private:
vrpn_Connection *connection;
/* Devices list
* The best would be to store only one map of all devices
* by using `vrpn_BaseClass` but this upcast is too many
* times ambiguous. Using `vprn_BaseClassUnique` solves the
* ambiguity problem but doesn't allow to run `mainloop()`.
*/
std::map<std::string, std::shared_ptr<vrpn_Analog>> analogDevicesList;
std::map<std::string, std::shared_ptr<vrpn_Tracker>> trackerDevicesList;
std::map<std::string, std::shared_ptr<vrpn_Button>> buttonDevicesList;
};
#endif // VRPNSERVERDEVICE_H
......@@ -23,8 +23,8 @@
// VRPN includes
#include <vrpn_ForceDevice.h>
VRPNForceDevice::VRPNForceDevice()
:
VRPNForceDevice::VRPNForceDevice(std::string deviceURL)
: VRPNDeviceClient(DeviceType::PHANTOM_OMNI, deviceURL),
enableForce(true),
contactPlane(core::Vec4f(0.0,1.0,0.0,100)),
dampingCoefficient(0.5),
......@@ -33,7 +33,6 @@ VRPNForceDevice::VRPNForceDevice()
staticFriction(0.0),
vrpnForce(nullptr)
{
this->setDeviceURL("Phantom0@localhost");
this->name = "VRPNForceDevice";
}
......
......@@ -35,7 +35,7 @@ public:
///
/// \brief Constructor/Destructor
///
VRPNForceDevice();
VRPNForceDevice(std::string deviceURL);
~VRPNForceDevice();
///
......
......@@ -23,6 +23,7 @@
#include "SimulationManager/SDK.h"
// Include required types scene objects
#include "Collision/PlaneCollisionModel.h"
#include "Collision/MeshCollisionModel.h"
#include "Collision/PlaneCollisionModel.h"
#include "Collision/PlaneToMeshCollision.h"
......@@ -58,19 +59,22 @@ int main(int ac, char** av)
// 3. Create default scene (scene 0)
//-------------------------------------------------------
auto sdk = SDK::createStandardSDK();
auto client = std::make_shared<VRPNForceDevice>();
auto server = std::make_shared<VRPNDeviceServer>();
//get some user input and setup device url
std::string input = "Phantom@localhost";
client->setDeviceURL(input);
// setup device client
std::string deviceURL = "Phantom@localhost";
auto client = std::make_shared<VRPNForceDevice>(deviceURL);
sdk->registerModule(client);
// setup controller
auto controller = std::make_shared<ToolCoupler>(client);
controller->setScalingFactor(20.0);
sdk->registerModule(server);
// sdk->registerModule(client);
sdk->registerModule(controller);
// setup server
auto server = std::make_shared<VRPNDeviceServer>();
server->addDeviceClient(client);
sdk->registerModule(server);
//-------------------------------------------------------
// Create scene actor 1: fem scene object + fem simulator
//-------------------------------------------------------
......
......@@ -59,8 +59,7 @@
#include <vtkRendererCollection.h>
#include <vtkRenderer.h>
#define SPACE_EXPLORER_DEVICE true
const DeviceType controllerType = DeviceType::NAVIGATOR_3DCONNEXION;
const float X = 8;
const float Y = 6;
const float Z = 6;
......@@ -351,30 +350,35 @@ void add2DOverlay(std::shared_ptr<VTKViewer> vtkViewer,
/// \brief Create a Laparoscopic camera controller and connect
/// it to the vtk viewer
///
int addCameraController(std::shared_ptr<SDK> sdk)
void addCameraController(std::shared_ptr<SDK> sdk)
{
std::string deviceURL;
std::shared_ptr<VRPNForceDevice> camClient = std::make_shared<VRPNForceDevice>();
std::shared_ptr<VRPNDeviceServer> server;
std::string input;
if (SPACE_EXPLORER_DEVICE)
{
server = std::make_shared<VRPNDeviceServer>();
input = "navigator@localhost";
}
else
{
//get some user input and setup device url
std::string input = "Phantom0@localhost";//"Phantom@10.171.2.217"
std::cout << "Enter the VRPN device URL(" << camClient->getDeviceURL() << "): ";
std::getline(std::cin, input);
}
if (input.empty())
// Set Camera Client
switch( controllerType )
{
return EXIT_FAILURE;
case DeviceType::NAVIGATOR_3DCONNEXION:
deviceURL = "navigator@localhost";
break;
case DeviceType::SPACE_EXPLORER_3DCONNEXION:
deviceURL = "device0@localhost";
break;
case DeviceType::PHANTOM_OMNI:
deviceURL = "Phantom0@localhost"; //"Phantom@10.171.2.217"
break;
case DeviceType::XKEYS_XK3:
deviceURL = "xkeys0@localhost";
break;
case DeviceType::OSVR_HDK:
deviceURL = "com_osvr_Multiserver/OSVRHackerDevKit0@localhost";
break;
}
camClient->setDeviceURL(input);
auto camClient = std::make_shared<VRPNDeviceClient>(controllerType, deviceURL);
std::cout<<"Device URL = "<<camClient->getDeviceURL()<<std::endl;
// Set server
std::shared_ptr<VRPNDeviceServer> server = std::make_shared<VRPNDeviceServer>();
server->addDeviceClient(camClient);
// Get vtkCamera
auto viewer = sdk->getViewerInstance();
......@@ -384,18 +388,13 @@ int addCameraController(std::shared_ptr<SDK> sdk)
// Set Camera Controller
auto camController = std::make_shared<LaparoscopicCameraController>(camClient);
camController->setScalingFactor(40.0);
camController->setScalingFactor(8);
camController->setCamera(cam);
// Register modules
sdk->registerModule(server);
sdk->registerModule(camClient);
sdk->registerModule(camController);
if (SPACE_EXPLORER_DEVICE)
{
sdk->registerModule(server);
}
return EXIT_SUCCESS;
}
int main()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment