SMACC2
Loading...
Searching...
No Matches
cp_april_visualization.hpp
Go to the documentation of this file.
1// Copyright 2025 Robosoft Inc.
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/*****************************************************************************************************************
16 *
17 * Authors: Pablo Inigo Blasco, Brett Aldrich
18 *
19 ******************************************************************************************************************/
20#pragma once
21
22#include <smacc2/common.hpp>
23#include <smacc2/component.hpp>
24
25#include <rclcpp/rclcpp.hpp>
26
27#include <memory>
28#include <mutex>
29#include <vector>
30
31#include <std_msgs/msg/header.hpp>
32#include <visualization_msgs/msg/marker_array.hpp>
33
35
36using namespace std::chrono_literals;
37using std::chrono_literals::operator""s;
38
39namespace cl_isaac_apriltag
40{
41
50{
51public:
53
55
56 void onInitialize() override
57 {
58 // Get tracker component via requiresComponent pattern (NOT owner_ cast!)
60
62 getNode()->create_publisher<visualization_msgs::msg::MarkerArray>("/markers_2", 10);
63 }
64
65 std::optional<tf2::Transform> getGlobalApriltagTransform()
66 {
67 std::lock_guard<std::mutex> lock(m_mutex_);
69 }
70
72 {
73 std::stringstream ss;
74
75 ss << "[CpAprilTagVisualization] computeAggregatedMarker" << std::endl;
76
77 // Access tracker via requiresComponent (NOT owner_ cast!)
78 ss << "[CpAprilTagVisualization] getTagsWithinTime" << std::endl;
79 auto tags = tracker_->getTagsWithinTime(0.5s);
80
81 // Average apriltag position
82 double avgX = 0;
83 double avgY = 0;
84 double avgZ = 0;
85 for (auto & apriltag : tags)
86 {
87 avgX += apriltag.second.pose.position.x;
88 avgY += apriltag.second.pose.position.y;
89 avgZ += apriltag.second.pose.position.z;
90 }
91
92 if (tags.size() == 0)
93 {
94 RCLCPP_INFO_THROTTLE(
95 getLogger(), *(getNode()->get_clock()), 1000,
96 "[CpAprilTagVisualization] no apriltags detected to visualize");
97 return;
98 }
99
100 avgX /= tags.size();
101 avgY /= tags.size();
102 avgZ /= tags.size();
103
104 // Subtract some small forward offset from apriltag position for the goal position
105 avgX -= 0.15;
106
107 ss << "[CpAprilTagVisualization] detected " << tags.size() << " tags" << std::endl;
108 ss << "[CpAprilTagVisualization] avgX: " << avgX << ", avgY: " << avgY << ", avgZ: " << avgZ
109 << std::endl;
110
111 tf2::Transform apriltagTransform;
112 apriltagTransform.setOrigin(tf2::Vector3(avgX, avgY, 0.0));
113 apriltagTransform.setRotation(tf2::Quaternion(0.0, 0.0, 0.0, 1.0));
114
115 globalApriltagTransform_ = apriltagTransform;
116
117 ss << "[CpAprilTagVisualization] apriltagTransform: " << apriltagTransform.getOrigin().x()
118 << ", " << apriltagTransform.getOrigin().y() << ", " << apriltagTransform.getOrigin().z();
119 ss << "[CpAprilTagVisualization] globalApriltagTransform: "
120 << globalApriltagTransform_->getOrigin().x() << ", "
121 << globalApriltagTransform_->getOrigin().y() << ", "
122 << globalApriltagTransform_->getOrigin().z();
123 RCLCPP_INFO_THROTTLE(getLogger(), *(getNode()->get_clock()), 1000, ss.str().c_str());
124 }
125
126 virtual void update() override
127 {
129 {
131
132 // Publish visualization markers of the apriltag global estimation
133 visualization_msgs::msg::MarkerArray markerArray;
134
135 visualization_msgs::msg::Marker marker;
136 marker.header.frame_id = "map";
137 marker.header.stamp = getNode()->now();
138 marker.ns = "apriltag";
139 marker.id = 0;
140 marker.action = visualization_msgs::msg::Marker::ADD;
141
142 // Lifetime of 0.5s
143 marker.lifetime = rclcpp::Duration(0.5s);
144
145 // Type sphere
146 marker.type = visualization_msgs::msg::Marker::SPHERE;
147
148 auto origin = globalApriltagTransform_->getOrigin();
149 marker.pose.position.x = origin.x();
150 marker.pose.position.y = origin.y();
151 marker.pose.position.z = origin.z();
152
153 auto rotation = globalApriltagTransform_->getRotation();
154 marker.pose.orientation.w = rotation.w();
155 marker.pose.orientation.y = rotation.y();
156 marker.pose.orientation.z = rotation.z();
157 marker.pose.orientation.x = rotation.x();
158
159 RCLCPP_INFO_THROTTLE(
160 getLogger(), *(getNode()->get_clock()), 1000,
161 "[CpAprilTagVisualization] marker position: %f, %f, %f", origin.x(), origin.y(),
162 origin.z());
163
164 // Red color
165 marker.color.r = 1.0;
166 marker.color.g = 0.0;
167 marker.color.b = 0.0;
168 marker.color.a = 1.0;
169
170 marker.scale.x = 0.1;
171 marker.scale.y = 0.1;
172 marker.scale.z = 0.1;
173
174 markerArray.markers.push_back(marker);
175
176 markerPublisher_->publish(markerArray);
177 }
178 }
179
180protected:
181 std::mutex m_mutex_;
182
183 // Tracker component (obtained via requiresComponent)
185
186 rclcpp::Publisher<visualization_msgs::msg::MarkerArray>::SharedPtr markerPublisher_;
187 std::optional<tf2::Transform> globalApriltagTransform_;
188};
189
190} // namespace cl_isaac_apriltag
Component that tracks AprilTag detections and transforms them to a target frame.
std::map< std::string, geometry_msgs::msg::PoseStamped > getTagsWithinTime(rclcpp::Duration duration)
Get tags detected within the specified duration from now.
Component that visualizes AprilTag detections in RViz.
std::optional< tf2::Transform > getGlobalApriltagTransform()
rclcpp::Publisher< visualization_msgs::msg::MarkerArray >::SharedPtr markerPublisher_
std::optional< tf2::Transform > globalApriltagTransform_
rclcpp::Logger getLogger() const
void requiresComponent(TComponent *&requiredComponentStorage, ComponentRequirement requirementType=ComponentRequirement::SOFT)
rclcpp::Node::SharedPtr getNode()