Skip to content

Commit bdd7fd1

Browse files
Martin-Idel-SIKarsten1987
authored andcommitted
Allow an arbitrary topic to be recorded (ros2#26)
* ros2GH-52 Extend db schema to include topic meta data - Two table db layout (messages and topics) - Messages table references topics table but without foreign key for improved write performance - Create_topic must be called for every topic prior to storing a message of this topic. - Sqlite_storage caches all known topics - At least for now the type information is stored as a simple string. * ros2GH-54 Make first rcl subscription prototype work * ros2GH-54 find type name from topic * ros2GH-54 Publish messages from database knowing only topic name and pass topic name by terminal * ros2GH-54 Refactoring of typesupport helpers * ros2GH-54 Use c++ typesupport * ros2GH-54 Use cpp typesupport and rclcpp::Node for publisher * ros2GH-54 Add raw subscription and use in rosbag_record * ros2GH-54 Add Rosbag2Node and Rosbag2Publisher classes and use them in Rosbag2::play * ros2GH-54 Rename Rosbag2Publisher to RawPublisher * ros2GH-54 Minor refactoring of Rosbag2Node * ros2GH-54 Extract and test waiting for topic into its own method * ros2GH-54 Fix read integration tests and linters * ros2GH-55 Refactor Rosbag2Node::create_raw_publisher() * ros2GH-54 Add subscription method to rosbag node * ros2GH-54 Keep subscription alive * ros2GH-54: Extract subscription to correct class * ros2GH-55 Change interface of raw_publisher to match subscriber * ros2GH-54 Add test for rosbag node * ros2GH-54 Unfriend rclcpp class * ros2GH-54 Make test more robust * ros2GH-54 Fix build * ros2GH-54 Minor cleanup and documentation * ros2GH-55 Minor refactoring + TODO comment * ros2GH-54 Change dynamic library folder on Windows * ros2GH-54 Fix build * ros2GH-54 Add shutdown to test * ros2GH-55 Add test helpers methods for usage in multiple tests * ros2GH-55 Add new method to read all topics and types in BaseReadInterface and use it in Rosbag2::play * ros2GH-55 Fix gcc and msvc * ros2GH-54 Rename raw to generic in publisher/subscriber * ros2GH-55 Check that topic and associated type in bag file are well defined before playing back messages * ros2GH-54 Prevent unnecessary error message loading storage * ros2GH-54 Fix memory leak * ros2GH-54 stabilize node test * ros2GH-55 Check if database exists when opening storage with READ_ONLY flag * ros2GH-54 Minor cleanup of subscriber * ros2GH-54 Wait a small amount of time to let node discover other nodes * Add logging to false case * ros2GH-54 Catch exceptions and exit cleanly * Use rmw_serialized_message_t and rcutils_char_array_t consistently * ros2GH-4 Refactoring for correctness - pass a few strings as const reference - throw error when no topics could be found * Improve error messages when loading plugins * alphabetical order * type_id -> type
1 parent 3f77b33 commit bdd7fd1

34 files changed

+1191
-97
lines changed

rosbag2/CMakeLists.txt

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,36 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
1616
endif()
1717

1818
find_package(ament_cmake REQUIRED)
19+
find_package(ament_index_cpp REQUIRED)
20+
find_package(poco_vendor)
21+
find_package(Poco COMPONENTS Foundation)
22+
find_package(rcl REQUIRED)
1923
find_package(rclcpp REQUIRED)
2024
find_package(rcutils REQUIRED)
21-
find_package(std_msgs REQUIRED)
2225
find_package(rosbag2_storage REQUIRED)
26+
find_package(rosidl_generator_c REQUIRED)
27+
find_package(std_msgs REQUIRED)
2328

2429
add_library(
2530
librosbag2
2631
SHARED
27-
src/rosbag2/rosbag2.cpp)
32+
src/rosbag2/rosbag2.cpp
33+
src/rosbag2/typesupport_helpers.cpp
34+
src/rosbag2/generic_publisher.cpp
35+
src/rosbag2/generic_subscription.cpp
36+
src/rosbag2/rosbag2_node.cpp)
2837

