Hi Christian,
the basic question is if you really need signals for input/output of
force/position.
Obviously you aren't using the individual samples of a block, hence
it's a waste of cpu. You are proably better off with messages, where
you can also use 3-element lists for input/output of data.
Concerning your "static" variables, they are obviously not initialized
which will result in undefined behaviour. For the "link problems" it's
relevant how and where you move the variables, which is impossible to
anticipate without the actual code.
As far as i can see you cannot really separate the position and force
into two objects as they share the same resource. Having more than one
instance of an object will yield aliased results.
best greetings,
Thomas
Am 01.08.2006 um 07:59 schrieb Christian Frisson:
Re-,
More about the project: I'm trying to wrap a GPL C++ haptik API called
the Haptik Library (http://www.haptiklibrary.org) in a library of flext
externals in order to sense/actuate haptic devices directly under Pd/MSP. First
attemps have been made with Pd under Windows XP (Linux will follow), compiling
with nmake from VC++7 and debugging with a SensAble PHANToM Omni haptic
device. Basically a morph between the library example from the flext tutorial
and the "HelloHaptikConsole" example from the Haptik Library.I hope you won't mind my pasting the code deliberately on the body of
the message (see below for the "ugly static" version), as I want to wait
for a proper first release before setting up a webpage.I've tried to move the "static" variables as private members of the
base flext class and create protected accessors, but the compilation ended as a
link error (I'll paste the number ID on the next message).On the list of yet unhandled important issues:
- the "m_signal" functions are not in sync with the frequency rate of
the haptic device;
- both "m_signal" instances seems to crosstalk, as they behave
normally alone, but not together, the following quotation of the Pd C external howto
initiating the answer:"Optimization of the DSP-tree tries to avoid unnecessary
copy-operations. Therefore it is possible, that in- and out-signal are located at the
same address in the memory. In this case, the programmer has to be careful
not to write into the out-signal before having read the in-signal to avoid
overwriting data that is not yet saved."Thanks for your previous realtime answer and beforehand for the one to
come! Christian/*
-- haptik~ - the Haptik Library wrapped as a library of flext externals Copyright (c) 2006 Christian Frisson To be released under a GPL license
-- */
// include flext header
#include <flext.h>
// check for appropriate flext version
#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)
#error You need at least flext version 0.4.0
#endif
// include Haptik headers
#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <RSLib\Haptik.hpp>
using namespace RSLib;
using namespace RSLib::Math;
Haptik haptikWrapper;
IHaptikDeviceInterface hapticDevice;
bool haptikDeviceStatus;
UINT32 haptikID, haptikRate, uRes;
HaptikData fdata, pdata;
/ /----------------------------------------------------------------------
class haptik:
// inherit from basic flext class
public flext_dsp
{
// obligatory flext header (class name,base class name)
FLEXT_HEADER(haptik,flext_dsp)
public:
// constructor haptik(); ~haptik();
protected:
void m_off(); // method to set the device on void m_on(); // method to set the device on void m_dev(int d); // method to set the device ID void m_rate(int r); // method to set the device ID void m_callback(HaptikData& data);// device callback
private:
FLEXT_CALLBACK(m_on); FLEXT_CALLBACK(m_off); FLEXT_CALLBACK_I(m_dev); FLEXT_CALLBACK_I(m_rate);
};
haptik::haptik()
{
// define inlets:
// first inlet must always be of type anything (or signal for dsp
objects)AddInSignal("dev, on, off, rate, position x or force x"); // signal
inlet for force// register methods
// set up tagged methods for the default inlet (0)
// the underscore _ after CADDMETHOD indicates that a message tag is
usedFLEXT_ADDMETHOD_(0,"on",m_on); // register method for tag "on"
FLEXT_ADDMETHOD_(0,"off",m_off); // register method for tag "off"
FLEXT_ADDMETHOD_I(0,"dev",m_dev); // register method for tag "dev"
and int argumentFLEXT_ADDMETHOD_I(0,"rate",m_rate); // register method for tag "rate"
and int argument}
haptik::~haptik()
{
if (haptikDeviceStatus)
hapticDevice->Stop();
// release interface
RELEASE_HAPTIK_INTERFACE(hapticDevice);
}
void haptik::m_on()
{
if (!haptikDeviceStatus)
{
// warn user if no device has been found if (haptikWrapper.numberOfDevices == 0) { post("%s - No Haptik Devices Found! Checkout configuration
file!",thisName());
return; } // list installed devices if (haptikID == -1) { post("%s - Installed devices:",thisName()); for(UINT32 i = 0 ; i<haptikWrapper.numberOfDevices ; i++) post("%s - \t[%d] %s (%s) by
%s",thisName(),i,haptikWrapper.device[i].name,haptikWrapper.device[i].m odel,haptikWrapper.device[i].manufacturer);
post("%s - Please choose your device using a message
box",thisName());
return; } // ask for an interface to that device hapticDevice = (IHaptikDeviceInterface)
haptikWrapper.GetDeviceInterface( haptikID == -1 ? HAPTIK_DEFAULT_DEVICE : haptikID );
if (hapticDevice == NULL) { post("%s - Invalid Interface. Is device connected?",thisName()); return; } // set an object-based callback uRes =
hapticDevice-
Init(METHOD_ADDRESS(haptik,m_callback),OBJECT_ADDRESS(haptik,*this));
if FAILED(uRes) { RELEASE_HAPTIK_INTERFACE(hapticDevice); post("%s - Failed to Initialize device",thisName()); return; } // set rate uRes = hapticDevice->SetRate(haptikRate); if FAILED(uRes) { RELEASE_HAPTIK_INTERFACE(hapticDevice); post("%s - Failed to Start device",thisName()); return; } // start device uRes = hapticDevice->Start(); if FAILED(uRes) { RELEASE_HAPTIK_INTERFACE(hapticDevice); post("%s - Failed to Start device",thisName()); return; } // user interaction... post("%s - Device is on",thisName()); haptikDeviceStatus = true ;
}
else
post("%s - Device is already on!",thisName());
}
void haptik::m_off()
{
if (haptikDeviceStatus)
{
post("%s - Device is off",thisName()); hapticDevice->Stop(); // release interface RELEASE_HAPTIK_INTERFACE(hapticDevice); haptikDeviceStatus = false;
}
else
post("%s - Device is already off!",thisName());
}
void haptik::m_dev(int d)
{
if ((d<haptikWrapper.numberOfDevices) && (d>-1))
{
if (!haptikDeviceStatus) { haptikID = (UINT32)d; post("%s - Device [%d] chosen",thisName(),d); } else post("%s - Please disable the current device first",thisName());
}
else
post("%s - No such device!",thisName());
}
void haptik::m_rate(int r)
{
if ((r>=1) && (r<=1000))
{
if (haptikDeviceStatus) { uRes = hapticDevice->SetRate((UINT32)r); if FAILED(uRes) { RELEASE_HAPTIK_INTERFACE(hapticDevice); post("%s - Failed to set device rate",thisName()); return; } } haptikRate=(UINT32)r; post("%s - Rate set at: %i",thisName(),haptikRate);
}
else
post("%s - Please choose a rate between 1 and 1000 Hz",thisName());
}
void haptik::m_callback(HaptikData& data)
{
pdata.position = data.position;
data.forceFeedback = fdata.forceFeedback;
//data.torqueFeedback = Vector3(0,0,0);
}
/ /----------------------------------------------------------------------
class haptikposition:
// inherit from basic flext class
public haptik
{
// obligatory flext header (class name,base class name)
FLEXT_HEADER(haptikposition,haptik)
public:
haptikposition();
protected:
virtual void m_signal(int n, float *const *in, float *const *out);
};
FLEXT_LIB("haptik~.position",haptikposition);
haptikposition::haptikposition()
{
// define outlets:
AddOutSignal("position (3 element list)"); //signal outlet for
position xAddOutSignal("position (3 element list)"); //signal outlet for
position yAddOutSignal("position (3 element list)"); //signal outlet for
position z}
void haptikposition::m_signal(int n, float *const *in, float *const *out)
{
float *outx = out[0];
float *outy = out[1];
float *outz = out[2];
while (n--)
{
if (haptikDeviceStatus) { // output position *outz++ = pdata.position.z; *outy++ = pdata.position.y; *outx++ = pdata.position.x; }
}
} // end m_signal
/ /----------------------------------------------------------------------
class haptikforce:
// inherit from basic flext class
public haptik
{
// obligatory flext header (class name,base class name)
FLEXT_HEADER(haptikforce,haptik)
public:
haptikforce();
protected:
virtual void m_signal(int n, float *const *in, float *const *out);
};
FLEXT_LIB("haptik~.force",haptikforce);
haptikforce::haptikforce()
{
// define inlets:
// first inlet must always be of type anything (or signal for dsp
objects)AddInSignal("force (3 element list)"); // signal inlet for force y
AddInSignal("force (3 element list)"); // signal inlet for force z
}
void haptikforce::m_signal(int n, float *const *in, float *const *out)
{
const float *insx = in[0];
const float *insy = in[1];
const float *insz = in[2];
while (n--)
{
if (haptikDeviceStatus) { // input force fdata.forceFeedback.x = *insx++; fdata.forceFeedback.y = *insy++; fdata.forceFeedback.z = *insz++; fdata.torqueFeedback = Vector3(0,0,0); }
}
} // end m_signal
/ /----------------------------------------------------------------------
static void lib_setup()
{
post("Haptik~ Library v0.01");
post("Christian Frisson - 06/07/31");
post("");
// call the objects' setup routines
FLEXT_SETUP(haptikposition);
FLEXT_SETUP(haptikforce);
haptikDeviceStatus = false;
haptikID = -1;
haptikRate = 1000;
}
// setup the library
FLEXT_LIB_SETUP(haptik,lib_setup)