I am rather new to python programming and I’m struggling with modelling this component:
I have modelled my own belt conveyor and now I want to connect different signals to it and each signal triggers a different movement eg., moving a belt to adjust to the size of the product.
I don’t know how to program the script so that it waits until a signal is triggered and then move the respective joint (with servo.moveJoint(0,…)). I’ve already tried using onSignal (signal) or conditiontrigger (in a while loop) and if…elif inside a while loop but with no success.
For what I’ve learned so far:
-onSignal doesn’t let me use commands for movement that need time like .movejoint.
-conditiontrigger looks like it needs to be executed in the order or if not it won’t enter on the next conditiontrigger
-the if… elif option gets the program hooked.
Use a while loop,
inside it,
if you need a positive or negative trigger (rising/falling edge) =>
triggerCondition(lambda: getTrigger() == yourSignal and yourSignal.Value)
if you do not need a trigger, but simply wait until a value is something, and the value change could have already happend =>
condition(lambda: yourSignal.Value)
In OnSignal, you are correct, you are not allowed to spend simulation time, e.g. moving a servo, unless it is immediate motions.
Thanks for your answer. I tried the triggerCondition method inside a while loop as follows:
#WHILE LOOP INSIDE DEF ONRUN()
while sim.IsRunning == True:
#MOVEMENT OF STOPS:
triggerCondition ( lambda:getTrigger()==sensorSignal and sensorSignal.Value)
servo.moveJoint(0,30)
triggerCondition ( lambda:getTrigger()==sensorSignal and sensorSignal.Value==False)
servo.moveJoint(0,0)
#MOVEMENT OF BELTS IN X AXIS:
triggerCondition ( lambda:getTrigger()==PresetSignal and PresetSignal.Value)
servo2.moveJoint(0,-180)
triggerCondition ( lambda:getTrigger()==PresetSignal and PresetSignal.Value==False)
servo2.moveJoint(0,0)
As I said, when I try this method looks like I must run the script in order. If I try to trigger the “PresetSignal” before “sensorSignal” it does nothing. Any ideas on how to solve it?
Aha yes, you must have them in order, you can solve it in 2 ways,
either you do something like:
triggerCondition ( lambda:getTrigger() in [sensorSignal, PresetSignal ])
if sensorSignal.Value:
doSomething
elif not sensorSignal.Value:
do something else
elif PresetSignal .Value:
do something else
etc.
or you create a queue in OnRun:
def OnSignal(signal):
if signal == sensorSignal and sensorSignal .Value:
queue.append((0,30))
elif signal == sensorSignal and not sensorSignal .Value:
queue.append((0,0))
def OnRun():
global queue
queue = []
while True:
condition(lambda: queue)
target = queue.pop(0)
servo2.moveJoint(target[0], target[1])
I tried out the first one and it worked perfectly fine although I had to change one elif since it wasn’t working at first somehow. Here’s the code:
while sim.IsRunning == True:
triggerCondition ( lambda:getTrigger() in [sensorSignal,PresetSignal])
#MOVEMENT OF STOPS:
if PresetSignal.Value:
servo2.moveJoint(0,-180)
elif PresetSignal.Value==False:
servo2.moveJoint(0,0)
#MOVEMENT OF BELTS IN X AXIS
if sensorSignal.Value:
servo.moveJoint(0,30)
elif sensorSignal.Value==False:
servo.moveJoint(0,0)
By the way, when do you recommend to use more than one python script for a component?
For virtual commissioning purposes I have many inputs/outputs per component that may happen in parallel so I was wondering if it was wise to use more than one python script.
Hi, remember that each script, creates like a sandbox (uses system resources), so the more is not merrier. Only have more then one, if you have things that require parallel execution that is not solvable in 1 thread so to speak.
Continuing with the thread, I have the following problem. I have to wait for many signals that can trigger a servo movement at any time. So after troubleshooting for some time, I found a way of doing so in the same script with the same servo controller, although it is quite tedious since I have to write a if…elif…condition for every single signal, and I could have up to 80 signals in one component.
Could you experts tell me if there is a more eficient way of programming the component? I tried with a for loop and entering the signals into a list but it didn’t work out.
Have I done well by writing everything in a single script or maybe it’s better to separate some of the signals in more components and have more scripts?
Thanks in advance. The code would be like the following:
from vcScript import *
app = getApplication()
sim = app.Simulation
comp = getComponent()
sensorSignal=comp.findBehaviour('BooleanSignal')
signal_1=comp.findBehaviour('Signal1')
...................
...................
signal_12=comp.findBehaviour('Signal12')
...........
servo = comp.findBehaviour("Servo Controller")
def OnSignal(signal):
suspendRun()
global go
go=True
resumeRun()
def OnRun():
global go
while sim.IsRunning == True:
triggerCondition ( lambda:go==True)
if sensorSignal.Value:
servo.setJointTarget(0,30)
elif sensorSignal.Value==False:
servo.setJointTarget(0,0)
if signal_1.Value:
servo.setJointTarget(1,30)
elif signal_1.Value==False:
servo.setJointTarget(1,0)
if signal_2.Value:
servo.setJointTarget(2,30)
elif signal_2.Value==False:
servo.setJointTarget(2,0)
..................................................................
if signal_12.Value:
servo.setJointTarget(12,30)
elif signal_12.Value==False:
servo.setJointTarget(12,0)
............................................................
servo.move()
go=False
You could create a dictonary object with signal name as key and target as list value, then you just do loop the signals. e.g. sevoDict[signal.Name] = [jointIndex, positiveValue, negativeValue] = [0,30,0]
signals = list of all your signals
for signal in signals:
joint_target_list = sevoDict[signal.Name]
target = joint_target_list[1] if signal.Value else joint_target_list[2]
servo.setJointTarget(joint_target_list[0], target)
servo.move()
isntead of the go part, you could just do triggerCondition ( lambda: getTrigger() in signals)