Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5

Program instruction operations using the API

#1
My goal is to have a script that will insert a command after the selected instruction in a program.  The snippet of code below finds the instruction that is selected/highlighted.  It is a robodk.robolink.Item object.  Next, the script looks at the parent of this (which should be an ITEM_TYPE_PROGRAM) and loops through the instructions looking for a match.

However, using program.Instruction(n) returns a tuple.  So, I have a tuple and a  robodk.robolink.Item with no way to check if they are the same.  I cannot use the Item.Type() + Item.Name() because the names are not unique.

I hope that I explained that so it made sense...

This code is part of a PySide app - sorry if it looks a little different.
Code:
    def btnSelectedItem_Clicked(self):
        '''Show information about the selected item in the tree'''

        self.ui.textInfo.clear()

        currentSelection = self.rdk.Selection()

        if len(currentSelection) == 0:
            self.ui.textInfo.append('No items selected')
            return

        item = currentSelection[0]
        itemType = item.Type()
        itemName = item.Name()
        itemParent = item.Parent()
        itemVisible = item.Visible()

        self.ui.textInfo.append(f'{itemName=}')
        self.ui.textInfo.append(f'{itemType=}')
        self.ui.textInfo.append(f'{itemParent=}')
        self.ui.textInfo.append(f'{itemVisible=}')
        self.ui.textInfo.append(f'type={type(item)}')

        # The parent is a program, so it must be an instruction
        if itemParent.Type() == 8:

            instructionCount = itemParent.InstructionCount()
            self.ui.textInfo.append(f'Looping through {instructionCount} instructions...')

            for n in range(instructionCount):
                self.ui.textInfo.append(f'Instruction {n}')
                current = itemParent.Instruction(n)

                # How to compare if item == current?
                # current is a tuple and item is an robodk.robolink.Item
#2
You can temporarily rename the selected object after saving its original name. The new name must be unique and can be generated, for example, using a random number generator. Then search through all instructions, comparing the first element of the tuple with the unique name. This way, you will avoid name collisions. After finding the desired instruction, you can restore the selected instruction’s original name, which you saved earlier.
#3
Instructions are not treated as separate items when using the API and the Selection function. With many API operations, when using instructions (such as Selection) they will be treated as their program.

