Python3: Publisher Best Practice Question

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.

“Good” Solutions
  • Solution 1
  • Solution 2
  • Solution 3
  • Solution 4
  • Other

0 voters

1 Like

Have you thought of using classes? That would be basically like the global var declaration.

Have you tried the Python 3 for Robotics course? Look specifically for Python classes.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.