You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A long time ago, we discussed using coroutines for sequential behaviors, but it required a lot of boilerplate code in Python 2.7. With Python 3 the yield from keyword fixes the problem.
Here is a toy example. We first need a few library functions. The "payoff" is in the complete behavior takeoff_circle_land which would be somewhat cumbersome to implement as a state machine. Note how easy it is to have one control policy sleeping while executing a high level command while others are sending low-level setpoints in a fast loop.
I am leaving this in discussion for now because the example is not complicated enough to stress the library design. If anyone validates/fixes the design in a more complex project, we can promote it to an example script.
"""EXPERIMENTAL: Example of coroutines as an alternative to state machines.We use the term 'control coroutine' , abbreviated 'coco', for a Pythongenerator whose inputs are floating-point time values. These generators can beused to implement sequential behaviors with internal state that might becomecumbersome for a a state-machine-based implementation."""importnumpyasnpfrompycrazyswarmimport*defbegin_at_zero(coco_maker):
"""Decorator for shifting the time argument of a control coroutine. Inside the control coroutine, the first value of `yield` will be zero, no matter the current real time. """defcoco_wrapper(*args, **kwargs):
coco=coco_maker(*args, **kwargs)
coco.send(None)
t=yieldt0=ttry:
whileTrue:
t=yieldcoco.send(t-t0)
exceptStopIteration:
returnreturncoco_wrapper@begin_at_zerodefellipse(cf, center, major, minor, period):
"""Infinite (never stops yielding) control coroutine for ellipse."""# Scale factors.s=2*np.pi/periods2=s*swhileTrue:
t=yieldcos=np.cos(s*t)
sin=np.sin(s*t)
pos= (cos*major) + (sin*minor) +centervel=-(s*sin*major) + (s*cos*minor)
acc=-(s2*cos*major) - (s2*sin*minor)
# TODO: Compute the proper value of omega by extracting the needed math# into a standalone function in uav_trajectory.py.omega=np.zeros(3)
cf.cmdFullState(
pos,
vel,
acc,
yaw=0.0,
omega=omega,
)
@begin_at_zerodeftruncate(coco, duration):
"""Executes an infinite control coroutine for a finite duration."""coco.send(None)
t=yieldwhilet<=duration:
coco.send(t)
t=yield@begin_at_zerodefsleep(duration):
"""Coroutine version of timeHelper.sleep() for high-level commands."""t=yieldwhilet<=duration:
t=yielddefpoll_cocos(cocos, timeHelper, rateHz):
"""Executes a set of control coroutines."""forcocoincocos:
coco.send(None)
whileTrue:
t=timeHelper.time()
n_done=0forcocoincocos:
try:
coco.send(t)
exceptStopIteration:
n_done+=1ifn_done==len(cocos):
breaktimeHelper.sleep(1.0/rateHz)
deftakeoff_circle_land(cf, loops):
"""Example of a sequential behavior."""print(f"cf{cf.id} taking off.")
cf.takeoff(1.0, duration=3.0)
yieldfromsleep(4.0)
print(f"cf{cf.id} beginning circle.")
major=np.array([1.0, 0.0, 0.0])
minor=np.array([0.0, 1.0, 0.0])
center=cf.position() -majorperiod=12.0yieldfromtruncate(
ellipse(cf, center, major, minor, period),
duration=loops*period
)
print(f"cf{cf.id} landing.")
cf.notifySetpointsStop()
cf.land(0.05, duration=3.0)
yieldfromsleep(4.0)
defmain():
crazyflies_yaml=""" crazyflies: - channel: 100 id: 1 initialPosition: [1.0, 0.0, 0.0] - channel: 100 id: 2 initialPosition: [0.0, -1.0, 0.0] """swarm=Crazyswarm(crazyflies_yaml=crazyflies_yaml)
timeHelper=swarm.timeHelperallcfs=swarm.allcfscfs=allcfs.crazyfliescocos= [
takeoff_circle_land(cf, loops=i+1)
fori, cfinenumerate(cfs)
]
poll_cocos(cocos, timeHelper, rateHz=30)
if__name__=="__main__":
main()
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
A long time ago, we discussed using coroutines for sequential behaviors, but it required a lot of boilerplate code in Python 2.7. With Python 3 the
yield from
keyword fixes the problem.Here is a toy example. We first need a few library functions. The "payoff" is in the complete behavior
takeoff_circle_land
which would be somewhat cumbersome to implement as a state machine. Note how easy it is to have one control policysleep
ing while executing a high level command while others are sending low-level setpoints in a fast loop.I am leaving this in discussion for now because the example is not complicated enough to stress the library design. If anyone validates/fixes the design in a more complex project, we can promote it to an example script.
Beta Was this translation helpful? Give feedback.
All reactions