I recently worked with a service that involved moving the robot in a specific pattern. My code broke that motion up into “go forward”, “turn 90 degrees”, “stop” and assigned each a helper function.
I ran into an issue when it each method got to the point that it needed to publish its movement command to the robot. I tried a number of solutions to address this.
Solution 1
The simplest solution was to have each method create its own publisher, but that sounded very inefficient and repetitive.
Pseudo
def callback(req):
go_forward(req.a)
turn_robot(req.b)
def go_forward(distance)
pub = rospy.Publisher("/cmd_vel", Twist, queue_size = 1)
...
def turn_robot(angle)
pub = rospy.Publisher("/cmd_vel", Twist, queue_size = 1)
...
...
Solution 2:
Create a single publisher in the callback and pass it into each helper function
Pseudo
def callback(req):
pub = rospy.Publisher("/cmd_vel", Twist, queue_size = 1)
go_forward(pub, req.a)
turn_robot(pub, req.b)
def go_forward(pub, distance)
...
def turn_robot(pub, angle)
...
...
Despite this seeming to be a reasonable solution, I ran into a bizarre issue where the program would consistently ignore the first publish command (even if I added dummy publishes to “flush” the issue). This drove me onward to…
Solution 3:
Define the publisher in the “main body” of the script (i.e. make publisher global). This work perfect, but I have heard that using global objects is poor practice.
Pseudo
def callback(req):
go_forward(req.a)
turn_robot(req.b)
def go_forward(distance)
...
pub.publish(fwd_cmd)
def turn_robot(angle)
...
pub.publish(turn_cmd)
...
pub = rospy.Publisher("/cmd_vel", Twist, queue_size = 1)
A final (untested) solution that I have thought of while typing this up is to have a single move()
function that calls the helper functions to populate the move_cmd to be published.
Pseudo
def callback(req):
move("forward", req.a)
move("turn", req.b)
def move(type, var):
pub = rospy.Publisher("/cmd_vel", Twist, queue_size = 1)
move_cmd = Twist()
if(type == "forward"):
move_cmd = forward_cmd(var)
...
pub.publish(move_cmd)
def forward_cmd(distance)
...
return(fwd_cmd) # type Twist
def turn_robot(angle)
...
return(turn_cmd) # type Twist
...
Ultimately my question boils down to “which is best practice?”. I have a feeling that the answer will be nuanced and might involve object oriented programming. If that is the case, I would appreciate an expanded explanation or links to resources.
- Solution 1
- Solution 2
- Solution 3
- Solution 4
- Other
0 voters