## For instruction on writing tutorials ## http://www.ros.org/wiki/WritingTutorials #################################### ##FILL ME IN #################################### ## for a custom note with links: ## note = ## for the canned note of "This tutorial assumes that you have completed the previous tutorials:" just add the links ## note.0= [[executive_teer/Tutorials/Wait Conditions|Wait for Conditions]] ## descriptive title for the tutorial ## title = Pause and Resume Tasks ## multi-line description to be displayed in search ## description = This tutorial shows how to pause and resume a list of tasks. ## the next tutorial description (optional) ## next = ## links to next tutorial (optional) ## next.0.link=[[executive_teer/Tutorials/On Termination|React On Termination]] ## next.1.link= ## what level user is this tutorial for ## level= BeginnerCategory ## keywords = #################################### <<IncludeCSTemplate(TutorialCSHeaderTemplate)>> In teer, a task can pause or resume other tasks. This tutorial shows an example of these functions. Like the [[executive_teer/Tutorials/Wait Conditions|previous tutorial]], this one requires [[turtlesim]]. In this tutorial, two turtles move in squares of opposite directions. When turtles meet, they fall in love, forget about their doing, and dance for a while; then they become bored and get back to business. This tutorial is based on [[https://github.com/ethz-asl/executive_teer/blob/master/teer_example_turtle/src/turtle_dating.py|turtle_dating.py]] from [[teer_example_turtle]]. First, we import the packages and create the scheduler, this time with two condition variables, one for the pose of each turtle: {{{ #!Python #!/usr/bin/env python import math import roslib; roslib.load_manifest('teer_tutorials') import rospy import numpy as np from turtlesim.msg import Velocity from turtlesim.msg import Pose from turtlesim.srv import TeleportAbsolute from turtlesim.srv import SetPen from turtlesim.srv import Spawn from std_srvs.srv import Empty as EmptyServiceCall from turtle_math import * from teer_ros import * class TurtleScheduler(Scheduler): turtle1_pose = ConditionVariable(None) turtle2_pose = ConditionVariable(None) def __init__(self): super(TurtleScheduler,self).__init__() }}} Like in the previous example, turtle move using two tasks each (`turtleN_go` and `turtleN_wandering`): {{{ #!Python def turtle1_go(target): while True: # set new speed commands turtle1_velocity.publish(control_command(sched.turtle1_pose, target, 1.0)) # wait for 1 s yield WaitDuration(0.5) def turtle2_go(target): while True: # set new speed commands turtle2_velocity.publish(control_command(sched.turtle2_pose, target, 0.7)) # wait for 1 s yield WaitDuration(0.5) def turtle1_wandering(): yield WaitCondition(lambda: sched.turtle1_pose is not None) targets = [(2,2), (9,2), (9,9), (2,9)] target_id = 0 while True: sched.printd('Going to ' + str(targets[target_id])) target = targets[target_id] go_tid = sched.new_task(turtle1_go(target)) yield WaitCondition(lambda: dist(sched.turtle1_pose, target) < 0.1) sched.kill_task(go_tid) target_id = (target_id + 1) % len(targets) def turtle2_wandering(): yield WaitCondition(lambda: sched.turtle2_pose is not None) targets = [(2,9), (9,9), (9,2), (2,2)] target_id = 0 while True: sched.printd('Going to ' + str(targets[target_id])) target = targets[target_id] go_tid = sched.new_task(turtle2_go(target)) yield WaitCondition(lambda: dist(sched.turtle2_pose, target) < 0.1) sched.kill_task(go_tid) target_id = (target_id + 1) % len(targets) }}} In addition, a fifth task, `cupidon`, waits until turtles are close enough, pauses their tasks, makes them dance, and resumes their tasks afterwards: {{{ #!Python def cupidon(): my_tid = sched.get_current_tid() while True: yield WaitCondition(lambda: dist(sched.turtle1_pose, sched.turtle2_pose) < 1) sched.printd('Found friend, let\'s dance') paused_tasks = sched.pause_all_tasks_except([my_tid]) turtle1_set_pen(255,0,0,0,0) turtle2_set_pen(0,255,0,0,0) for i in range(7): turtle1_velocity.publish(Velocity(1, 1)) turtle2_velocity.publish(Velocity(1, -1)) yield WaitDuration(0.9) turtle1_set_pen(0,0,0,0,1) turtle2_set_pen(0,0,0,0,1) sched.printd('Tired of dancing, going back to wandering') sched.resume_tasks(paused_tasks) yield WaitDuration(10) }}} Finally, we just have to create the callbacks and the main function with the glue to connect to ROS: {{{ #!Python def turtle1_pose_updated(new_pose): sched.turtle1_pose = new_pose def turtle2_pose_updated(new_pose): sched.turtle2_pose = new_pose if __name__ == '__main__': # create scheduler sched = TurtleScheduler() sched.new_task(turtle1_wandering()) sched.new_task(turtle2_wandering()) sched.new_task(cupidon()) # connect to turtlesim rospy.init_node('teer_example_turtle') # services rospy.wait_for_service('reset') reset_simulator = rospy.ServiceProxy('reset', EmptyServiceCall) reset_simulator() rospy.wait_for_service('clear') clear_background = rospy.ServiceProxy('clear', EmptyServiceCall) spawn_turtle = rospy.ServiceProxy('spawn', Spawn) spawn_turtle(0,0,0, "turtle2") rospy.wait_for_service('turtle1/set_pen') turtle1_set_pen = rospy.ServiceProxy('turtle1/set_pen', SetPen) rospy.wait_for_service('turtle1/teleport_absolute') turtle1_teleport = rospy.ServiceProxy('turtle1/teleport_absolute', TeleportAbsolute) rospy.wait_for_service('turtle2/set_pen') turtle2_set_pen = rospy.ServiceProxy('turtle2/set_pen', SetPen) rospy.wait_for_service('turtle2/teleport_absolute') turtle2_teleport = rospy.ServiceProxy('turtle2/teleport_absolute', TeleportAbsolute) # subscriber/publisher rospy.Subscriber('turtle1/pose', Pose, turtle1_pose_updated) turtle1_velocity = rospy.Publisher('turtle1/command_velocity', Velocity) rospy.Subscriber('turtle2/pose', Pose, turtle2_pose_updated) turtle2_velocity = rospy.Publisher('turtle2/command_velocity', Velocity) # setup environment turtle1_set_pen(0,0,0,0,1) turtle2_set_pen(0,0,0,0,1) turtle1_teleport(2,2,0) turtle2_teleport(2,9,0) clear_background() # run scheduler sched.run() }}} ## AUTOGENERATED DO NOT DELETE ## TutorialCategory ## FILL IN THE STACK TUTORIAL CATEGORY HERE