transform_tree.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #include "core/basic_obj_types.hpp"
  2. #include "core/global_defs.h"
  3. #include "utility/bit_operations.hpp"
  4. #include "utility/config_utility.hpp"
  5. #include "utility/coro_worker.hpp"
  6. #include "utility/coro_worker_helper_func.hpp"
  7. #include "utility/coro_signal_group.hpp"
  8. #include "utility/named_vector.hpp"
  9. #include <boost/asio/co_spawn.hpp>
  10. #include <boost/asio/detached.hpp>
  11. #include <Eigen/Geometry>
  12. #include <list>
  13. #include <optional>
  14. #include <string>
  15. #include <vector>
  16. #include <utility>
  17. #include "utility/assert_utility.h"
  18. DEFAULT_TRISTATE_OBJ_DEF(transform_tree)
  19. namespace sophiar {
  20. using namespace Eigen;
  21. using boost::asio::co_spawn;
  22. using boost::asio::detached;
  23. struct transform_tree::impl {
  24. using node_index_type = uint8_t;
  25. using trans_type = Isometry3d;
  26. static_assert(std::is_same<trans_type, decltype(std::declval<transform_obj>().value)>());
  27. struct node_type { // 在父亲下观察自己
  28. node_index_type parent = -1, depth = 0; // 父亲的编号, 节点深度
  29. variable_index_type transform_var_index = -1;
  30. trans_type fixed_transform; // 如果不提供 transform_var_index, 则表示这是一个固定变换
  31. };
  32. struct query_scheme {
  33. std::list<node_index_type> left, right;
  34. };
  35. named_vector<node_index_type, node_type> nodes;
  36. std::vector<coro_worker::pointer> worker_list;
  37. std::optional<trans_type> get_transform_from_path(const std::list<node_index_type> &path) const {
  38. auto ret = trans_type::Identity();
  39. for (auto index: path) {
  40. const auto &node_info = nodes[index];
  41. if (!is_valid_id(node_info.transform_var_index)) {
  42. ret = ret * node_info.fixed_transform;
  43. } else {
  44. auto trans_obj = QUERY_VARIABLE(transform_obj, node_info.transform_var_index);
  45. if (trans_obj == nullptr) return std::nullopt;
  46. ret = ret * trans_obj->value;
  47. }
  48. }
  49. return ret;
  50. }
  51. std::optional<trans_type> get_transform_from_scheme(const query_scheme &scheme) const {
  52. auto left_trans = get_transform_from_path(scheme.left);
  53. auto right_trans = get_transform_from_path(scheme.right);
  54. if (!left_trans.has_value() || !right_trans.has_value()) return std::nullopt;
  55. return left_trans.value().inverse() * right_trans.value();
  56. }
  57. void create_worker(node_index_type observer,
  58. node_index_type target,
  59. variable_index_type out_var_index) {
  60. assert(is_valid_id(observer) && is_valid_id(target));
  61. assert(observer != target);
  62. query_scheme scheme;
  63. auto signal_group = coro_signal_any_group::new_instance();
  64. while (observer != target) {
  65. const auto &obs_info = nodes[observer];
  66. const auto &tar_info = nodes[target];
  67. if (obs_info.depth > tar_info.depth) {
  68. assert(is_valid_id(obs_info.parent));
  69. scheme.left.push_front(observer);
  70. if (is_valid_id(obs_info.transform_var_index)) {
  71. signal_group->add_watcher(REQUIRE_VARIABLE_WATCHER(obs_info.transform_var_index));
  72. }
  73. observer = obs_info.parent;
  74. } else { // target is deeper
  75. assert(is_valid_id(tar_info.parent));
  76. scheme.right.push_front(target);
  77. if (is_valid_id(tar_info.transform_var_index)) {
  78. signal_group->add_watcher(REQUIRE_VARIABLE_WATCHER(tar_info.transform_var_index));
  79. }
  80. target = tar_info.parent;
  81. }
  82. }
  83. signal_group->start();
  84. auto signal_watcher = signal_group->new_watcher();
  85. auto exit_func = SIGNAL_GROUP_AUTO_CLOSER(signal_group);
  86. auto worker_func = [=, this,
  87. first_run = true,
  88. scheme = std::move(scheme),
  89. signal_watcher = std::move(signal_watcher)]() mutable
  90. -> boost::asio::awaitable<bool> {
  91. if (!first_run) { // set initial value for watched transform
  92. co_await signal_watcher.coro_wait();
  93. }
  94. auto new_trans = get_transform_from_scheme(scheme);
  95. auto new_trans_obj = new_trans.has_value() ?
  96. transform_obj::new_instance(std::move(new_trans.value())) : nullptr;
  97. UPDATE_VARIABLE(transform_obj, out_var_index, new_trans_obj);
  98. first_run = false;
  99. co_return true;
  100. };
  101. auto worker = make_infinite_coro_worker(std::move(worker_func),
  102. std::move(exit_func)); // signal group will be deleted here
  103. worker->run();
  104. worker_list.push_back(std::move(worker));
  105. }
  106. boost::asio::awaitable<void> stop_workers() {
  107. for (auto &worker: worker_list) {
  108. worker->cancel();
  109. }
  110. for (auto &worker: worker_list) {
  111. co_await worker->coro_wait_stop();
  112. }
  113. worker_list.clear();
  114. co_return;
  115. }
  116. void build_tree(const nlohmann::json &config) {
  117. ENSURE_ARRAY("node_list");
  118. for (auto &node: config["node_list"]) {
  119. auto name = LOAD_STRING_ITEM2(node, "name");
  120. auto index = nodes.new_elem(name);
  121. node_index_type parent_index = -1;
  122. if (node.contains("parent")) {
  123. auto parent_name = LOAD_STRING_ITEM2(node, "parent");
  124. parent_index = nodes.to_index_by_name(parent_name);
  125. }
  126. variable_index_type transform_var_index = invalid_variable_index;
  127. if (node.contains("transform_var_name")) {
  128. transform_var_index = LOAD_VARIABLE_INDEX2(node, transform_obj, "transform_var_name");
  129. }
  130. trans_type default_trans = trans_type::Identity();
  131. if (node.contains("transform")) {
  132. default_trans = transform_obj::read_value_from_json_array(node["transform"]);
  133. } else if (is_valid_id(parent_index)) {
  134. assert(is_valid_id(transform_var_index));
  135. }
  136. auto &node_info = nodes[index];
  137. node_info.parent = parent_index;
  138. node_info.transform_var_index = transform_var_index;
  139. node_info.fixed_transform = default_trans;
  140. if (is_valid_id(parent_index)) {
  141. node_info.depth = nodes[parent_index].depth + 1;
  142. }
  143. }
  144. }
  145. void config_watcher(const nlohmann::json &config) {
  146. ENSURE_ARRAY("watch_list");
  147. for (auto &watch_config: config["watch_list"]) {
  148. auto target_name = LOAD_STRING_ITEM2(watch_config, "target");
  149. auto observer_name = LOAD_STRING_ITEM2(watch_config, "observer");
  150. auto target_index = nodes.to_index_by_name(target_name);
  151. auto observer_index = nodes.to_index_by_name(observer_name);
  152. auto transform_obj_index = LOAD_VARIABLE_INDEX2(watch_config, transform_obj, "transform_var_name");
  153. create_worker(observer_index, target_index, transform_obj_index);
  154. }
  155. }
  156. };
  157. transform_tree::transform_tree()
  158. : pimpl(std::make_unique<impl>()) {}
  159. transform_tree::~transform_tree() = default;
  160. boost::asio::awaitable<bool> transform_tree::on_init(const nlohmann::json &config) noexcept {
  161. pimpl->build_tree(config);
  162. co_return true;
  163. }
  164. boost::asio::awaitable<bool> transform_tree::on_start(const nlohmann::json &config) noexcept {
  165. pimpl->config_watcher(config);
  166. co_return true;
  167. }
  168. boost::asio::awaitable<void> transform_tree::on_stop() noexcept {
  169. co_await pimpl->stop_workers();
  170. co_return;
  171. }
  172. boost::asio::awaitable<void> transform_tree::on_reset() noexcept {
  173. pimpl->nodes.clear();
  174. co_return;
  175. }
  176. }