ros2 / rclcpp Goto Github PK
View Code? Open in Web Editor NEWrclcpp (ROS Client Library for C++)
License: Apache License 2.0
rclcpp (ROS Client Library for C++)
License: Apache License 2.0
This function, wait_for_work
which is in the rclcpp::Executor
class:
rclcpp/rclcpp/include/rclcpp/executor.hpp
Line 167 in 860f478
rclcpp/rclcpp/include/rclcpp/executor.hpp
Line 211 in 860f478
rclcpp/rclcpp/include/rclcpp/executor.hpp
Line 233 in 860f478
repeatedly malloc
's for temporary storage used in the ros_middleware_interface::wait
function.
This could be avoided either by only allocating memory when resizing of the structures is required or by always using a structure of the maximum possible size (still would need to be updated when nodes are added or removed but less frequently) and ensuring that the ros_middleware_interface::wait
function properly handles the extra, unused storage.
rclcpp::parameter::ParameterVariant("bar", std::string("hello"))
is intepreted as a string correctly.
rclcpp::parameter::ParameterVariant("bar", "hello")
is interpreted as a bool with value true.
From testing in ros2/system_tests#14
Suggestion from @adolfo-rt:
Currently the ordering of tasks in the single-threaded executor is not exposed to the user. It should be possible to implement a single-threaded executor in which task execution ordering can be specified by the user. This is to further decouple the component topology from its thread execution.
Not a high priority for the current milestone (ROSCon demos) but an eventual goal.
add_two_ints_server__rmw_opensplice_cpp
/ add_two_ints_client__rmw_opensplice_cpp
: the server receives additional uninitialized requeststest_replier_cpp__rmw_opensplice_cpp
/ test_requester_cpp__rmw_opensplice_cpp
has the same problem - the test does not cover that (even with ros2/system_tests#34) since the client succeedsadd_two_ints_server__rmw_connext_cpp
/ add_two_ints_client__rmw_connext_cpp
do not exchange any messagesadd_two_ints_client__rmw_connext_cpp
can't be stopped with Ctrl-CNot sure if this is the way to make a comment or not, so please forgive.
Why should create_X return a handle for a publisher or subscriber when that information can be managed internally? What flexibility does it provide? Most topics are openend/closed at start/shutdown, with a single type on a single topic. With the current mechanism, there are 3 APIs: node, publish, subscribe. If the Node manages the publishers and subscribers, there would be a single API handling create/read/write, fewer objects for the client to track, and potentially a simpler locking and management scheme in a multi-threaded environment.
I noticed this while combing through the rclcpp library PR, but I wanted to make note of it here: we should pass std::vectors and other potentially large objects by reference. There are a few places where this is not done in parameter_client
and possibly elsewhere.
I was working on the unit tests with @gerkey for rate.sleep and expected the sleep to not return before expected.
On repeated runs it had a jitter on the order of 10us. (The printout is in nanoseconds. and the expected duration is 100 ms
Console output of observed delta: https://gist.github.com/tfoote/0ec473b38bc517d12779
We added an epsilon to the unit tests for now (#182), but we should review our code to make it as consistent as with the assumptions of developers who are used to calling the standard sleep methods.
This blocks writing the service tests in ros2/ros2#42.
When trying to create a demo application for #193 I got another segfault when using a Parameter Client with a spelling like DemoRobot for the parameter name.
Have a look at my demo application https://github.com/firesurfer/ros2_components_demo
It need the qt5 dev package in order to compile.
The application consists of three parts.
demo_parameter_server
demo_server
demo_client
The segfault happens in the demo_client in the file /src/ros2_components/Robot.h in the function ListAllKnownRobots
It fails due to an inability to resolve an overloaded function.
/home/tfoote/work/ros2/tf3/install/include/rclcpp/function_traits.hpp:51:85: error: decltype cannot resolve address of overloaded function
typename function_traits<decltype( & FunctionT::operator())>::arguments>::type;
The full error is here: https://gist.github.com/tfoote/17222805a01e7c05c3f1
rclcpp should be a wrapper around rcl (similar to rclpy).
I am going to start addressing this because I think it will help me understand how to design the rcl parameters API.
This is a spin off from ros2/ros2#55.
Basically we need to add some lubrication to the process of making a node which can be loaded as a library into a container or run as a stand-alone executable. This is what I imagine it would look like:
rclcpp_add_node(my_node src/my_node.cpp)
target_link_libraries(my_node ...)
ament_target_dependencies(my_node "rclcpp" ...)
...
The rclcpp_add_node
macro would create a target my_node
which builds a shared library, and also creates a target which builds an executable (name of this target is an implementation detail) with the output name my_node
. This allows the user to link extra libraries and what not to the library containing the node. It would also register this node in the ament index.
The output files will be lib/libmy_node.so
, bin/my_node
, and share/ament_index/resource_index/nodes/pkg_name/my_node
(maybe just share/ament_index/resource_index/nodes/pkg_name
with the my_node
in the contents of that file).
The user's code is compiled into lib/libmy_node.so
.
The executable is a boilerplate main which can load and run the shared library in stand alone mode or, with a cli switch, it can tell a remote container to load and run the library, acting as a surrogate until the node is removed from the container.
The infrastructure has been prototyped here: ros2/demos#18
Making all of this work will require us to figure out the issues surrounding multi vendor support in #48
Currently timers are naively implemented using a thread per timer, but it should be possible to implement the timers using a timeout argument to the ros_middleware_interface::wait
function. This would potentially be much more efficient and at least more ellegant, as the total number of threads and ros_middleware_interface::GuardConditionHandle
's would be significantly reduced. A stepping stone to this, without requiring a timeout in the ros_middleware_interface::wait
function, would be to have one thread for all timers which does the same waiting mechanism, but using a sleep function not as a parameter to ros_middleware_interface::wait
.
The callback are never invoked.
Acceptance Criteria:
Currently this repository contains the rmw_implementation
package which provides an interface to list and select an implementation for the rmw
API. It also sets the default implementation. We agreed that it should be in the rmw
repository as a peer to the rmw
package instead.
Acceptance Criteria:
rmw_implementation
package movedIs there already any logging mechanism implemented in ROS 2 one can use to log messages to a certain topic like in ROS 1 ( http://wiki.ros.org/roscpp/Overview/Logging ) ?
Branch multiple_nodes
in system_tests
, package test_rclcpp
, illustrates this bug:
https://github.com/ros2/system_tests/tree/multiple_nodes
Case 1 fails:
node1 and node2 are both added to one executor.
node1 publishes "foo", node2 subscribes to "foo"
node2 publishes "bar", node2 subscribes to "bar"
Both publishers publish 5 times.
0/5 messages are received for both subscribers.
Case 2 passes:
one node publishes "foo", "bar", subscribes to "foo" and "bar"
Both publishers publish 5 times.
5/5 messages are received for both subscribers.
Case 3 passes:
node1 and node2 both added to one executor.
node1 publishes "foo", subscribes to "foo"
node2 publishes "bar", subscribes to "bar"
Both publishers publish 5 times.
5/5 messages are received for both subscribers.
This was identified as potentially valuable during the parameter API review.
The use case is that there are a sequence of queries in a request, the response objects can be sorted in the same order as the requests, instead of requiring the response to be entirely self describing.
Make the client/service pipeline safe for real-time execution. It has not yet been vetted for allocations, STL structures which malloc automatically, and nondeterministic blocking.
This will be required for RT-safe node lifecycle, since we plan to use services to transition between states in the lifecycle.
Service::handle_request
make_shared
from async_send_request
std::vector
and std::map
(maybe just use a custom allocator)This is a spin-off from: ros2/ros2#55
We need a generic program which can be run and then remotely instructed to load and execute a node.
This program should probably:
This is not really useful until we have the ability to make, find, and dynamically load nodes, see:
This is also blocked by decisions that need to be made in: #48
If I understand this executor correctly, it's is a somewhat standard thread pool. there are n threads and m executable things. is it intended that "nodelets" will run under a similar scheme? I.e. That nodelet X will not be tied specifically to thread Y for the duration of the nodelet lifecycle?
Short description of my program:
static method A: gets a node passed, accesses a parameter server via an AsyncParametersClient
returns some information gained from the parameter server
static method B:gets a node passed: accesses a service that is hosted somewhere.
returns some information gained from the service
Both methods have somewhere a call to rclcpp::spin_until_future_complete.
Example:
When I call method A, A returns succesfully.
When I call method B, B will give me a segfault
Everytime I'm using a the service call in a static method (that succeeds), I cant do a second service call or a call to a parameter server because of a segfault at: rclcpp::spin_until_future_complete
gdb Backtrace:
#0 0x00000000006747b8 in std::__shared_ptr<std::__future_base::_State_baseV2, (__gnu_cxx::_Lock_policy)2>::operator-> (this=0x0) at /usr/include/c++/5/bits/shared_ptr_base.h:1055
#1 0x00007ffff201e263 in std::promise<std::shared_ptr<rcl_interfaces::srv::GetParameters_Response_<std::allocator<void> > > >::set_value(std::shared_ptr<rcl_interfaces::srv::GetParameters_Response_<std::allocator<void> > > const&) () from /home/firesurfer/workspace/ros2_ws/install/lib/librclcpp.so
#2 0x00007ffff201cfbb in rclcpp::client::Client<rcl_interfaces::srv::GetParameters>::handle_response(std::shared_ptr<void>&, std::shared_ptr<void>&) ()
from /home/firesurfer/workspace/ros2_ws/install/lib/librclcpp.so
#3 0x00007ffff1fcc7f6 in rclcpp::executor::Executor::execute_client(std::shared_ptr<rclcpp::client::ClientBase>) () from /home/firesurfer/workspace/ros2_ws/install/lib/librclcpp.so
#4 0x00007ffff1fcc193 in rclcpp::executor::Executor::execute_any_executable(std::shared_ptr<rclcpp::executor::AnyExecutable>) () from /home/firesurfer/workspace/ros2_ws/install/lib/librclcpp.so
#5 0x00007ffff1fcbdf9 in rclcpp::executor::Executor::spin_once(std::chrono::duration<long, std::ratio<1l, 1000000000l> >) () from /home/firesurfer/workspace/ros2_ws/install/lib/librclcpp.so
#6 0x000000000069d5a1 in rclcpp::executor::Executor::spin_until_future_complete<std::shared_ptr<ros2_components_msg::srv::ListChilds_Response_<std::allocator<void> > >, std::ratio<1l, 1000l> > (
this=0x7fffffffd3f0, future=..., timeout=...) at /home/firesurfer/workspace/ros2_ws/install/include/rclcpp/executor.hpp:184
#7 0x000000000068c94d in rclcpp::executors::spin_node_until_future_complete<std::shared_ptr<ros2_components_msg::srv::ListChilds_Response_<std::allocator<void> > >, std::ratio<1l, 1000l> > (executor=...,
node_ptr=std::shared_ptr (count 12, weak 1) 0x974440, future=..., timeout=...) at /home/firesurfer/workspace/ros2_ws/install/include/rclcpp/executors.hpp:67
#8 0x0000000000679fe9 in rclcpp::spin_until_future_complete<std::shared_ptr<ros2_components_msg::srv::ListChilds_Response_<std::allocator<void> > >, std::ratio<1l, 1000l> > (
node_ptr=std::shared_ptr (count 12, weak 1) 0x974440, future=..., timeout=...) at /home/firesurfer/workspace/ros2_ws/install/include/rclcpp/executors.hpp:81
gdb output:
Program received signal SIGSEGV, Segmentation fault.
0x00000000006747b8 in std::__shared_ptr<std::__future_base::_State_baseV2, (__gnu_cxx::_Lock_policy)2>::operator-> (this=0x0) at /usr/include/c++/5/bits/shared_ptr_base.h:1055
1055 return _M_ptr;
Edit: Some further research showed that this behavior occurs every time I create a Client and destroy it. When I'm creating a new client afterwards and want to use it, I get a segfault
Edit2: After digging in the ros2 code I think the solution might be to tell the executor that a certain client doenst exist anymore
However, they work fine if built from source.
Review callback passing strategy and find a uniform approach.
See #188
intra-process_publish_mutex
) #77take_intra_process_message
and store_intra_process_message
for pool alternative (solution: allocator template)std::map
in IntraProcessManager
(solution: allocator template for stdlib data structures)Dave Sandage reported this on the NG SIG:
I've just started playing with the ROS2 alpha2 release, and was experimenting with some samples. I wrote a node to act as a service server, modeling it after the add_two_ints_server example. It all works, but after Ive made my first call to the service, the server node pegs the CPU at 100%. add_two_ints_server does this also.
At the end of my node's main() function, I have the following loop:
while (rclcpp::utilities::ok()) { executor.spin_node_once(node, std::chrono::milliseconds(1000)); }After the first call to the service, this method returns immediately every time, leaving the node in a tight loop. Upon further debugging in rclcpp, it appears that in executor::execute_next_ready_executable(), get_next_service always returns a non-null value. Is there something in my service handler that needs to be done to remove the service from showing always ready to execute? I've modeled mine exactly on the add_two_ints_server (and it does the same thing).
See discussion on #152
It is missing coverage and it looks like it has a duration_cast missing.
Found working toward: ros2/ros2#160
http://ci.ros2.org/job/ci_osx/599/console
18:20:33 /Users/osrf/jenkins/workspace/ci_osx/ws/install/rclcpp/include/rclcpp/rate.hpp:74:20: error: no viable overloaded '+='
18:20:33 last_interval_ += period_;
18:20:33 ~~~~~~~~~~~~~~ ^ ~~~~~~~
18:20:33 /Users/osrf/jenkins/workspace/ci_osx/ws/src/ros/geometry_experimental/tf2_ros/src/tf2_echo.cpp:142:12: note: in instantiation of member function 'rclcpp::rate::GenericRate<std::__1::chrono::system_clock>::sleep' requested here
18:20:33 rate.sleep();
18:20:33 ^
18:20:33 /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/chrono:782:79: note: candidate function not viable: no known conversion from 'duration<[...], ratio<[...], 1000000000>>' to 'const duration<[...], ratio<[...], 1000000>>' for 1st argument
18:20:33 __attribute__ ((__visibility__("hidden"), __always_inline__)) time_point& operator+=(const duration& __d) {__d_ += __d; return *this;}
Currently spin_some
has a single-threaded implementation in Executor
that gets inherited by the child classes. The implementation for the MultiThreadedExecutor
should try assign the tasks to different threads.
We have a tools for checking our code with clang_format
but it is not configured to our liking yet.
Acceptance Criteria:
How should we expose synchronization primitives to implement a lock-free executor for real-time execution?
Currently all functions are defined in the header files directly. This makes it impossible to create executables from multiple C++ files since each will include its own version of the symbol and then collide at link time.
A recent PR /pull/107 added a return code and a timeout to this function. We should add tests for this function to test_rclcpp (and possibly for other Executor::spin functions).
This has been observed in the talker
using opensplice:
$ ./install/bin/talker__ros_middleware_opensplice_cpp
init()
init() get_instance
create_node()
create_node() opensplice_static
create_node() get_instance
create_node() create_participant in domain 0
create_node() pass opaque node handle
create_publisher()
create_publisher() opensplice_static
create_publisher() extract participant from opaque node handle
create_publisher() invoke register callback
simple_msgs::type_support::register_type__String()
create_publisher() create dds publisher
create_publisher() create topic: chatter
create_publisher() create data writer
create_publisher() build opaque publisher handle
Publishing: 'Hello World: 1'
Publishing: 'Hello World: 2'
Publishing: 'Hello World: 3'
^Csignal_handler(2)
*** Error in `./install/bin/talker__ros_middleware_opensplice_cpp': double free or corruption (!prev): 0x00000000016f8ff0 ***
Nowhere on the master branches of ROS 2 repositories do we subscribe to a topic with a callback signature receiving a MessageT::ConstSharedPtr
(shared_ptr<const MessageT
>, or publish a ConstSharedPtr
.
I tried to do this and there two problems:
AnySubscriptionCallback
doesn't have definitions for the ConstSharedPtr
type. This is easy to fix and I have an upcoming pull request for it.IntraProcessManager
receives the published message as a void*
in its store_intra_process
callback. The compile error is because the publisher template tries to copy the const message into a unique pointer of a const message and pass that to store_intra_proces
, but const
message cannot be cast to void. Fixing this requires a bit more work to ensure the copy of the message is not const.In the parameter events examples, the callback function is not always triggered. However further testing shows that the data was received, but the executor didn't trigger the callback. This may indicate that there's an issue in the way SingleThreadedExceutor is used.
For unit tests it would be good to start nodes without any additional overhead as it simplifies debugging.
rclcpp/rclcpp/include/rclcpp/node_impl.hpp
Lines 60 to 61 in 5baa519
Is it possible to list all parameters of a parameter server ?
I created a workaround in https://github.com/firesurfer/ros2_components/blob/master/src/ros2_components/Robot.h#L119 by requesting about 20.000 possible parameter names. It would be nicer if it would be possible to get a list of all parameters
I think it made sense for rmw_implementation
to be in the rclcpp
repository when it only used by rclcpp
, but now I think it probably belongs in rmw
.
Thoughts?
Discussed names were:
bool rclcpp::is_shutdown
and bool rclcpp::is_not_shutdown
bool rclcpp::is_shutting_down
State rclcpp::state
and compare to predefined states
while (rclcpp::state() == rclcpp::RUNNING)
while (rclcpp::state() != rclcpp::SHUTDOWN)
In ros2/rmw_connext#76 I complained about nondeterministic startup behavior for 2 nodes communicating in the same process (but this was before the intra-process pipeline was implemented)). It was argued that this is acceptable behavior, since the two nodes are being initialized through DDS and DDS discovery can't make timing guarantees.
I would expect nodes within the same process to be able to avoid this nondeterministic startup behavior if the intra-process pipeline were utilized. This would be an acceptable solution.
However, the intra-process pipeline currently does not work for communication between two different nodes in the same process. I assume because the intra-process manager is a child of the context, not the node, that this feature should be implemented.
In branch multiple_nodes
of system_tests
, I added a case for publishing messages from one node to another node in the same process:
Currently the callback fails to trigger.
This feature is probably not urgent right now, but important for node composability.
We need an equivalent of roscpp::waitForService(), which waits a bounded amount of time for a service server to become available. It should be possible to build it atop Node::count_subscribers(). Ideally it will internally be done in an event-driven manner, rather than polling.
why was the Context pattern chosen over a traditional Singleton pattern?
E.g.
rclcpp/rclcpp/src/rclcpp/parameter_client.cpp
Lines 246 to 257 in 249b7d8
so...
node caches parameters locally.
but sends them out to the parameter_event channel... so if all nodes are up, all nodes can get the events.
but it seems the parameter server does not listen to this channel, it relies on a service to set params in its cache. the server requires a separate api for access (parameter_client).
are the parts just not hooked up yet? or am i missing something?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.