ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

A node that's a subscriber, a publisher and uses dynamic parameters [Python]

asked 2017-12-30 02:40:13 -0500

mohsen gravatar image

updated 2018-01-08 14:05:03 -0500

Suppose I have defined two custom dynamic parameters, gain1 and gain2, in a cfg file. I would like to use these in a node that subscribes and publishes to two topics. Here's what i tried:

import rospy
from std_msgs.msg import Float64
from dynamic_reconfigure.server import Server
from myPack.cfg import paramConfig

def param_callback(config, level):
      gain1 = config.gain1
      gain2 = config.gain2
      return config

def callback1(msg):
      in1 = msg.data

def callback2(msg):
      in2 = msg.data

rospy.init_node('mixer')
srv = Server(paramConfig, param_callback)

sub1 = rospy.Subscriber('in1', Float64, callback1)
sub2 = rospy.Subscriber('in2', Float64, callback2)

pub1 = rospy.Publisher('out1', Float64)
pub2 = rospy.Publisher('out2', Float64)

out1 = Float64()
out2 = Float64()

while not rospy.is_shutdown():
      out1.data = in1*gain1
      out2.data = in2*gain2

      pub1.publish(out1)
      pub2.publish(out2)

But it seems the subscribers callbacks don't work. This error is given for the first line of the while loop.

 NameError: name 'in1' is not defined

Note that the subscription and parameter server code work fine individually.

Am I using the right method?

Update: As suggested by gvdhoorn, I had to define gain1 and gain2 as global variables and initialize in1 and in2 before the while loop. The latter because the program could reach the while loop before a callback. In this case, in1 is still undefined and I would receive the same error .

I feel this method is a bit inelegant and as gvdhoorn pointed out, using a class instead of global variables is better programming.

edit retag flag offensive close merge delete

Comments

1

Another problem you should change: your publishers are being declared as Subscribers. pub1 = rospy.Subscriber('out1', Float64) Change to : pub1 = rospy.Publisher('out1', Float64, queue_size=1)

marcoarruda gravatar image marcoarruda  ( 2018-01-08 08:20:15 -0500 )edit

Whoops. Just saw that. The node is a simplified version of what I use and written specifically for this question so I never actually ran it.

mohsen gravatar image mohsen  ( 2018-01-08 08:25:47 -0500 )edit

Ah ok then! It's just that I reproduced your problem, fixed the variable scope and got into another problem related to that (A Subscriber object doesn't have the .publish method). =]

marcoarruda gravatar image marcoarruda  ( 2018-01-08 11:24:40 -0500 )edit

2 Answers

Sort by ยป oldest newest most voted
1

answered 2017-12-30 02:59:27 -0500

gvdhoorn gravatar image

But it seems the subscribers callbacks don't work.

The callbacks are probably fine, and this is not a ROS problem (so there's nothing wrong with the publishers, subscribers or dyn re_cfg here), but most likely a Python scoping problem: you're trying to use variables (in1, in2, gain1 and gain2) in the body of your while-loop that are out of scope at that point (ie: they do not 'exist' there). See random tutorial about Python variable scopes for some explanation.

A quick work-around could be to put in1, in2, gain1 and gain2 in the global scope. Using a class and making those variables members would probably be nicer.


Edit: note that besides the scoping issue your current implementation also has some other issues:

  1. no rate limiting of your main while-loop (see wiki/rospy/Overview/Time - Sleeping and Rates)
  2. mixing an event system with a periodic, synchronous sampling one (and assuming that the event callbacks will be serviced at suitable intervals so the pub1 and pub2 publishers don't republish old data)

The first can lead to starvation of other tasks/nodes, while the second can lead to missed updates and publishing stale data (among other things).

edit flag offensive delete link more

Comments

Thank you. Is there a way to fix the second issue? I haven't found a different way to implement a publisher /subscriber that uses dynamic parameters.

mohsen gravatar image mohsen  ( 2017-12-30 03:24:43 -0500 )edit

I'm not sure I understand how the dynamic reconfigure complicates things. Can you elaborate?

gvdhoorn gravatar image gvdhoorn  ( 2017-12-30 03:28:30 -0500 )edit

I think it is a misunderstanding on my part. By "an event system", I thought you meant the parameter server.

mohsen gravatar image mohsen  ( 2017-12-30 03:53:10 -0500 )edit
1

No. ROS pub-sub is event-based, not just dynamic reconfigure.

Your while-loop implements a sync, periodic sampling on top of that. I just wanted to point that out.

gvdhoorn gravatar image gvdhoorn  ( 2017-12-30 06:06:17 -0500 )edit
0

answered 2018-01-08 14:09:08 -0500

mohsen gravatar image

updated 2018-01-09 01:52:32 -0500

Here's the final functioning code:

import rospy
from std_msgs.msg import Float64
from dynamic_reconfigure.server import Server
from myPack.cfg import paramConfig

def param_callback(config, level):
      global gain1, gain2
      gain1 = config.gain1
      gain2 = config.gain2
      return config

def callback1(msg):
      in1 = msg.data

def callback2(msg):
      in2 = msg.data

rospy.init_node('mixer')
srv = Server(paramConfig, param_callback)

sub1 = rospy.Subscriber('in1', Float64, callback1)
sub2 = rospy.Subscriber('in2', Float64, callback2)

pub1 = rospy.Publisher('out1', Float64)
pub2 = rospy.Publisher('out2', Float64)

out1 = Float64()
out2 = Float64()

in1 = 0
in2 = 0

rate = rospy.Rate(100)

while not rospy.is_shutdown():
      out1.data = in1*gain1
      out2.data = in2*gain2

      pub1.publish(out1)
      pub2.publish(out2)

     rate.sleep()
edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2017-12-30 02:27:13 -0500

Seen: 1,385 times

Last updated: Jan 09 '18