Week 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: Action State = {client.get_state()}") # (10)!
print(f"RESULT: {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
rospy
library. -
If we want to work with ROS Actions, we also need to import
actionlib
. -
We know that the
/camera_sweep_action_server
usesCameraSweepAction
messages from thetuos_msgs
package, so we import the full message definition:CameraSweepAction
as well as theGoal
message (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
Feedback
part of theCameraSweepAction
message 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_data
that is received by thefeedback_callback
function will be of theCameraSweepFeedback
type.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_data
object. -
Standard practice when we construct ROS nodes: we must initialise them with a name, where the
node_name
variable 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 caseCameraSweepAction
messages).(The
action_server_name
variable 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/CameraSweepFeedback
in a terminal. - You could use the autocomplete/variable suggestions provided in VS Code!