I know this has been discussed at length, but I still cant seem to figure it out.
My situation is this..
I have a node that has a lot of int attrs. This node is communicating with servos in my robot, so it connects to the robots controller and sends it serial commands. I have all that working. The problem comes when I adjust the values of the ints, the compute doesnt get called (because I am sure I have to force it somehow), so the servos dont move. I used the affects.cpp as a basis for this node, and just added my communication code to it. If I do what the comments say, which is add a "A" and a "B" attr to it and do the getAttr on B it does update and the servo moves! So I guess I am having trouble understanding hoe "setDependantsDirty" works. Is there an easy way to set the dirty bit for a nodes attr so its forced to compute?
CODE
#include
#include
#include
//#include
#include
#include
#include "dynamixel.h"
#pragma comment(lib, "dynamixel.lib")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//bioloid specific address
// Control table address
#define P_GOAL_POSITION_L 30
#define P_GOAL_POSITION_H 31
#define P_PRESENT_POSITION_L 36
#define P_PRESENT_POSITION_H 37
#define P_MOVING 46
#define P_MODEL_NUMBER_L 0 // Model number low byte
#define P_MODEL_NUMBER_H 1 // Model number high byte
#define P_VERSION 2 // Firmware version
//void //ErrorDisplay();
int index = 0;
class robotisCom : public MPxNode
{
public:
robotisCom();
virtual ~robotisCom();
virtual MStatus compute( const MPlug& plug, MDataBlock& data );
virtual MStatus setDependentsDirty( const MPlug& plugBeingDirtied,
MPlugArray &affectedPlugs );
static void* creator();
static MStatus initialize();
static MTypeId id; // The IFF type id
static MObject oConnect;
static MObject oDisconnect;
static MObject oScanDynamixels;
static MObject oServoOne;
static MObject oServoTwentyEight;
};
MObject robotisCom::oConnect;
MObject robotisCom::oDisconnect;
MObject robotisCom::oScanDynamixels;
MObject robotisCom::oServoOne;
MObject robotisCom::oServoTwentyEight;
//TEMP ID FOR NOW
MTypeId robotisCom::id( 0x00019 );
// This node does not need to perform any special actions on creation or
// destruction
//
robotisCom::robotisCom() {}
robotisCom::~robotisCom() {}
// The compute() method does the actual work of the node using the inputs
// of the node to generate its output.
//
// Compute takes two parameters: plug and data.
// - Plug is the the data value that needs to be recomputed
// - Data provides handles to all of the nodes attributes, only these
// handles should be used when performing computations.
//
MStatus robotisCom::compute( const MPlug& plug, MDataBlock& data )
{
MStatus status;
MObject thisNode = thisMObject();
MFnDependencyNode fnThisNode( thisNode );
MFnDagNode dagFn( thisNode );
int baudnum = 1;
char buffer[256];
sprintf( buffer, "robotisCom::compute() on ", fnThisNode.name().asChar() , "\n" );
MGlobal::displayInfo( buffer );
//GET ALL THE DATA FROM THE NODE FOR COMPUTING
MPlug servoTwentyEightPlug = fnThisNode.findPlug( "servoTwentyEight", &status );
sprintf( buffer, "servoTwentyEightValue status is ", status );
MGlobal::displayInfo( buffer );
short servoTwentyEightValue;
servoTwentyEightPlug.getValue( servoTwentyEightValue );
sprintf( buffer, "servoTwentyEightValue is ", servoTwentyEightValue, " and status is ", status );
MGlobal::displayInfo( buffer );
sprintf( buffer, "trying to get value 28 from plug ", servoTwentyEightPlug.name().asChar(), " and status is ", status );
MGlobal::displayInfo( buffer );
//if the connect box is checked connect to usb2dynamixel
MPlug connectPlug = fnThisNode.findPlug( "connect", &status );
short connectValue;
connectPlug.getValue( connectValue );
//if the connect box is checked connect to usb2dynamixel
MPlug disconnectPlug = fnThisNode.findPlug( "disconnect", &status );
short disconnectValue;
disconnectPlug.getValue( disconnectValue );
//if the connect box is checked connect to usb2dynamixel
MPlug scanDynamixelsPlug = fnThisNode.findPlug( "scanDynamixels", &status );
short scanDynamixelsValue;
scanDynamixelsPlug.getValue( scanDynamixelsValue );
//DONE GETING DATA
//NOW USE THE DATA
//INIT THE CONNECTION TO THE USB2DYNAMIXEL
if (connectValue)
{
sprintf( buffer, "TRYING to open USB2Dynamixel!\n" );
MGlobal::displayInfo( buffer );
int dxlInit = dxl_initialize();
if( dxlInit == 0 )
{
cout << ( "Failed to open USB2Dynamixel!\n" );
sprintf( buffer, "Failed to open USB2Dynamixel!\n" );
MGlobal::displayInfo( buffer );
////goto END_MAIN;
}
if( dxlInit == 1 )
{
cout <<( "Succeed to open USB2Dynamixel!\n" );
//printf( "Succeed to open USB2Dynamixel!\n" );
sprintf( buffer, "Succeed to open USB2Dynamixel!\n" );
MGlobal::displayInfo( buffer );
}
dxl_set_baud( baudnum );
//set it back to 0
connectPlug.setValue( 0 );
}
if (disconnectValue)
{
dxl_terminate();
disconnectPlug.setValue( 0 );
}
//////////// Scan Dynamixel //////////////
if (scanDynamixelsValue)
{
int i, j, n;
int bValue;
int wValue;
//printf( "Scan start!(Quit to press ESC key)\n" );
sprintf( buffer, "Scan start!(Quit to press ESC key)\n" );
MGlobal::displayInfo( buffer );
for( i=1; i<2; i++ )
{
dxl_set_baud( i );
//printf( "==== Baudrate number: %d =====\n", i );
sprintf( buffer, "==== Baudrate number: %d =====\n", i );
MGlobal::displayInfo( buffer );
for( j=0, n=0; j<BROADCAST_ID; j++ )
{
dxl_ping( j );
if( dxl_get_result() == COMM_RXSUCCESS )
{
n++;
//printf( "-ID:%d (", j );
sprintf( buffer, "-ID:%d (", j );
MGlobal::displayInfo( buffer );
wValue = dxl_read_word( j, P_MODEL_NUMBER_L );
if( dxl_get_result() == COMM_RXSUCCESS )
{ //printf( "Model number:%d, ", wValue );
sprintf( buffer, "Model number:%d, ", wValue );
MGlobal::displayInfo( buffer );
}
else
{
//ErrorDisplay();
printf( ", " );
}
bValue = dxl_read_byte( j, P_VERSION );
if( dxl_get_result() == COMM_RXSUCCESS )
{ //printf( "Version:%d", bValue );
sprintf( buffer, "Version:%d", bValue );
MGlobal::displayInfo( buffer );
}
else
//ErrorDisplay();
printf( ")\n" );
}
// key check
if( _kbhit() > 0 )
{
if( getch() == 0x1b )
{
printf( "Scan break!\n" );
//goto END_MAIN;
}
}
}
printf( "Total found number: %d\n", n );
sprintf( buffer, "Total found number: %d\n", n );
MGlobal::displayInfo( buffer );
}
scanDynamixelsPlug.setValue( 0 );
}
//HACK TO COMPUTE THE NODE FOR NOW
if ( plug.partialName() == "B" ) {
// Plug "B" is being computed. Assign it the value on plug "A"
// if "A" exists.
//
MPlug pA = fnThisNode.findPlug( "A", &status );
if ( MStatus::kSuccess == status ) {
fprintf(stderr,"\t\t... found dynamic attribute \"A\", copying its value to \"B\"\n");
MDataHandle inputData = data.inputValue( pA, &status );
CHECK_MSTATUS( status );
int value = inputData.asInt();
MDataHandle outputHandle = data.outputValue( plug );
outputHandle.set( value );
data.setClean(plug);
}
} else {
return MS::kUnknownParameter;
}
//move the dynamixel
int Moving, PresentPos;
dxl_set_baud( 1 );
Moving = dxl_read_byte( 28, P_MOVING );
if( dxl_get_result() == COMM_RXSUCCESS )
{
dxl_write_word( 28, P_GOAL_POSITION_L, servoTwentyEightValue );
}
return( MS::kSuccess );
}
void* robotisCom::creator()
{
return( new robotisCom() );
}
MStatus robotisCom::initialize()
{
MStatus status;
MFnNumericAttribute numFn;
//buffer for printing to script editor
char buffer[256];
oConnect = numFn.create( "connect", "cdm", MFnNumericData::kBoolean );
numFn.setKeyable( true );
numFn.setDefault( 0 );
status = addAttribute( oConnect );
if (!status)
{
status.perror( "Unable to add \"disconnect\" attribute" );
return status;
}
oDisconnect = numFn.create( "disconnect", "ddm", MFnNumericData::kBoolean );
numFn.setKeyable( true );
numFn.setDefault( 0 );
status = addAttribute( oDisconnect );
if (!status)
{
status.perror( "Unable to add \"disconnect\" attribute" );
return status;
}
oScanDynamixels = numFn.create( "scanDynamixels", "sdm", MFnNumericData::kBoolean );
numFn.setKeyable( true );
numFn.setDefault( 0 );
status = addAttribute( oScanDynamixels );
if (!status)
{
status.perror( "Unable to add \"scanDynamixels\" attribute" );
return status;
}
oServoOne = numFn.create( "servoOne", "son", MFnNumericData::kShort );
numFn.setDefault( 512 );
numFn.setMin( 0 );
numFn.setMax( 1023 );
numFn.setKeyable( true );
status = addAttribute( oServoOne );
if (!status)
{
status.perror( "Unable to add \"servoOne\" attribute" );
return status;
}
oServoTwentyEight = numFn.create( "servoTwentyEight", "ste", MFnNumericData::kShort );
numFn.setDefault( 512 );
numFn.setMin( 0 );
numFn.setMax( 1023 );
numFn.setKeyable( true );
status = addAttribute( oServoTwentyEight );
if (!status)
{
status.perror( "Unable to add \"servoTwentyEight\" attribute" );
return status;
}
return( MS::kSuccess );
}
MStatus robotisCom::setDependentsDirty( const MPlug &plugBeingDirtied,
MPlugArray &affectedPlugs )
{
MStatus status;
MObject thisNode = thisMObject();
MFnDependencyNode fnThisNode( thisNode );
if ( plugBeingDirtied.partialName() == "A" ) {
// "A" is dirty, so mark "B" dirty if "B" exists.
// This implements the relationship "A robotisCom B".
//
fprintf(stderr,"robotisCom::setDependentsDirty, \"A\" being dirtied\n");
MPlug pB = fnThisNode.findPlug( "B", &status );
if ( MStatus::kSuccess == status ) {
fprintf(stderr,"\t\t... dirtying \"B\"\n");
CHECK_MSTATUS( affectedPlugs.append( pB ) );
}
}
/////////////////////////////////////////////////
//tried this, and it didnt seem to do anything//
///////////////////////////////////////////////
if ( plugBeingDirtied.partialName() == "servoTwentyEight" ) {
MPlug pSte = fnThisNode.findPlug( "servoTwentyEight", &status );
if ( MStatus::kSuccess == status ) {
CHECK_MSTATUS( affectedPlugs.append( pSte ) );
}
}
return( MS::kSuccess );
}
// These methods load and unload the plugin, registerNode registers the
// new node type with maya
//
MStatus initializePlugin( MObject obj )
{
MStatus status;
MFnPlugin plugin( obj, PLUGIN_COMPANY , "6.0", "Any");
status = plugin.registerNode( "robotisCom", robotisCom::id, robotisCom::creator,
robotisCom::initialize );
if (!status) {
status.perror("registerNode");
return( status );
}
return( status );
}
MStatus uninitializePlugin( MObject obj)
{
MStatus status;
MFnPlugin plugin( obj );
status = plugin.deregisterNode( robotisCom::id );
if (!status) {
status.perror("deregisterNode");
return( status );
}
return( status );
}
with it written like this, it still doesnt work UNLESS I plug something into both sides of the attr "servoTwentyEight" So I connect anything into it, then its output to something else.. and it updates
connectAttr locator1.translateX robotisCom.servoTwentyEight;
connectAttr robotisCom.servoTwentyEight locator2.translateX;
now move locator1 and it updates the server.. would rather not have to plug things in everywhere to just get it to update.