29-
ament_target_dependencies(librosbag2 rclcpp rcutils std_msgs rosbag2_storage)
38+
ament_target_dependencies(
39+
librosbag2
40+
ament_index_cpp
41+
Poco
42+
rcl
43+
rclcpp
44+
rcutils
45+
rosbag2_storage
46+
rosidl_generator_c
47+
std_msgs
48+
)
3049
target_include_directories(librosbag2
3150
PUBLIC
3251
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
@@ -61,6 +80,8 @@ if(BUILD_TESTING)
6180
ament_add_gmock(rosbag2_write_integration_test
6281
test/rosbag2/rosbag2_write_integration_test.cpp
6382
test/rosbag2/rosbag2_test_fixture.hpp
83+
test/rosbag2/test_helpers.hpp
84+
src/rosbag2/typesupport_helpers.cpp
6485
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
6586
if(TARGET rosbag2_write_integration_test)
6687
target_link_libraries(rosbag2_write_integration_test librosbag2)
@@ -69,10 +90,42 @@ if(BUILD_TESTING)
6990
ament_add_gmock(rosbag2_read_integration_test
7091
test/rosbag2/rosbag2_read_integration_test.cpp
7192
test/rosbag2/rosbag2_test_fixture.hpp
93+
test/rosbag2/test_helpers.hpp
94+
src/rosbag2/typesupport_helpers.cpp
7295
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
7396
if(TARGET rosbag2_read_integration_test)
7497
target_link_libraries(rosbag2_read_integration_test librosbag2)
7598
endif()
99+
100+
ament_add_gmock(rosbag2_typesupport_helpers_test
101+
test/rosbag2/rosbag2_typesupport_helpers_test.cpp
102+
src/rosbag2/typesupport_helpers.cpp
103+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
104+
if(TARGET rosbag2_typesupport_helpers_test)
105+
ament_target_dependencies(rosbag2_typesupport_helpers_test rcl Poco ament_index_cpp
106+
rosidl_generator_cpp)
107+
endif()
108+
109+
ament_add_gmock(rosbag2_integration_test
110+
test/rosbag2/rosbag2_integration_test.cpp
111+
test/rosbag2/test_helpers.hpp
112+
src/rosbag2/typesupport_helpers.cpp
113+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
114+
if(TARGET rosbag2_integration_test)
115+
target_link_libraries(rosbag2_integration_test librosbag2)
116+
endif()
117+
118+
ament_add_gmock(rosbag2_rosbag_node_test
119+
test/rosbag2/rosbag2_rosbag_node_test.cpp
120+
src/rosbag2/typesupport_helpers.cpp
121+
src/rosbag2/generic_subscription.cpp
122+
src/rosbag2/generic_publisher.cpp
123+
src/rosbag2/rosbag2_node.cpp
124+
test/rosbag2/test_helpers.hpp
125+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
126+
if(TARGET rosbag2_rosbag_node_test)
127+
ament_target_dependencies(rosbag2_rosbag_node_test rclcpp Poco ament_index_cpp std_msgs)
128+
endif()
76129
endif()
77130

78131
ament_package()

rosbag2/include/rosbag2/rosbag2.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616
#define ROSBAG2__ROSBAG2_HPP_
1717

1818
#include <functional>
19+
#include <memory>
1920
#include <string>
2021

22+
#include "rclcpp/rclcpp.hpp"
23+
24+
#include "rosbag2_storage/storage_interfaces/read_only_interface.hpp"
2125
#include "rosbag2/visibility_control.hpp"
2226

2327
namespace rosbag2
@@ -34,6 +38,15 @@ class Rosbag2
3438

3539
ROSBAG2_PUBLIC
3640
void play(const std::string & file_name, const std::string & topic_name);
41+
42+
ROSBAG2_PUBLIC
43+
std::string get_topic_type(
44+
const std::string & topic_name, const std::shared_ptr<rclcpp::Node> & node);
45+
46+
ROSBAG2_PUBLIC
47+
std::string get_topic_type(
48+
std::shared_ptr<rosbag2_storage::storage_interfaces::ReadOnlyInterface> storage,
49+
const std::string & topic);
3750
};
3851

3952
} // namespace rosbag2

rosbag2/package.xml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@
99

1010
<buildtool_depend>ament_cmake</buildtool_depend>
1111

12-
<build_depend>rosbag2_storage</build_depend>
13-
<build_depend>rcutils</build_depend>
14-
15-
<exec_depend>rosbag2_storage</exec_depend>
16-
<exec_depend>rcutils</exec_depend>
12+
<depend>ament_index_cpp</depend>
13+
<depend>libpoco-dev</depend>
14+
<depend>poco_vendor</depend>
15+
<depend>rcl</depend>
16+
<depend>rclcpp</depend>
17+
<depend>rcutils</depend>
18+
<depend>rosbag2_storage</depend>
19+
<depend>rosidl_generator_c</depend>
20+
<depend>std_msgs</depend>
1721

1822
<test_depend>ament_lint_auto</test_depend>
1923
<test_depend>ament_lint_common</test_depend>

rosbag2/src/rosbag2/demo_play.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,24 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#include <string>
16+
1517
#include "rclcpp/rclcpp.hpp"
1618

1719
#include "rosbag2/rosbag2.hpp"
1820

1921
int main(int argc, const char ** argv)
2022
{
23+
if (argc < 2) {
24+
std::cerr << "\nThe name of the topic to play to must be given as parameter!\n";
25+
return 0;
26+
}
27+
std::string topic_name = argv[1];
28+
2129
rclcpp::init(argc, argv);
2230

2331
rosbag2::Rosbag2 rosbag2;
24-
rosbag2.play("test.bag", "string_topic");
32+
rosbag2.play("test.bag", topic_name);
2533

2634
rclcpp::shutdown();
2735

rosbag2/src/rosbag2/demo_record.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121

2222
int main(int argc, const char ** argv)
2323
{
24+
if (argc < 2) {
25+
std::cerr << "\nThe name of the topic to record must be given as parameter!\n";
26+
return 0;
27+
}
28+
std::string topic_name = argv[1];
29+
2430
// TODO(anhosi): allow output file to be specified by cli argument and do proper checking if
2531
// file already exists
2632
std::string filename("test.bag");
@@ -29,7 +35,7 @@ int main(int argc, const char ** argv)
2935
rclcpp::init(argc, argv);
3036

3137
rosbag2::Rosbag2 rosbag2;
32-
rosbag2.record(filename, "string_topic");
38+
rosbag2.record(filename, topic_name);
3339

3440
rclcpp::shutdown();
3541

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2018, Bosch Software Innovations GmbH.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "generic_publisher.hpp"
16+
17+
#include <memory>
18+
#include <string>
19+
20+
namespace rosbag2
21+
{
22+
23+
GenericPublisher::GenericPublisher(
24+
rclcpp::node_interfaces::NodeBaseInterface * node_base,
25+
const std::string & topic,
26+
const rosidl_message_type_support_t & type_support)
27+
: rclcpp::PublisherBase(node_base, topic, type_support, rcl_publisher_get_default_options())
28+
{}
29+
30+
void GenericPublisher::publish(std::shared_ptr<rmw_serialized_message_t> message)
31+
{
32+
auto return_code = rcl_publish_serialized_message(
33+
get_publisher_handle(), message.get());
34+
35+
if (return_code != RCL_RET_OK) {
36+
rclcpp::exceptions::throw_from_rcl_error(return_code, "failed to publish serialized message");
37+
}
38+
}
39+
40+
} // namespace rosbag2
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2018, Bosch Software Innovations GmbH.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef ROSBAG2__GENERIC_PUBLISHER_HPP_
16+
#define ROSBAG2__GENERIC_PUBLISHER_HPP_
17+
18+
#include <memory>
19+
#include <string>
20+
21+
#include "rclcpp/rclcpp.hpp"
22+
23+
namespace rosbag2
24+
{
25+
26+
class GenericPublisher : public rclcpp::PublisherBase
27+
{
28+
public:
29+
GenericPublisher(
30+
rclcpp::node_interfaces::NodeBaseInterface * node_base,
31+
const std::string & topic,
32+
const rosidl_message_type_support_t & type_support);
33+
34+
~GenericPublisher() override = default;
35+
36+
void publish(std::shared_ptr<rmw_serialized_message_t> message);
37+
};
38+
39+
} // namespace rosbag2
40+
41+
#endif // ROSBAG2__GENERIC_PUBLISHER_HPP_
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2018, Bosch Software Innovations GmbH.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "generic_subscription.hpp"
16+
17+
#include <memory>
18+
#include <string>
19+
20+
#include "rclcpp/any_subscription_callback.hpp"
21+
#include "rclcpp/subscription.hpp"
22+
23+
namespace rosbag2
24+
{
25+
26+
GenericSubscription::GenericSubscription(
27+
std::shared_ptr<rcl_node_t> node_handle,
28+
const rosidl_message_type_support_t & ts,
29+
const std::string & topic_name,
30+
std::function<void(std::shared_ptr<rcutils_char_array_t>)> callback)
31+
: SubscriptionBase(
32+
node_handle,
33+
ts,
34+
topic_name,
35+
rcl_subscription_get_default_options(),
36+
true),
37+
default_allocator_(rcutils_get_default_allocator()),
38+
callback_(callback)
39+
{}
40+
41+
std::shared_ptr<void> GenericSubscription::create_message()
42+
{
43+
return create_serialized_message();
44+
}
45+
46+
std::shared_ptr<rmw_serialized_message_t> GenericSubscription::create_serialized_message()
47+
{
48+
return borrow_serialized_message(0);
49+
}
50+
51+
52+
void GenericSubscription::handle_message(
53+
std::shared_ptr<void> & message, const rmw_message_info_t & message_info)
54+
{
55+
(void) message_info;
56+
auto typed_message = std::static_pointer_cast<rcutils_char_array_t>(message);
57+
callback_(typed_message);
58+
}
59+
60+
void GenericSubscription::return_message(std::shared_ptr<void> & message)
61+
{
62+
auto typed_message = std::static_pointer_cast<rcutils_char_array_t>(message);
63+
return_serialized_message(typed_message);
64+
}
65+
66+
void GenericSubscription::return_serialized_message(
67+
std::shared_ptr<rmw_serialized_message_t> & message)
68+
{
69+
message.reset();
70+
}
71+
72+
void GenericSubscription::handle_intra_process_message(
73+
rcl_interfaces::msg::IntraProcessMessage & ipm,
74+
const rmw_message_info_t & message_info)
75+
{
76+
(void) ipm;
77+
(void) message_info;
78+
throw std::runtime_error("Intra process is not supported");
79+
}
80+
81+
const std::shared_ptr<rcl_subscription_t>
82+
GenericSubscription::get_intra_process_subscription_handle() const
83+
{
84+
return nullptr;
85+
}
86+
87+
std::shared_ptr<rmw_serialized_message_t>
88+
GenericSubscription::borrow_serialized_message(size_t capacity)
89+
{
90+
auto message = new rmw_serialized_message_t;
91+
*message = rmw_get_zero_initialized_serialized_message();
92+
auto init_return = rmw_serialized_message_init(message, capacity, &default_allocator_);
93+
if (init_return != RCL_RET_OK) {
94+
rclcpp::exceptions::throw_from_rcl_error(init_return);
95+
}
96+
97+
auto serialized_msg = std::shared_ptr<rmw_serialized_message_t>(message,
98+
[](rmw_serialized_message_t * msg) {
99+
auto fini_return = rmw_serialized_message_fini(msg);
100+
delete msg;
101+
if (fini_return != RCL_RET_OK) {
102+
RCUTILS_LOG_ERROR_NAMED(
103+
"rosbag2",
104+
"failed to destroy serialized message: %s", rcl_get_error_string_safe());
105+
}
106+
});
107+
108+
return serialized_msg;
109+
}
110+
111+
} // namespace rosbag2

0 commit comments

Comments
 (0)