serialRobotInteractiveLimits.py

You can view and download this file on Github: serialRobotInteractiveLimits.py

  1#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2# This is an EXUDYN example
  3#
  4# Details:  Example of a serial robot with redundant coordinates
  5#
  6# Author:   Johannes Gerstmayr
  7# Date:     2020-02-16
  8# Revised:  2023-03-22
  9# Note:     This example uses the redundant mbs approach; The kinematic tree approach would be much faster!
 10#
 11# Copyright:This file is part of Exudyn. Exudyn is free software. You can redistribute it and/or modify it under the terms of the Exudyn license. See 'LICENSE.txt' for more details.
 12#
 13#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 14
 15
 16import exudyn as exu
 17from exudyn.itemInterface import *
 18from exudyn.utilities import * #includes itemInterface and rigidBodyUtilities
 19import exudyn.graphics as graphics #only import if it does not conflict
 20from exudyn.rigidBodyUtilities import *
 21from exudyn.graphicsDataUtilities import *
 22from exudyn.robotics import *
 23from exudyn.robotics.motion import Trajectory, ProfileConstantAcceleration, ProfilePTP
 24from exudyn.interactive import InteractiveDialog
 25
 26import numpy as np
 27from numpy import linalg as LA
 28from math import pi
 29
 30SC = exu.SystemContainer()
 31mbs = SC.AddSystem()
 32
 33sensorWriteToFile = True
 34
 35mbs.variables['controlActive'] = 1 #flag to deactivate control
 36#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 37
 38#now in the new structure
 39
 40mode='newDH'
 41
 42graphicsBaseList = [graphics.Brick([0,0,-0.4], [0.12*1,0.12*1,0.6], graphics.color.grey)]
 43graphicsBaseList +=[graphics.Cylinder([0,0,0], [0.5,0,0], 0.0025, graphics.color.red)]
 44graphicsBaseList +=[graphics.Cylinder([0,0,0], [0,0.5,0], 0.0025, graphics.color.green)]
 45graphicsBaseList +=[graphics.Cylinder([0,0,0], [0,0,0.5], 0.0025, graphics.color.blue)]
 46graphicsBaseList +=[graphics.Cylinder([0,0,-0.1], [0,0,0.1], 0.05, graphics.color.blue)]
 47graphicsBaseList +=[graphics.CheckerBoard([0,0,-0.7], [0,0,1], size=2)]
 48#newRobot.base.visualization['graphicsData']=graphicsBaseList
 49
 50ty = 0.03
 51tz = 0.04
 52zOff = -0.05
 53toolSize= [0.05,0.5*ty,0.06]
 54graphicsToolList = [graphics.Cylinder(pAxis=[0,0,zOff], vAxis= [0,0,tz], radius=ty*1.5, color=graphics.color.red)]
 55graphicsToolList+= [graphics.Brick([0,ty,1.5*tz+zOff], toolSize, graphics.color.grey)]
 56graphicsToolList+= [graphics.Brick([0,-ty,1.5*tz+zOff], toolSize, graphics.color.grey)]
 57
 58
 59#changed to new robot structure July 2021:
 60newRobot = Robot(gravity=[0,0,0*9.81],
 61              base = RobotBase(visualization=VRobotBase(graphicsData=graphicsBaseList)),
 62              tool = RobotTool(HT=HTtranslate([0,0,0.1]), visualization=VRobotTool(graphicsData=graphicsToolList)),
 63             referenceConfiguration = []) #referenceConfiguration created with 0s automatically
 64
 65#modDHKK according to Khalil and Kleinfinger, 1986
 66link0={'stdDH':[0,0,0,pi/2],
 67       'modDHKK':[0,0,0,0],
 68        'mass':20,  #not needed!
 69        'inertia':np.diag([1e-8,0.35,1e-8]), #w.r.t. COM!
 70        'COM':[0,0,0]}
 71
 72link1={'stdDH':[0,0,0.4318,0],
 73       'modDHKK':[0.5*pi,0,0,0],
 74        'mass':17.4,
 75        'inertia':np.diag([0.13,0.524,0.539]), #w.r.t. COM!
 76        'COM':[-0.3638, 0.006, 0.2275]}
 77
 78link2={'stdDH':[0,0.15,0.0203,-pi/2],
 79       'modDHKK':[0,0.4318,0,0.15],
 80        'mass':4.8,
 81        'inertia':np.diag([0.066,0.086,0.0125]), #w.r.t. COM!
 82        'COM':[-0.0203,-0.0141,0.07]}
 83
 84link3={'stdDH':[0,0.4318,0,pi/2],
 85       'modDHKK':[-0.5*pi,0.0203,0,0.4318],
 86        'mass':0.82,
 87        'inertia':np.diag([0.0018,0.0013,0.0018]), #w.r.t. COM!
 88        'COM':[0,0.019,0]}
 89
 90link4={'stdDH':[0,0,0,-pi/2],
 91       'modDHKK':[0.5*pi,0,0,0],
 92        'mass':0.34,
 93        'inertia':np.diag([0.0003,0.0004,0.0003]), #w.r.t. COM!
 94        'COM':[0,0,0]}
 95
 96link5={'stdDH':[0,0,0,0],
 97       'modDHKK':[-0.5*pi,0,0,0],
 98        'mass':0.09,
 99        'inertia':np.diag([0.00015,0.00015,4e-5]), #w.r.t. COM!
100        'COM':[0,0,0.032]}
101linkList=[link0, link1, link2, link3, link4, link5]
102
103for link in linkList:
104    newRobot.AddLink(RobotLink(mass=link['mass'],
105                               COM=link['COM'],
106                               inertia=link['inertia'],
107                               localHT=StdDH2HT(link['stdDH']),
108                               ))
109
110cnt = 0
111for link in newRobot.links:
112    color = graphics.colorList[cnt]
113    color[3] = 0.75 #make transparent
114    link.visualization = VRobotLink(jointRadius=0.06, jointWidth=0.08, showMBSjoint=True, linkWidth=0.05,
115                                    linkColor=color, showCOM= False )
116    cnt+=1
117
118#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
119#configurations and trajectory
120q0 = [0,0,0,0,0,0] #zero angle configuration
121
122# q1 = [0, pi/8, pi*0.75, 0,pi/8,0] #configuration 1
123# q2 = [pi,-pi, -pi*0.5,1.5*pi,-pi*2,pi*2] #configuration 2
124# q3 = [3*pi,0,-0.25*pi,0,0,0] #zero angle configuration
125
126#trajectory generated with optimal acceleration profiles:
127trajectory = Trajectory(initialCoordinates=q0, initialTime=0)
128# trajectory.Add(ProfileConstantAcceleration(q3,0.25))
129# trajectory.Add(ProfileConstantAcceleration(q1,0.25))
130# trajectory.Add(ProfileConstantAcceleration(q2,0.25))
131trajectory.Add(ProfileConstantAcceleration(q0,0.25))
132#traj.Add(ProfilePTP([1,1],syncAccTimes=False, maxVelocities=[1,1], maxAccelerations=[5,5]))
133
134# x = traj.EvaluateCoordinate(t,0)
135
136
137#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
138#test robot model
139#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
140#control parameters, per joint:
141fc=1
142Pcontrol = 0.1*np.array([40000, 40000, 40000, 10*100, 10*100, 10*10])
143Dcontrol = np.array([400,   400,   100,   10*1,   10*1,   10*0.1])
144Pcontrol = fc*Pcontrol
145Dcontrol = fc*Dcontrol
146#soft:
147#Pcontrol = [4000, 4000, 4000, 100, 100, 10]
148#Dcontrol = [40,   40,   10,   1,   1,   0.1]
149
150#desired angles:
151qE = q0
152qE = q0
153tStart = [0,0,0, 0,0,0]
154duration = 0.1
155
156
157jointList = [0]*newRobot.NumberOfLinks() #this list must be filled afterwards with the joint numbers in the mbs!
158
159def ComputeMBSstaticRobotTorques(newRobot):
160    q=[]
161    for joint in jointList:
162        q += [mbs.GetObjectOutput(joint, exu.OutputVariableType.Rotation)[2]] #z-rotation
163    HT=newRobot.JointHT(q)
164    return newRobot.StaticTorques(HT)
165
166#++++++++++++++++++++++++++++++++++++++++++++++++
167#base, graphics, object and marker:
168
169objectGround = mbs.AddObject(ObjectGround(referencePosition=HT2translation(newRobot.GetBaseHT()),
170                                      #visualization=VObjectGround(graphicsData=graphicsBaseList)
171                                          ))
172
173
174#baseMarker; could also be a moving base!
175baseMarker = mbs.AddMarker(MarkerBodyRigid(bodyNumber=objectGround, localPosition=[0,0,0]))
176
177
178
179#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
180#build mbs robot model:
181robotDict = newRobot.CreateRedundantCoordinateMBS(mbs, baseMarker=baseMarker)
182
183jointList = robotDict['jointList'] #must be stored there for the load user function
184
185unitTorques0 = robotDict['unitTorque0List'] #(left body)
186unitTorques1 = robotDict['unitTorque1List'] #(right body)
187
188loadList0 = robotDict['jointTorque0List'] #(left body)
189loadList1 = robotDict['jointTorque1List'] #(right body)
190#print(loadList0, loadList1)
191
192
193#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
194#add CartesianSpringDamper for mouse drag
195gripperBody=robotDict['bodyList'][-1]
196gripperLength = 0.1 #in z-direction
197markerGripper = mbs.AddMarker(MarkerBodyPosition(bodyNumber=gripperBody, localPosition=[0,0,gripperLength]))
198markerGround0 =  mbs.AddMarker(MarkerBodyPosition(bodyNumber=objectGround))
199
200# def UFcartesianSD(mbs, t, itemNumber, displacement, velocity, stiffness, damping, offset):
201#     if mbs.variables['controlActive']:
202#         return [0,0,0]
203#     else:
204#         p = SC.GetCurrentMouseCoordinates(True) #True=OpenGL coordinates; 2D
205#         A = np.array(SC.GetRenderState()['modelRotation'])
206#         # print('p=',p)
207#         # print('u=',displacement)
208#         p3D = A@np.array([p[0],p[1],0.])
209
210#         dp = displacement-p3D
211#         f = [stiffness[0]*dp[0], stiffness[1]*dp[1], stiffness[2]*dp[2]]
212#         return f
213
214
215kSD = 50000*0.1
216dSD = kSD*0.01 #damping included in robot
217gripperSD = mbs.AddObject(CartesianSpringDamper(markerNumbers=[markerGround0, markerGripper],
218                                                stiffness=[kSD,kSD,kSD],
219                                                damping=[dSD,dSD,dSD],
220                                                #springForceUserFunction=UFcartesianSD,
221                                                visualization=VCartesianSpringDamper(show=False), #do not show, looks weird
222                                                ))
223mbs.variables['gripperSD'] = gripperSD
224
225#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
226#test for joint limits:
227limits = []
228def UFtsd(mbs, t, itemNumber, rotation, angularVelocity, stiffness, damping, offset):
229    f = 0.
230    if False and mbs.variables['controlActive']:
231        f = stiffness*rotation + damping*angularVelocity
232    else:
233        limTSD = limits[itemNumber]
234        if rotation > limTSD[1]:
235            f = 50*stiffness*(rotation-limTSD[1])**2 + stiffness*(rotation-offset) + damping*angularVelocity
236        elif rotation < limTSD[0]:
237            f = -50*stiffness*(rotation-limTSD[0])**2 + stiffness*(rotation-offset) + damping*angularVelocity
238        else:
239            f = stiffness*(rotation-offset) + damping*angularVelocity
240    return f
241
242useUserFunction = 1
243if not useUserFunction:
244    UFtsd = 0
245
246#control robot
247compensateStaticTorques = False
248torsionalSDlist = []
249nGenericList = []
250limits = [[0.,0.]]*mbs.systemData.NumberOfObjects()
251limits += [[-0.75*pi,0.75*pi],
252           [ 0.0*pi,1.0*pi],
253           [-1.0*pi,0.4*pi],
254           [-0.5*pi,0.5*pi],
255           [-0.5*pi,0.5*pi],
256           [-0.5*pi,0.5*pi],
257           ]
258for i in range(len(jointList)):
259    joint = jointList[i]
260    rot0 = mbs.GetObject(joint)['rotationMarker0']
261    rot1 = mbs.GetObject(joint)['rotationMarker1']
262    markers = mbs.GetObject(joint)['markerNumbers']
263
264    nGeneric=mbs.AddNode(NodeGenericData(initialCoordinates=[0],
265                                         numberOfDataCoordinates=1)) #for infinite rotations
266    nGenericList += [nGeneric]
267    tsd = mbs.AddObject(TorsionalSpringDamper(markerNumbers=markers,
268                                        nodeNumber=nGeneric,
269                                        rotationMarker0=rot0,
270                                        rotationMarker1=rot1,
271                                        stiffness=Pcontrol[i],
272                                        damping=Dcontrol[i],
273                                        springTorqueUserFunction=UFtsd,
274                                        visualization=VTorsionalSpringDamper(drawSize=0.1)
275                                        ))
276    torsionalSDlist += [tsd]
277
278
279#user function which is called only once per step, speeds up simulation drastically
280def PreStepUF(mbs, t):
281
282    # print('nG=',end='')
283    # for i in nGenericList:
284    #     q = mbs.GetNodeOutput(i, exu.OutputVariableType.Coordinates)
285    #     print(round(q,4),', ',end='')
286    # print('')
287
288    #additional static torque compensation; P and D control in TSD:
289    if not mbs.variables['controlActive']:
290        p = SC.GetCurrentMouseCoordinates(True) #True=OpenGL coordinates; 2D
291        A = np.array(SC.GetRenderState()['modelRotation'])
292        p3D = A@np.array([p[0],p[1],0.])
293
294        offset = p3D
295        mbs.SetObjectParameter(mbs.variables['gripperSD'], 'offset', offset)
296        mbs.SetObjectParameter(mbs.variables['gripperSD'], 'activeConnector', True)
297    else:
298        mbs.SetObjectParameter(mbs.variables['gripperSD'], 'activeConnector', False)
299
300    #with control:
301    if compensateStaticTorques:
302        staticTorques = ComputeMBSstaticRobotTorques(newRobot)
303        #print("tau=", staticTorques)
304    else:
305        staticTorques = np.zeros(len(jointList))
306
307
308    [u,v,a] = trajectory.Evaluate(t)
309
310    fact = 1.
311    if mbs.variables['controlActive']==2:
312        fact =1. #0.1 #soft reset ...
313
314    #compute load for joint number
315    for i in range(len(jointList)):
316        joint = jointList[i]
317        phi = mbs.GetObjectOutput(joint, exu.OutputVariableType.Rotation)[2] #z-rotation
318        omega = mbs.GetObjectOutput(joint, exu.OutputVariableType.AngularVelocityLocal)[2] #z-angular velocity
319        #[u1,v1,a1] = MotionInterpolator(t, robotTrajectory, i)
320        tsd = torsionalSDlist[i]
321        if mbs.variables['controlActive'] or i>=3:
322            mbs.SetObjectParameter(tsd, 'torque', staticTorques[i]) #additional torque from given velocity; positive sign from Exudyn 1.2.38 onwards
323            mbs.SetObjectParameter(tsd, 'stiffness', Pcontrol[i]*fact)
324            mbs.SetObjectParameter(tsd, 'damping', Dcontrol[i]*1)
325
326    # with mouse drag:
327    for i in range(len(jointList)):
328        if not (mbs.variables['controlActive'] or i>=3):
329            tsd = torsionalSDlist[i]
330            #keep damping, but deactivate stiffness
331            mbs.SetObjectParameter(tsd, 'torque', 0)
332            #mbs.SetObjectParameter(tsd, 'stiffness', 0)
333            mbs.SetObjectParameter(tsd, 'damping', Dcontrol[i]*0.1) #keep small damping to improve drag!
334
335    return True
336
337mbs.SetPreStepUserFunction(PreStepUF)
338
339
340# mbs.variables['q0Current'] = q0[0]
341for i in range(6):
342    mbs.variables['q{}Current'.format(i)] = q0[i]
343
344#add sensors:
345cnt = 0
346for i in range(len(jointList)):
347    jointLink = jointList[i]
348    tsd = torsionalSDlist[i]
349    sJointRot = mbs.AddSensor(SensorObject(objectNumber=tsd,
350                               fileName="solution/joint" + str(cnt) + "Rot.txt",
351                               outputVariableType=exu.OutputVariableType.Rotation,
352                               writeToFile = sensorWriteToFile))
353    sJointAngVel = mbs.AddSensor(SensorObject(objectNumber=jointLink,
354                               fileName="solution/joint" + str(cnt) + "AngVel.txt",
355                               outputVariableType=exu.OutputVariableType.AngularVelocityLocal,
356                               writeToFile = sensorWriteToFile))
357    cnt+=1
358
359cnt = 0
360jointTorque0List = []
361for load0 in robotDict['jointTorque0List']:
362    sTorque = mbs.AddSensor(SensorLoad(loadNumber=load0, fileName="solution/jointTorque" + str(cnt) + ".txt",
363                                       writeToFile = sensorWriteToFile))
364    jointTorque0List += [sTorque]
365    cnt+=1
366
367
368
369
370def GetPoseString(q):
371    strx = '   x = ['
372    strphi = 'phi = ['
373    HT = newRobot.JointHT(q)[-1]
374    t = np.round(HT[0:3,-1], 4)
375    R = HT[0:3,0:3]
376    phi = np.round(RotationMatrix2RotXYZ(R),3)
377
378    for i in range(2):
379        strx += '{},\t'.format(t[i])
380        strphi += '{},\t'.format(phi[i])
381
382    strx += '{}]'.format(t[-1])
383    strphi += '{}]'.format(phi[-1])
384    diffLen = len(strx) - len(strphi)
385    if diffLen > 0:
386        strphi += ' '*diffLen
387    elif diffLen < 0:
388        strx += ' '*diffLen
389
390    return strx + '\n' + strphi
391
392#define items for dialog
393fAngle=2.
394dialogItems = [{'type':'label', 'text':'Angle 1', 'grid':(0,0,2), 'options':['L']},
395               {'type':'slider', 'range': (-fAngle*3.14, fAngle*3.14), 'value':q0[0], 'steps':628, 'variable':'q0Current', 'grid':(0,1)},
396               {'type':'label', 'text':'Angle 2:', 'grid':(1,0)},
397               {'type':'slider', 'range': (-fAngle*3.14, fAngle*3.14), 'value':q0[1], 'steps':628, 'variable':'q1Current', 'grid':(1,1)},
398               {'type':'label', 'text':'Angle 3:', 'grid':(2,0)},
399               {'type':'slider', 'range': (-fAngle*3.14, fAngle*3.14), 'value':q0[2], 'steps':628, 'variable':'q2Current', 'grid':(2,1)},
400               {'type':'label', 'text':'Angle 4:', 'grid':(3,0)},
401               {'type':'slider', 'range': (-fAngle*3.14, fAngle*3.14), 'value':q0[3], 'steps':628, 'variable':'q3Current', 'grid':(3,1)},
402               {'type':'label', 'text':'Angle 5:', 'grid':(4,0)},
403               {'type':'slider', 'range': (-fAngle*3.14, fAngle*3.14), 'value':q0[4], 'steps':628, 'variable':'q4Current', 'grid':(4,1)},
404               {'type':'label', 'text':'Angle 6:', 'grid':(5,0)},
405               {'type':'slider', 'range': (-fAngle*3.14, fAngle*3.14), 'value':q0[5], 'steps':628, 'variable':'q5Current', 'grid':(5,1)},
406               {'type': 'label', 'text': 'Position:', 'grid': (6,0)},
407               {'type': 'label', 'text': '{}'.format(GetPoseString(q0)), 'grid': (6,1)},
408               {'type':'radio', 'textValueList':[('Mouse drag',0),('Control on',1),('Reset',2)], 'value':1, 'variable':'controlActive',
409                'grid': [(7,0),(7,1),(7,2)]}
410               #{'type':'button', 'text':'test button','callFunction':ButtonCall, 'grid':(7,0,2)},
411               ]
412
413
414mbs.Assemble()
415#mbs.systemData.Info()
416
417SC.visualizationSettings.connectors.showJointAxes = True
418SC.visualizationSettings.connectors.jointAxesLength = 0.02
419SC.visualizationSettings.connectors.jointAxesRadius = 0.002
420
421SC.visualizationSettings.nodes.showBasis = True
422SC.visualizationSettings.nodes.basisSize = 0.1
423SC.visualizationSettings.loads.show = False
424
425SC.visualizationSettings.openGL.multiSampling=4
426SC.visualizationSettings.openGL.shadow=0.3
427SC.visualizationSettings.openGL.perspective=0.7
428
429tEnd = 1.25
430h = 0.0005
431
432#mbs.WaitForUserToContinue()
433simulationSettings = exu.SimulationSettings() #takes currently set values or default values
434
435simulationSettings.solutionSettings.solutionInformation = 'Hanging Robot Interactive Example'
436
437
438simulationSettings.timeIntegration.numberOfSteps = int(tEnd/h)
439simulationSettings.timeIntegration.endTime = tEnd
440simulationSettings.solutionSettings.solutionWritePeriod = h*1
441simulationSettings.solutionSettings.sensorsWritePeriod = h*10
442simulationSettings.solutionSettings.binarySolutionFile = True
443simulationSettings.timeIntegration.verboseMode = 0
444#simulationSettings.solutionSettings.writeSolutionToFile = False
445# simulationSettings.timeIntegration.simulateInRealtime = True
446# simulationSettings.timeIntegration.realtimeFactor = 0.25
447simulationSettings.solutionSettings.writeInitialValues = False
448
449simulationSettings.displayComputationTime = False
450simulationSettings.displayStatistics = False
451# simulationSettings.linearSolverType = exu.LinearSolverType.EigenSparse
452# simulationSettings.timeIntegration.generalizedAlpha.computeInitialAccelerations=False
453
454#simulationSettings.timeIntegration.newton.useModifiedNewton = True
455simulationSettings.timeIntegration.generalizedAlpha.useIndex2Constraints = False
456simulationSettings.timeIntegration.generalizedAlpha.useNewmark = simulationSettings.timeIntegration.generalizedAlpha.useIndex2Constraints
457simulationSettings.timeIntegration.newton.useModifiedNewton = True
458
459SC.visualizationSettings.window.renderWindowSize=[1920,1200]
460SC.visualizationSettings.general.graphicsUpdateInterval=0.005
461
462#this is an exemplariy simulation function, which adjusts some values for simulation
463def SimulationUF(mbs, dialog):
464    q = []
465    for i in range(6):
466        qi = mbs.variables['q{}Current'.format(i)] #not possible to update this variable
467        #qi = dialog.sliderVariables[i].get()
468        mbs.SetObjectParameter(torsionalSDlist[i],'offset',qi)
469        theta = mbs.GetObjectOutput(torsionalSDlist[i],exu.OutputVariableType.Rotation)
470        #q += [mbs.variables['q{}Current'.format(i)]]
471        q += [1.*theta] #current rotation
472    #dialog.dialogItems[-1]['text'] = GetPoseString(q)
473
474    if mbs.variables['controlActive'] == 2:
475        for i in range(6):
476            q[i] = 0
477            mbs.variables['q{}Current'.format(i)] = 0
478            dialog.widgets[2*i+1].set(q[i])
479
480    dialog.labelStringVariables[-1].set(GetPoseString(q))
481
482    if not mbs.variables['controlActive']:
483        for i in range(6):
484            #dialog.sliderVariables[i].set(q[i])
485            dialog.widgets[2*i+1].set(q[i])
486    #print(q)
487
488SC.visualizationSettings.general.autoFitScene = False #use loaded render state
489exu.StartRenderer()
490if 'renderState' in exu.sys:
491    SC.SetRenderState(exu.sys[ 'renderState' ])
492
493InteractiveDialog(mbs=mbs, simulationSettings=simulationSettings,
494                  simulationFunction=SimulationUF,
495                  title='Interactive window',
496                  dialogItems=dialogItems, period=0.01, realtimeFactor=4, #realtime is only approx. (does not include time lost for computation ==> 2 is a good choice)
497                  runOnStart=True,
498                  addLabelStringVariables=True,
499                  #addSliderVariables=True
500                  )
501
502exu.StopRenderer()
503
504if 0:
505    if useGraphics:
506        exu.StartRenderer()
507        if 'renderState' in exu.sys:
508            SC.SetRenderState(exu.sys['renderState'])
509        mbs.WaitForUserToContinue()
510
511    mbs.SolveDynamic(simulationSettings, showHints=True)
512
513
514    if useGraphics:
515        SC.visualizationSettings.general.autoFitScene = False
516        exu.StopRenderer()
517
518
519    mbs.SolutionViewer()
520
521    lastRenderState = SC.GetRenderState() #store model view
522
523    #compute final torques:
524    measuredTorques=[]
525    for sensorNumber in jointTorque0List:
526        measuredTorques += [mbs.GetSensorValues(sensorNumber)[2]]
527    exu.Print("torques at tEnd=", VSum(measuredTorques))
528
529
530
531    if True:
532        import matplotlib.pyplot as plt
533        import matplotlib.ticker as ticker
534        plt.rcParams.update({'font.size': 14})
535        plt.close("all")
536
537        doJointTorques = False
538        if doJointTorques:
539            for i in range(6):
540                data = np.loadtxt("solution/jointTorque" + str(i) + ".txt", comments='#', delimiter=',')
541                plt.plot(data[:,0], data[:,3], PlotLineCode(i), label="joint torque"+str(i)) #z-rotation
542
543            plt.xlabel("time (s)")
544            plt.ylabel("joint torque (Nm)")
545            ax=plt.gca() # get current axes
546            ax.grid(True, 'major', 'both')
547            ax.xaxis.set_major_locator(ticker.MaxNLocator(10))
548            ax.yaxis.set_major_locator(ticker.MaxNLocator(10))
549            plt.tight_layout()
550            ax.legend(loc='center right')
551            plt.show()
552            # plt.savefig("solution/robotJointTorques.pdf")
553
554        doJointAngles = True
555        if doJointAngles:
556            plt.close("all")
557
558            for i in range(6):
559                data = np.loadtxt("solution/joint" + str(i) + "Rot.txt", comments='#', delimiter=',')
560                plt.plot(data[:,0], data[:,1], PlotLineCode(i), label="joint"+str(i)) #z-rotation
561
562            plt.xlabel("time (s)")
563            plt.ylabel("joint angle (rad)")
564            ax=plt.gca()
565            ax.grid(True, 'major', 'both')
566            ax.xaxis.set_major_locator(ticker.MaxNLocator(10))
567            ax.yaxis.set_major_locator(ticker.MaxNLocator(10))
568            plt.tight_layout()
569            ax.legend()
570            plt.rcParams.update({'font.size': 16})
571            plt.show()
572            # plt.savefig("solution/robotJointAngles.pdf")