Getting joint angles of programmed points in Python

I have a robot and programmed some PTPMotion statements that the robot drives to:


Now, when I select any point, I can check the corresponding values of the joints, see below:

I selected point #17 and can now see the joint values of the robot when it drives to this point (as highlighted).
Ultimately, I would like to export the joint values of every single point to a csv file.
However, I’m unsure on what would be best practice to programmatically get those values for each point using a python script.

If anyone has any ideas I would be really thankful,
cheers

1 Like

Hi @TStotz

This should be fairly straightforward to do with a python script once you know the basics.
I would recommend to start with going through thecourses Basics of Python Scripting (https://academy.visualcomponents.com/courses/basics-of-python-scripting/) and Python Robotics (https://academy.visualcomponents.com/courses/python-robotics-programming-a-robot-with-python/) to get more familiar with scripting.

After going through these courses, you should have a solid understanding of python scripting and you can implement custom scripts with help form the API documentation.

1 Like

The recommended courses can help because the following might read like gibberish.

About the API in relation to linear and PTP motion statements, each point is a vcPositionFrame object that has a JointValues property, which gives you a list of the joint values for that target. The assumption would be the motion statement was made with the robot in your setup.

In relation to points in a Path statement, each point is a vcSchemaPositionFrame. You need to do a little more work to get the joint values for each point since a point gives you a position matrix and any external joint values. So the example in vcSchemaPositionFrame has a section on how to create a vcMotionTarget, and that target can be used in conjunction with robot controller to find the joint values. For custom statements using schema, the workflow would be similar, but there are probably easier ways to get the values, such as using the vcMotionInterpolator object.

This is a helpful question @TStotz since I noticed vcHelpers.Selection does not have methods for returning all positions and their joint values.

There, of course, is the option to record the joint values of robot during simulation, but that is trivial. Here is a code example that records using sampling interval, but if you drive or jog a robot to a programmed point the vcDof object for each joint of robot (internal and external) can be used to get the value.

from vcScript import *

SAMPLING_INTERVAL = 0.1


def getRobotJointValues():
  joint_values = [d.VALUE for d in dofs]
  return joint_values


def stopRecordingJointValues(program_executor):
  #just an event handler to stop recording joint values
  suspendRun()


def OnRun():
  ##recorded joint values
  #while app.Simulation.IsRunning:
  #  print getRobotJointValues() #write to file, note behavior, etc.
  #  delay(SAMPLING_INTERVAL)
  pass


comp = getComponent()
app = getApplication()
robot = app.findComponent("Generic Articulated Robot")
controller = robot.findBehaviour("Controller")

joints = controller.Joints
dofs = [j.Dof for j in joints]

executor = robot.findBehaviour("Executor")
executor.OnProgramFinished = stopRecordingJointValues
recorded_jv = [[0.0, 0.0, 90.0, 0.0, 0.0, 0.0],[0.0, 2.1119999999999988, 88.0899798038463, 0.0, 4.820922531023192, 0.0],[0.0, 8.447999999999995, 82.3599192153852, 0.0, 19.283690124092768, 0.0],[0.0, 23.137002028808805, 69.07569074172633, 0.0, 52.813302263737555, 0.0],[0.0, 30.36425338657955, 62.53961306368592, 0.0, 69.31047030731943, 0.0],[0.0, 30.91558837890625, 62.65484619140625, 0.0, 69.41049194335938, 0.0],[0.0, 32.46856689453125, 64.78207397460938, 0.0, 65.73031616210938, 0.0],[0.0, 37.327117919921875, 67.9119873046875, 0.0, 57.741851806640625, 0.0],[0.0, 38.958099365234375, 68.32638549804688, 0.0, 55.696441650390625, 0.0],[0.0, 37.17315673828125, 67.860595703125, 0.0, 57.947174072265625, 0.0],[0.0, 33.78765869140625, 66.01943969726562, 0.0, 63.173828125, 0.0],[0.0, 30.873138427734375, 62.58172607421875, 0.0, 69.526123046875, 0.0],[0.5162845265931946, 30.68658447265625, 62.24810791015625, 0.0, 70.04623413085938, 0.0],[9.72522573987986, 30.68658447265625, 62.24810791015625, 0.0, 70.04623413085938, 0.0],[22.26451988207098, 30.68658447265625, 62.24810791015625, 0.0, 70.04623413085938, 0.0],[46.18529419434725, 30.68658447265625, 62.24810791015625, 0.0, 70.04623413085938, 0.0],[62.185294194347264, 30.68658447265625, 62.24810791015625, 0.0, 70.04623413085938, 0.0],[86.18529419434728, 30.68658447265625, 62.24810791015625, 0.0, 70.04623413085938, 0.0],[102.18529419434729, 30.68658447265625, 62.24810791015625, 0.0, 70.04623413085938, 0.0],[123.60580873966178, 30.68658447265625, 62.24810791015625, 0.0, 70.04623413085938, 0.0],[131.90636022294524, 30.68658447265625, 62.24810791015625, 0.0, 70.04623413085938, 0.0],[135.12451755269726, 30.643537552467265, 62.387184397011424, -0.8264927964098103, 69.86271927933883, -0.8264927964098103],[135.12451722306437, 30.116253280204358, 64.09074051295111, -10.950251959022037, 67.61483500542037, -10.950251959022037],[135.12451602531212, 28.20031588548187, 70.28077317318876, -47.73589070294041, 59.446934375792694, -47.73589070294041],[135.1245148645087, 26.34348230042353, 76.2798525626289, -83.38674738316328, 51.53100129244232, -83.38674738316328],[135.12451313316214, 23.574001754792203, 85.22752229159404, -136.5602545867535, 39.72433059708786, -136.56025458675347],[135.1245122906234, 22.226267716508236, 89.58179698620123, -162.43649542414124, 33.97875783975631, -162.43649542414124]]
3 Likes

Thank you @Este and @WilliamSmith for your helpful information.
There seem to be many different options to export the joint values. In the end, I went with a different approach and thought it might be interesting for others.
First, I gather all programmed statements from the vcExecutor object and iterate over the statements and positions. Then, I use the function move_immediate to move the robot to the position of the current statement. Then I can read the current joint values of every joint and save them.

program = robotExecutor.Program
routine = program.MainRoutine
for statement in routine.Statements:
    for position in statement.Positions:
	    controller = robotExecutor.Controller
	    controller.moveImmediate(position.PositionInReference)
	    for joint in controller.Joints:
		    //save current value

Depending on your statements, you might need to check whether the current statement does have positions. Also, this not 100% tested but works fine for what I want to accomplish and does not rely on actually running a simulation.

Hello, when I read jointvalues from vcPositionFrame those values are correct for the desired robot position and configuration. However when I run the simulation or click on the PTP statement, the robot doesnt go to those joint values but to another ones - same position but different configuration.
Why is this and where can I read and write the jointvalues where robot actually goes?
I tried changing robot configuration in PTP statement properties, this changed the vcPosframe joint values but again not the joint values which robot actually uses (it also changed vcPosframe configuration property).

I could get around this by sending the robot to the “correct” joint values, ie those of vcposframe and then touching up the PTP command. Is there a way to touch up a point via python? Thanks for help

Hello!

For what place does this script save the joint values? How can I use it? Does this make an extra button or something inside the program?

I just saved your lines into a .py format and paste it into the python commands directory.

Hello!

For what place does this script save the joint values? How can I use it? Does this make an extra button or something inside the program?

I just saved your lines into a .py format and paste it into the python commands directory.

Hello!
First of all, this topic hasn’t been updated for a long time, and some of the people in it are no longer active, maybe you can start a new topic for help.
Secondly, about the script, in most of the above scripts do not mention “save values”, they are how to “get values”, the only output action is a print function, but he only outputs to the output table, and this program will not generate any buttons, he is just a built-in python script, if you need, you can use “Ctrl+J” in the python script editing of VC to call up the reference function to find, You can find the way to read and write CSV here, of course, you can also simply save these values directly in the properties of the Component or the numeric signal, if you want to button it, you need to refer to the init.py of most plugins to define your own plugins.
I hope you find this helpful.

If anyone needs Its a shorter form of the same program that WilliamSmith made. Though doesnt fulfill my expectations. Somehow its impossible to synchronize robot path cycle time and sampling interval time to get exactly the joint values from my robot path points.

"from vcScript import *

comp = getComponent()
app = getApplication()
controller = comp.findBehavioursByType(VC_ROBOTCONTROLLER)[0]

SAMPLING_INTERVAL = 0.2

def OnRun():
while app.Simulation.IsRunning:
joints = controller.Joints
print([j.CurrentValue for j in joints])
delay(SAMPLING_INTERVAL)"

Good morning!
If you’re wondering why this code doesn’t accurately get the coordinates of the robot at the path points, that’s for sure, the code is just using a fixed period to get the robot joints from the beginning, if you want to get the joint values at these path points, you can use two methods:
1. You can utilize the OnPostExecuteStatement approach of getting the joint values on the fly, which has the advantage that you can disregard, or think less about, the effects of program bars other than the motion bar, as illustrated in the following example:

from vcScript import *

def printjoints(*n):
  joints = controller.Joints
  print([j.CurrentValue for j in joints])

comp = getComponent()
app = getApplication()
controller = comp.findBehavioursByType(VC_ROBOTCONTROLLER)[0]
exe = comp.findBehavioursByType(VC_ROBOTEXECUTOR)[0]
exe.OnPostExecuteStatement = printjoints

2. You can also use .NET or Python scripts to get the joint values every time you need them, but it’s slightly more complicated, and you also have to consider the problems that come with multiple routines and the problems that come with all kinds of program strips other than the motion strips, but the advantage is that when your program is taking a lot of time to run a process, this approach allows you to just skip over the excessively long runtime and just get the the value you need, simple Python routines are given below:

from vcScript import *
from vcHelpers.Robot2 import *
from vcMatrix import *
def OnSignal( signal ):
  pass

def OnRun():
  pass

comp = getComponent()
robot = getRobot()
exe = comp.findBehavioursByType(VC_ROBOTEXECUTOR)[0]

if not exe.Program.Routines == []:
  for i in exe.Program.Routines:
    pass#Write your function about how to handle multiple subroutines here
else:
  for i in exe.Program.MainRoutine.Statements:
    if i.Scopes != []:
      for j in i.Scopes:
        for z in j.Statements:
          print z.Positions[0].JointValues  

Get_robot_joint_values.vcmx (2.4 MB)