Part 5 Camera Sweep Action Client¶
Copy all the code below into your move_client.py file.  Then, review the code annotations to understand how it all works.
(Oh, and DFTS!)
#!/usr/bin/env python3
import rospy # (1)!
import actionlib # (2)!
from tuos_msgs.msg import CameraSweepAction, CameraSweepGoal, CameraSweepFeedback # (3)!
node_name = "camera_sweep_action_client"
action_server_name = "/camera_sweep_action_server"
captured_images = 0
def feedback_callback(feedback_data: CameraSweepFeedback): # (4)!
    global captured_images
    captured_images = feedback_data.{BLANK}
    print(f"FEEDBACK: Current yaw: {feedback_data.current_angle:.1f} degrees. "
          f"Image(s) captured so far: {captured_images}...")
rospy.init_node(node_name) # (5)!
client = actionlib.SimpleActionClient(action_server_name, 
            CameraSweepAction) # (6)!
client.wait_for_server() # (7)!
goal = CameraSweepGoal()
goal.sweep_angle = 0
goal.image_count = 0
client.send_goal(goal, feedback_cb=feedback_callback) # (8)!
client.wait_for_result() # (9)!
print(f"RESULT:") # (10)!
print(f"  * Action State = {client.get_state()}")
print(f"  * {captured_images} images saved to {client.get_result()}")
- 
As you know by now, in order to develop ROS nodes using Python we need to use the rospylibrary.
- 
If we want to work with ROS Actions, we also need to import actionlib.
- 
We know that the /camera_sweep_action_serverusesCameraSweepActionmessages from thetuos_msgspackage, so we import the full message definition:CameraSweepActionas well as theGoalmessage (which we use to actually make a call to the server).As we now know, ROS Actions provide feedback, so we're also importing the Feedbackpart of theCameraSweepActionmessage into our client node as well, so that it can be kept up to date with what the Action Server is doing, in real-time.
- 
To process this feedback data, we need to define a feedback callback function, to handle the data whenever a new feedback message comes in. Here we're using Python's "Type Annotations" feature: ... which informs the interpreter that thefeedback_datathat is received by thefeedback_callbackfunction will be of theCameraSweepFeedbacktype.All this really does is allow autocomplete functionality to work with in our editor (VS Code), whenever we want to pull an attribute from the feedback_dataobject.
- 
Standard practice when we construct ROS nodes: we must initialise them with a name, where the node_namevariable was assigned earlier on in the code:
- 
Then, we connect to the action server using the actionlib.SimpleActionClient()method, provide this with the name of the server that we wish to connect to and the type of messages that are used on the server (in this caseCameraSweepActionmessages).(The action_server_namevariable was also assigned earlier on in the code too:action_server_name = "/camera_sweep_action_server")
- 
This makes the node wait until the action server is live on the ROS Network (if it isn't already). Execution of the code can't continue past this point until the Action Server is visible on the ROS Network. 
- 
Once the server is available, we construct a goal message and send this to the action server, whilst also pointing it to the callback function that we defined earlier, which will be used to process the feedback messages. Tip Both goal parameters have been set to 0(above), so you'll need to change these in order for the client to successfully make a call to the server!
- 
Then, we simply wait for the action to complete. 
- 
Once it has completed, the server provides us with a result, so we simply print that (as well as the current state of the action) to the terminal. 
Fill in the Blank!
Which attribute of the feedback_data object tells us how many images have been captured over the course of the Camera Sweep Action? There are a number of ways we can work this out:
- You could use the same approach as we used earlier.
- You could run rosmsg info tuos_msgs/CameraSweepFeedbackin a terminal.
- You could use the autocomplete/variable suggestions provided in VS Code!