Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rclpy minimal pub sub #139

Merged
merged 16 commits into from
Nov 30, 2016
Merged

Rclpy minimal pub sub #139

merged 16 commits into from
Nov 30, 2016

Conversation

mikaelarguedas
Copy link
Member

This PR adds several simple pub/sub examples.
This not sure if the "local function" and the "lambda" are necessary, maybe we should just pick one and discard the other.

@mikaelarguedas mikaelarguedas added the in review Waiting for review (Kanban column) label Nov 28, 2016
@mikaelarguedas mikaelarguedas self-assigned this Nov 28, 2016
This package contains a few different strategies for creating short nodes that blast out messages.
The `publisher_old_school` recipe creates a talker node very similar to how it would be done in ROS1 using rospy.
The `publisher_lambda` and `publisher_local_function` allow to leverage the timers provided by ROS2 to trigger message publication.
The `publisher_member_function` created a class MinimalPublisher that sends messages periodically
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I 'member!

publisher_.publish(msg)
rclpy.spin_once(node)

node.destroy_timer(timer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do these timers and nodes get destroyed automatically on shutdown, or is manual destruction necessary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they do get destroyed automatically, I added the destruction to avoid that linters complain about unused variables. I'm unsure about the amount of comments that should be placed in these examples. But this one definitely deserves deserves one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in a55f5b1

Copy link
Member

@codebot codebot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my comments are very minor. these simple examples and setup.py examples are gr8

msg.data = 'Hello World: %d' % i
i += 1
print('Publishing: "%s"' % msg.data)
publisher_.publish(msg)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm probably just not understanding this correctly, but it seems like the timer with lambda will also be publishing, so the messages will be sent twice (one from the lambda, one from this publish() call ? And will this loop run at a particular rate, or will it run as quickly as possible?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_< indeed this publish shouldn't be here.
Regarding the loop, filling up the message etc cannot be done in the lambda because of how lambdas work in python (no variable assignment, has to be single line etc). I would be in favor of removing the publisher_lambda and the subscriber_local_function but I'm not a fan of not having symmetry in the minimalist publisher/subscriber examples

timer = node.create_timer(0.5, timer_callback)

while rclpy.ok():
rclpy.spin_once(node)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it recommended to have this while loop calling spin_once() or is it better to just have spin() (I don't know) 🐔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unfortunately there is no spin yet in python, only spin_once

class MinimalPublisher:

def __init__(self):
self.node = rclpy.create_node('minimal_publisher')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the python recommended style, but having the lines smashed together without whitespace seems nicer to me. But maybe there is a style guide for such things 🐔


subscription_ = node.create_subscription(
String, 'topic', listener_callback)
subscription_ # noqa
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this line do? ELI5

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line tells the linter that this variable is not an unused variable. That's the counterpart of calling the destroy_* functions explicitely.

Copy link
Member Author

@mikaelarguedas mikaelarguedas Nov 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment changed from to avoid confusion

# Destroy the node explicitly
# (optional - otherwise it will be done automatically
# when the garbage collector destroys the node object)
minimal_subscriber.node.destroy_node()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be done in some sort of destructor for the MinimalSubscriber class?

# Minimal "publisher" cookbook recipes

This package contains a few different strategies for creating short nodes that blast out messages.
The `publisher_old_school` recipe creates a talker node very similar to how it would be done in ROS1 using rospy.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you use ROS 1 and ROS 2 (with spaces) for consistency please

i += 1
print('Publishing: "%s"' % msg.data)
publisher_.publish(msg)
# TODO(mikaelarguedas): explain why spin_once can't be used here
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible to add a comment to address this now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that has been done in 1cf6702

<test_depend>ament_copyright</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>ament_pep8</test_depend>
<test_depend>ament_pyflakes</test_depend>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think the linters go against the minimalistic nature? there seems to be a few lines added that could confuse people just for linter sake

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I though the conclusion was that examples should be tested and linted as opposed to the tutorials. Did I miss something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the conclusion was exactly the opposite, because testing would cause the CMake and potentially the code to be more complex, making it less copy-pastable. The tutorials, however, are not meant as minimal starting locations, so they can afford to have more complex CMake lists and code?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tutorial code tested, examples copy-paste friendly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I thought it was the other way around (examples are as short as possible, but tutorials are longer-form with narrative and automatically tested)? 🐔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok my bad I thought we wanted to make sure that the copy-pasted code compiles/run whereas it was not crucial for the ones supposed to show concepts on the wiki. Will remove all the tests then

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do want to make sure it compiles, and I don't think that linting it is a bad idea. If our code commonly make the sure do something that doesn't pass a linter, then we should consider changing the API.

So, I'd say leave the linters, but do not test it with automated tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left the linters and added a comment in the package.xml to highlight the purpose of these dependencies

if args is None:
args = sys.argv

rclpy.init(args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be more minimalistic to remove the args variable altogether (and sys import)


msg = String()
i = 0
timer = node.create_timer(0.5, lambda: publisher_.publish(msg))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be in favour of removing/reworking this script since the lambda doesn't show that much (like you mentioned)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree, although it is a bit unfortunate that symmetry isn't possible, that's a language restriction and there isn't much we can do about it. I'm also in favor of removing this example 🐔

@mikaelarguedas
Copy link
Member Author

Comments addressed

The `publisher_local_function` allow to leverage the timers provided by ROS 2 to trigger message publication.
The `publisher_member_function` created a class MinimalPublisher that sends messages periodically
The `publisher_local_function` recipe shows how to leverage the timers provided by ROS 2 to trigger message publication.
The `publisher_member_function` recipe creates a class MinimalPublisher that sends messages periodically.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx

@mikaelarguedas
Copy link
Member Author

Thanks everyone for reviewing.
Any other comments on this ?

@codebot
Copy link
Member

codebot commented Nov 28, 2016

👍 🐔

minimal_publisher = MinimalPublisher()

while rclpy.ok():
rclpy.spin_once(minimal_publisher.node)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the cookbook examples are supposed to show best practice it might be best to not have the node attached to the class, so that multiple publishers can easily be attached to a node. it's not a blocker though, just a suggestion

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, done eea27f3

print('Publishing: "%s"' % msg.data)
publisher_.publish(msg)

timer = node.create_timer(0.5, timer_callback)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth highlighting the units here, since they're different to rclcpp. either commented or through a variable name

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think a comment is necessary given that we pass the same value to the python sleep function. It should be pretty obvious given that all scripts have equivalent behavior. If doubt there is, the variable name in the API is timer_period_sec.
I'm not opposed to it but don't think this is a source of confusion

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok I added a comment in c056f8f just in case



def test_copyright():
rc = main(argv=['.', 'test'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be . and test? Isn't test a subfolder of the package root .?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was a copy paste from rclpy_examples, 'test' can be removed but '.' needs to stay because the linters don't provide a default path so removing it cause the nosetest invocation to fail. updated in e368944

@mikaelarguedas mikaelarguedas merged commit cf6662f into master Nov 30, 2016
@mikaelarguedas mikaelarguedas deleted the rclpy_minimal_pub_sub branch November 30, 2016 20:10
@mikaelarguedas mikaelarguedas removed the in review Waiting for review (Kanban column) label Nov 30, 2016
haueck pushed a commit to haueck/examples that referenced this pull request Dec 8, 2016
* minimal pub examples

* sub examples + linters

* class examples

* rename files and targets

* add READMEs

* add comment about object destruction

* clarify use of spin_once

* address comments

* remove reference to deleted scripts

* Readme fixup

* pass node to pub/sub classes

* variable name consistency

* update old school publisher comment

* remove unnecessary folder name

* Clarify units

* Update 'not recommended' comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants