Skip to content

Commit 0e7af5e

Browse files
authored
Moving variable sync from fuse_publishers to fuse_variables (#413)
1 parent 095de24 commit 0e7af5e

File tree

8 files changed

+362
-312
lines changed

8 files changed

+362
-312
lines changed

fuse_models/include/fuse_models/odometry_2d_publisher.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
#include <fuse_core/transaction.h>
4343
#include <fuse_core/uuid.h>
4444
#include <fuse_core/variable.h>
45-
#include <fuse_publishers/stamped_variable_synchronizer.h>
45+
#include <fuse_variables/stamped_variable_synchronizer.h>
4646

4747
#include <geometry_msgs/AccelWithCovarianceStamped.h>
4848
#include <nav_msgs/Odometry.h>
@@ -172,7 +172,7 @@ class Odometry2DPublisher : public fuse_core::AsyncPublisher
172172
/**
173173
* @brief Object that searches for the most recent common timestamp for a set of variables
174174
*/
175-
using Synchronizer = fuse_publishers::StampedVariableSynchronizer<fuse_variables::Orientation2DStamped,
175+
using Synchronizer = fuse_variables::StampedVariableSynchronizer<fuse_variables::Orientation2DStamped,
176176
fuse_variables::Position2DStamped,
177177
fuse_variables::VelocityLinear2DStamped,
178178
fuse_variables::VelocityAngular2DStamped,

fuse_publishers/CMakeLists.txt

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -164,28 +164,4 @@ if(CATKIN_ENABLE_TESTING)
164164
CXX_STANDARD 17
165165
CXX_STANDARD_REQUIRED YES
166166
)
167-
168-
# StampedVariableSynchronizer Tests
169-
catkin_add_gtest(test_stamped_variable_synchronizer
170-
test/test_stamped_variable_synchronizer.cpp
171-
)
172-
add_dependencies(test_stamped_variable_synchronizer
173-
${catkin_EXPORTED_TARGETS}
174-
)
175-
target_include_directories(test_stamped_variable_synchronizer
176-
PRIVATE
177-
include
178-
)
179-
target_include_directories(test_stamped_variable_synchronizer
180-
SYSTEM PRIVATE
181-
${catkin_INCLUDE_DIRS}
182-
)
183-
target_link_libraries(test_stamped_variable_synchronizer
184-
${catkin_LIBRARIES}
185-
)
186-
set_target_properties(test_stamped_variable_synchronizer
187-
PROPERTIES
188-
CXX_STANDARD 17
189-
CXX_STANDARD_REQUIRED YES
190-
)
191167
endif()

fuse_publishers/include/fuse_publishers/pose_2d_publisher.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
#ifndef FUSE_PUBLISHERS_POSE_2D_PUBLISHER_H
3535
#define FUSE_PUBLISHERS_POSE_2D_PUBLISHER_H
3636

37-
#include <fuse_publishers/stamped_variable_synchronizer.h>
37+
#include <fuse_variables/stamped_variable_synchronizer.h>
3838

3939
#include <fuse_core/async_publisher.h>
4040
#include <fuse_core/graph.h>
@@ -149,7 +149,7 @@ class Pose2DPublisher : public fuse_core::AsyncPublisher
149149
void tfPublishTimerCallback(const ros::TimerEvent& event);
150150

151151
protected:
152-
using Synchronizer = StampedVariableSynchronizer<fuse_variables::Orientation2DStamped,
152+
using Synchronizer = fuse_variables::StampedVariableSynchronizer<fuse_variables::Orientation2DStamped,
153153
fuse_variables::Position2DStamped>;
154154

155155
std::string base_frame_; //!< The name of the robot's base_link frame

fuse_publishers/include/fuse_publishers/stamped_variable_synchronizer.h

Lines changed: 3 additions & 282 deletions
Original file line numberDiff line numberDiff line change
@@ -34,288 +34,9 @@
3434
#ifndef FUSE_PUBLISHERS_STAMPED_VARIABLE_SYNCHRONIZER_H
3535
#define FUSE_PUBLISHERS_STAMPED_VARIABLE_SYNCHRONIZER_H
3636

37-
#include <fuse_core/graph.h>
38-
#include <fuse_core/fuse_macros.h>
39-
#include <fuse_core/transaction.h>
40-
#include <fuse_core/uuid.h>
41-
#include <fuse_core/variable.h>
42-
#include <fuse_variables/stamped.h>
43-
#include <ros/time.h>
37+
#include <fuse_variables/stamped_variable_synchronizer.h>
4438

45-
#include <type_traits>
46-
47-
48-
namespace fuse_publishers
49-
{
50-
51-
/**
52-
* @brief A utility class that finds the most recent timestamp shared by a set of stamped variables
53-
*
54-
* This is designed to be used by derived fuse_core::Publisher classes. The class remembers the last common timestamp
55-
* from the previous call, and attempts to find a more recent common timestamp using the provided transaction
56-
* information. If no common timestamp is found after searching the transaction, a full search of the graph will
57-
* be conducted. If no common timestamp is found after searching the full graph, a zero timestamp will be returned.
58-
*
59-
* The set of variable types are provided in the template parameters. e.g.
60-
* @code{.cpp}
61-
* auto synchronizer = StampedVariableSynchronizer<Orientation2DStamped, Position2DStamped>(device_id);
62-
* @endcode
63-
*
64-
* This class only functions with variables derived from the fuse_variables::Stamped base class.
65-
*/
66-
template <typename ...Ts>
67-
class StampedVariableSynchronizer
68-
{
69-
public:
70-
FUSE_SMART_PTR_DEFINITIONS(StampedVariableSynchronizer);
71-
static const ros::Time TIME_ZERO; //!< Constant representing a zero timestamp
72-
73-
/**
74-
* @brief Construct a synchronizer object
75-
*
76-
* @param[in] device_id The device id to use for all variable types
77-
*/
78-
explicit StampedVariableSynchronizer(const fuse_core::UUID& device_id = fuse_core::uuid::NIL);
79-
80-
/**
81-
* @brief Find the latest timestamp for which variables of all the specified template types exist in the graph
82-
*
83-
* @param[in] transaction A fuse_core::Transaction object containing the changes to the graph since the last call
84-
* @param[in] graph The complete graph
85-
* @return The latest timestamp shared by all requested variable types
86-
*/
87-
ros::Time findLatestCommonStamp(const fuse_core::Transaction& transaction, const fuse_core::Graph& graph);
88-
89-
private:
90-
fuse_core::UUID device_id_; //!< The device_id to use with the Stamped classes
91-
ros::Time latest_common_stamp_; //!< The previously discovered common stamp
92-
93-
/**
94-
* @brief Search the variables in the provided range for more recent timestamps. Update the \p latest_common_stamp_
95-
* member variable if a newer common timestamp is found.
96-
*
97-
* @param[in] variable_range The collection of variables to test
98-
* @param[in] graph The complete graph, used to verify that all requested variables exist for a given time
99-
*/
100-
template <typename VariableRange>
101-
void updateTime(const VariableRange& variable_range, const fuse_core::Graph& graph);
102-
};
103-
104-
namespace detail
105-
{
106-
107-
/**
108-
* @brief Some helper structs for testing properties of all types in a template parameter pack
109-
*/
110-
template<bool...> struct bool_pack;
111-
template<bool ...bs>
112-
using all_true_helper = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;
113-
114-
/**
115-
* @brief Test if a property is true for all types in a template parameter pack. This is a type.
116-
*/
117-
template <typename ...Ts>
118-
using all_true = all_true_helper<Ts::value...>;
119-
120-
/**
121-
* @brief Test if a property is true for all types in a template parameter pack. This is a boolean value.
122-
*/
123-
template<typename ...Ts>
124-
constexpr bool allTrue = all_true<Ts...>::value;
125-
126-
/**
127-
* @brief Test if a class is derived from the fuse_variables::Stamped base class. This is a type.
128-
*/
129-
template<typename T>
130-
using is_stamped = std::is_base_of<fuse_variables::Stamped, T>;
131-
132-
/**
133-
* @brief Test if a class is derived from the fuse_variables::Stamped base class. This is a boolean value.
134-
*/
135-
template<typename T>
136-
constexpr bool isStamped = is_stamped<T>::value;
137-
138-
/**
139-
* @brief Test if a class is derived from the fuse_core::Variable base class. This is a type.
140-
*/
141-
template<typename T>
142-
using is_variable = std::is_base_of<fuse_core::Variable, T>;
143-
144-
/**
145-
* @brief Test if a class is derived from the fuse_core::Variable base class. This is a boolean value.
146-
*/
147-
template<typename T>
148-
constexpr bool isVariable = is_variable<T>::value;
149-
150-
/**
151-
* @brief Test if a class is derived from both the fuse_core::Variable base class and the fuse_variables::Stamped
152-
* base class. This is a type.
153-
*/
154-
template<typename T>
155-
struct is_stamped_variable
156-
{
157-
static constexpr bool value = isStamped<T> && isVariable<T>;
158-
};
159-
160-
/**
161-
* @brief Test if a class is derived from both the fuse_core::Variable base class and the fuse_variables::Stamped
162-
* base class. This is a boolean value.
163-
*/
164-
template<typename T>
165-
constexpr bool isStampedVariable = is_stamped_variable<T>::value;
166-
167-
/**
168-
* @brief Test if all of the template parameter pack types are fuse_core::Variable and fuse_variables::Stamped.
169-
* This is a type.
170-
*/
171-
template <typename ...Ts>
172-
using all_stamped_variables = all_true<is_stamped_variable<Ts>...>;
173-
174-
/**
175-
* @brief Test if all of the template parameter pack types are fuse_core::Variable and fuse_variables::Stamped.
176-
* This is a boolean value.
177-
*/
178-
template<typename ...Ts>
179-
constexpr bool allStampedVariables = all_stamped_variables<Ts...>::value;
180-
181-
/**
182-
* @brief Test if instances of all the template parameter pack types exist in the graph
183-
*
184-
* This version accepts an empty parameter pack, and is used to terminate the recursive template parameter pack
185-
* expansion.
186-
*
187-
* This would be much easier to write in C++17 using 'if constexpr (sizeof...(Ts) > 0)'
188-
*
189-
* @param[in] graph The complete graph, used to verify the existence of a variable
190-
* @param[in] stamp The timestamp used to construct all variable types
191-
* @param[in] device_id The device id used to construct all variable types
192-
* @return True if all variables exist, false otherwise
193-
*/
194-
template <typename...>
195-
struct all_variables_exist
196-
{
197-
static bool value(const fuse_core::Graph& /*graph*/, const ros::Time& /*stamp*/, const fuse_core::UUID& /*device_id*/)
198-
{
199-
return true;
200-
}
201-
};
202-
203-
/**
204-
* @brief Test if instances of all the template parameter pack types exist in the graph
205-
*
206-
* This version accepts two or more template arguments. The template parameter pack is expanded recursively.
207-
*
208-
* @param[in] graph The complete graph, used to verify the existence of a variable
209-
* @param[in] stamp The timestamp used to construct all variable types
210-
* @param[in] device_id The device id used to construct all variable types
211-
* @return True if all variables exist, false otherwise
212-
*/
213-
template <typename T, typename ...Ts>
214-
struct all_variables_exist<T, Ts...>
215-
{
216-
static bool value(const fuse_core::Graph& graph, const ros::Time& stamp, const fuse_core::UUID& device_id)
217-
{
218-
return graph.variableExists(T(stamp, device_id).uuid()) &&
219-
all_variables_exist<Ts...>::value(graph, stamp, device_id);
220-
}
221-
};
222-
223-
/**
224-
* @brief Test if a given variable is included in the template parameter pack types
225-
*
226-
* This version accepts an empty parameter pack, and is used to terminate the recursive template parameter pack
227-
* expansion.
228-
*
229-
* This would be much easier to write in C++17 using 'if constexpr (sizeof...(Ts) > 0)'
230-
*
231-
* @param[in] variable The variable to check against the template parameter pack
232-
* @return True if the variable's type is part of the template parameter pack, false otherwise
233-
*/
234-
template <typename...>
235-
struct is_variable_in_pack
236-
{
237-
static bool value(const fuse_core::Variable& /*variable*/)
238-
{
239-
return false;
240-
}
241-
};
242-
243-
/**
244-
* @brief Test if a given variable is included in the template parameter pack types
245-
*
246-
* This version accepts two or more template arguments. The template parameter pack is expanded recursively.
247-
*
248-
* @param[in] variable The variable to check against the template parameter pack
249-
* @return True if the variable's type is part of the template parameter pack, false otherwise
250-
*/
251-
template <typename T, typename ...Ts>
252-
struct is_variable_in_pack<T, Ts...>
253-
{
254-
static bool value(const fuse_core::Variable& variable)
255-
{
256-
auto derived = dynamic_cast<const T*>(&variable);
257-
return static_cast<bool>(derived) ||
258-
is_variable_in_pack<Ts...>::value(variable);
259-
}
260-
};
261-
262-
} // namespace detail
263-
264-
template <typename ...Ts>
265-
const ros::Time StampedVariableSynchronizer<Ts...>::TIME_ZERO = ros::Time(0, 0);
266-
267-
template <typename ...Ts>
268-
StampedVariableSynchronizer<Ts...>::StampedVariableSynchronizer(const fuse_core::UUID& device_id) :
269-
device_id_(device_id),
270-
latest_common_stamp_(TIME_ZERO)
271-
{
272-
static_assert(detail::allStampedVariables<Ts...>, "All synchronized types must be derived from both "
273-
"fuse_core::Variable and fuse_variable::Stamped.");
274-
static_assert(sizeof...(Ts) > 0, "At least one type must be specified.");
275-
}
276-
277-
template <typename ...Ts>
278-
ros::Time StampedVariableSynchronizer<Ts...>::findLatestCommonStamp(
279-
const fuse_core::Transaction& transaction,
280-
const fuse_core::Graph& graph)
281-
{
282-
// Clear the previous stamp if the variable was deleted
283-
if (latest_common_stamp_ != TIME_ZERO &&
284-
!detail::all_variables_exist<Ts...>::value(graph, latest_common_stamp_, device_id_))
285-
{
286-
latest_common_stamp_ = TIME_ZERO;
287-
}
288-
// Search the transaction for more recent variables
289-
updateTime(transaction.addedVariables(), graph);
290-
// If no common timestamp was found, search the whole graph for the most recent variable set
291-
if (latest_common_stamp_ == TIME_ZERO)
292-
{
293-
updateTime(graph.getVariables(), graph);
294-
}
295-
return latest_common_stamp_;
296-
}
297-
298-
template <typename ...Ts>
299-
template <typename VariableRange>
300-
void StampedVariableSynchronizer<Ts...>::updateTime(
301-
const VariableRange& variable_range,
302-
const fuse_core::Graph& graph)
303-
{
304-
for (const auto& candidate_variable : variable_range)
305-
{
306-
if (detail::is_variable_in_pack<Ts...>::value(candidate_variable))
307-
{
308-
const auto& stamped_variable = dynamic_cast<const fuse_variables::Stamped&>(candidate_variable);
309-
if ((stamped_variable.stamp() > latest_common_stamp_) &&
310-
(stamped_variable.deviceId() == device_id_) &&
311-
(detail::all_variables_exist<Ts...>::value(graph, stamped_variable.stamp(), device_id_)))
312-
{
313-
latest_common_stamp_ = stamped_variable.stamp();
314-
}
315-
}
316-
}
317-
}
318-
319-
} // namespace fuse_publishers
39+
#pragma message("The StampedVariableSynchronizer class has been moved to the fuse_variables package. " \
40+
"Please include that header instead.")
32041

32142
#endif // FUSE_PUBLISHERS_STAMPED_VARIABLE_SYNCHRONIZER_H

fuse_variables/CMakeLists.txt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ install(
9797
#############
9898

9999
if(CATKIN_ENABLE_TESTING)
100+
set(test_depends
101+
fuse_graphs
102+
)
103+
find_package(catkin REQUIRED COMPONENTS
104+
${build_depends}
105+
${test_depends}
106+
)
100107
find_package(roslint REQUIRED)
101108
find_package(rostest REQUIRED)
102109

@@ -583,4 +590,28 @@ if(CATKIN_ENABLE_TESTING)
583590
CXX_STANDARD 17
584591
CXX_STANDARD_REQUIRED YES
585592
)
593+
594+
# StampedVariableSynchronizer Tests
595+
catkin_add_gtest(test_stamped_variable_synchronizer
596+
test/test_stamped_variable_synchronizer.cpp
597+
)
598+
add_dependencies(test_stamped_variable_synchronizer
599+
${catkin_EXPORTED_TARGETS}
600+
)
601+
target_include_directories(test_stamped_variable_synchronizer
602+
PRIVATE
603+
include
604+
${catkin_INCLUDE_DIRS}
605+
${CERES_INCLUDE_DIRS}
606+
)
607+
target_link_libraries(test_stamped_variable_synchronizer
608+
${PROJECT_NAME}
609+
${catkin_LIBRARIES}
610+
${CERES_LIBRARIES}
611+
)
612+
set_target_properties(test_stamped_variable_synchronizer
613+
PROPERTIES
614+
CXX_STANDARD 17
615+
CXX_STANDARD_REQUIRED YES
616+
)
586617
endif()

0 commit comments

Comments
 (0)