Actually, modifying the Alignment Angle wasn't the best thing to do in my previous article. I should have played with the RevoluteJointMotion.rotationValue instead. That's what the "Drive Joints" command is modifying as well. And this way the Joint Limits will be honoured too :)
I also improved things a bit so that now you can select the two Revolute Joints that you want to drive using the command:
#Author- #Description- import adsk.core, adsk.fusion, adsk.cam, traceback # Global variable used to maintain a reference to all event handlers. handlers = [] # Other global variables commandName = "MoveRobot" app = adsk.core.Application.get() if app: ui = app.userInterface revoluteJoint1 = None revoluteJoint2 = None isReverseUpDown = False isReverseLeftRight = False revolutionStep = 0.1 # Event handler for the keyDown event. class MyKeyDownHandler(adsk.core.KeyboardEventHandler): def __init__(self): super().__init__() def notify(self, args): try: eventArgs = adsk.core.KeyboardEventArgs.cast(args) keyCode = eventArgs.keyCode if keyCode == adsk.core.KeyCodes.UpKeyCode: if isReverseUpDown: diffVal = -revolutionStep else: diffVal = revolutionStep motion = revoluteJoint1.jointMotion motion.rotationValue = motion.rotationValue + diffVal elif keyCode == adsk.core.KeyCodes.DownKeyCode: if isReverseUpDown: diffVal = revolutionStep else: diffVal = -revolutionStep motion = revoluteJoint1.jointMotion motion.rotationValue = motion.rotationValue + diffVal elif keyCode == adsk.core.KeyCodes.LeftKeyCode: if isReverseLeftRight: diffVal = -revolutionStep else: diffVal = revolutionStep motion = revoluteJoint2.jointMotion motion.rotationValue = motion.rotationValue + diffVal elif keyCode == adsk.core.KeyCodes.RightKeyCode: if isReverseLeftRight: diffVal = revolutionStep else: diffVal = -revolutionStep motion = revoluteJoint2.jointMotion motion.rotationValue = motion.rotationValue + diffVal # Refresh the view to show the change vp = app.activeViewport vp.refresh() except: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) # Event handler for the inputChanged event. class MyInputChangedHandler(adsk.core.InputChangedEventHandler): def __init__(self): super().__init__() def notify(self, args): eventArgs = adsk.core.InputChangedEventArgs.cast(args) commandInput = eventArgs.input if commandInput.id == commandName + '_step': global revolutionStep revolutionStep = commandInput.value elif commandInput.id == commandName + '_reverseUpDown': global isReverseUpDown isReverseUpDown = commandInput.value elif commandInput.id == commandName + '_reverseLeftRight': global isReverseLeftRight isReverseLeftRight = commandInput.value # Event handler for the executePreview event. class MyExecutePreviewHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): eventArgs = adsk.core.CommandEventArgs.cast(args) # Make it accept the changes whatever happens eventArgs.isValidResult = True class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler): def __init__(self): super().__init__() def notify(self, args): try: command = adsk.core.Command.cast(args.command) # Subscribe to the various command events onInputChanged = MyInputChangedHandler() command.inputChanged.add(onInputChanged) handlers.append(onInputChanged) onExecutePreview = MyExecutePreviewHandler() command.executePreview.add(onExecutePreview) handlers.append(onExecutePreview) onKeyDown = MyKeyDownHandler() command.keyDown.add(onKeyDown) handlers.append(onKeyDown) onDestroy = MyCommandDestroyHandler() command.destroy.add(onDestroy) handlers.append(onDestroy) inputs = command.commandInputs inputs.addTextBoxCommandInput( commandName + '_usage', 'Usage:', 'Use the arrow buttons to drive the robot arm', 2, True); inputs.addValueInput( commandName + '_step', 'Rotation step: ', 'deg', adsk.core.ValueInput.createByReal(revolutionStep)) inputs.addBoolValueInput( commandName + '_reverseUpDown', 'Reverse Up/Down direction', True, '', isReverseUpDown) inputs.addBoolValueInput( commandName + '_reverseLeftRight', 'Reverse Left/Right direction', True, '', isReverseLeftRight) except: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) class MyCommandDestroyHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: commandDefinitions = ui.commandDefinitions # Check the command exists or not cmdDef = commandDefinitions.itemById(commandName) if cmdDef: cmdDef.deleteMe # When the command is done, terminate the script # this will release all globals which will remove all event handlers adsk.terminate() except: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) def run(context): try: product = app.activeProduct design = adsk.fusion.Design.cast(product) if not design: ui.messageBox('It is not supported in current workspace, please change to MODEL workspace and try again.') return # Get selected Revolute Joints to work on selections = app.userInterface.activeSelections if selections.count != 2: ui.messageBox("The 2 revolute joints you want to control need to be selected before running the command!") return global revoluteJoint1, revoluteJoint2 revoluteJoint1 = selections.item(0).entity revoluteJoint2 = selections.item(1).entity commandDefinitions = ui.commandDefinitions # Check the command exists or not cmdDef = commandDefinitions.itemById(commandName) if not cmdDef: cmdDef = commandDefinitions.addButtonDefinition( commandName, commandName, commandName, '') # Subscribe to events onCommandCreated = MyCommandCreatedHandler() cmdDef.commandCreated.add(onCommandCreated) # Keep the handler referenced beyond this function handlers.append(onCommandCreated) # Run the command inputs = adsk.core.NamedValues.create() cmdDef.execute(inputs) # Prevent this module from being terminated when the script returns, # because we are waiting for event handlers to fire adsk.autoTerminate(False) except: ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
-Adam