On the other hand, there are a few commands/parameters that you can use but are not well documented:
  1. Retrieve the current instructions selected in a program (indexes separated by commas):
    Code:
    prog.setParam("Selection").
  2. How to update the selection in a program given their indexes. For example, to select instructions 2 an 3:
    Code:
    prog.setParam("Selection, "1,2")
  3. Retrieve the currently running instruction (index):
    Code:
    ins_idx_running = prog.setParam("CurrentInstruction")
  4. Start running a program from instruction index ins_idx:
    Code:
    prog.setParam("Start", ins_idx)

    # You can also run only one instruction using "StartOne"
    prog.setParam("StartOne", ins_idx)
  5. Retrieve an instruction as a JSON dictionary (contains all data related to an instruction and it can be used to create a copy of this instruction on the same program or a new program):
    Code:
    strjson = prog.setParam(ins_idx)
    # strjson is a JSON dictionary with all the details about the instruction index ins_idx
  6. Delete an instruction index ins_idx from a program prog using InstructionDelete:
    Code:
    prog.InstructionDelete(ins_idx)
  7. Add a new instruction at index id using a json dictionary to specify the instruction information (data like the one you can retrieve using prog.setParam(index)). Example:
    Code:
    strjson = {"Name": name, "Type": insType, ...}
    # Add a new instruction at the end
    p.setParam("New", strjson)

    # Update instruction data. Important: instruction type must be the same, otherwise you should remove this instruction and add a new one
    p.setParam(ins_idx, strjson)
  8. Update the selection for API operations (new instructions will be added after this instruction.
    Example:
    Code:
    prog.InstructionSelect(instruction_id)

    # Add a new instruction after the instruction_id index
    prog.RunInstruction("ProgramCall", INSTRUCTION_CALL_PROGRAM)
  9. Reorder an instruction before or after another one using "Reorder Before" or "Reorder After".
    Example:
    Code:
    # Move instruction_id_from to before instruction_id_to:
    program.setParam("Reorder Before", str(instruction_id_from) + "|" + str(instruction_id_to))

    # You can also move the instruction to another program using the following concept:
    program.setParam("Reorder Before", str(instruction_id_from) + "|" + str(instruction_id_to) + "|" + str(program_to.ptr))
#4
Gentlemen - thank you for all of the great information.  I never realized that dictionaries of parameters were available and could be used like this.  This is very useful.

I pasted some demo code below in case anyone stumbles on this thread in the future.  It was part of a PySide program but I stripped all that out so it was easier to follow.  One interesting thing is that if/when you double click on a script in the station to run it, that is now the selected item in the station.  So, your code will have to ask the user to select an instruction before running the code below.  I hope that makes sense.

A related question - is it possible to get and set an item's "parameter dictionary" if it is not a program instruction?  For example, a target.

Thanks again for your help - this is working great.

 
Code:
    def btnDemo_Clicked(self):
        '''Insert an instruction after the selected instruction'''

        # Get a comma separated string of selected items
        rdk = robolink.Robolink()
        currentSelection = rdk.Selection()
        print(f'{currentSelection=}')

        # There should one be one instruction selected
        if len(currentSelection) == 0:
            print('Please select an existing instruction so the program knows where to insert the new instruction below.')
            return

        if len(currentSelection) != 1:
            print('There should only be one instruction selected so the program knows where to insert the new instruction below.')
            return

        # We only have one item selected
        item = currentSelection[0]
        itemParent = item.Parent()

        # The parent is a program, so the item must be an instruction
        if itemParent.Type() == 8:

            # Get a comma separated string of indices that are selected in this program
            # There should only be one selected
            currentSelection = itemParent.setParam("Selection")
            indexSelected = int( currentSelection )
            print(f'Selected instruction in the program is at index {indexSelected}')

            # Create a dictionary of instruction settings
            newSettings = {}
            newSettings['Name']     = f'Instruction Name'
            newSettings['Type']     = 8
            newSettings['Behavior'] = 1
            newSettings['Code']     = f'Command = Something\nParameters = 1, 2, 3'
            print(f'Parameter dictionary: {newSettings}')

            # Add the new instruction - it is a INSTRUCTION_INSERT_CODE type of instruction
            itemParent.InstructionSelect(indexSelected)
            result = itemParent.RunInstruction('Temporary Name', 1)
            print(f'Result of creating the temporary instruction is {result}  (zero is good)')

            # Update instruction data
            result = itemParent.setParam(indexSelected+1, newSettings)
            print(f'Result of updating the parameters is {result}')
#5
Thank you for letting us know.

You can get and set the target of a movement instruction using the pose string. Set reference and set tool instructions also contain poses. Operating on these poses should update the item values.

You can use a function like the following to convert the pose provided as a string into a pose of type Mat:
Code:
def String2Pose(posestring):
    from robodk import robomath
    import math
    context = {}
    context["transl"] = robomath.transl
    context["rotx"] = lambda rx: robomath.rotx(rx * math.pi / 180.0)
    context["roty"] = lambda ry: robomath.roty(ry * math.pi / 180.0)
    context["rotz"] = lambda rz: robomath.rotz(rz * math.pi / 180.0)
    # pose = eval("transl(100,0,0)*rotx(180)*roty(90)", context)
    pose = eval(posestring, context)
    return pose

pose = String2Pose(instruction["Pose"])
We just improved our documentation to include the information related to operating with program instructions:
https://robodk.com/doc/en/PythonAPI/exam...ng-via-api
  




Users browsing this thread:
1 Guest(s)