ArMarkerExternalCameraCalibration.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package Imagine::ArmarXObjects::ArMarkerExternalCameraCalibration
17 * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu )
18 * @date 2020
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
25#include <filesystem>
26
27#include <SimoxUtility/json.h>
28#include <SimoxUtility/math/pose/invert.h>
29#include <SimoxUtility/math/pose/pose.h>
30#include <VirtualRobot/XML/RobotIO.h>
31
34
36
37namespace armarx
38{
39
42 {
45
46 defs->component(localizer);
47 defs->defineOptionalProperty<std::string>("cmp.PointCloudToArViz",
48 "PointCloudToArViz",
49 "Name of the PointCloudToArViz component.");
50
51 defs->optional(localizerMarkerID, "loc.MarkerID", "The marker ID to use (-1 for any ID).");
52
53 defs->optional(robotArMarkerFileName,
54 "robot.ArMarkerRobotFileName",
55 "File name of robot model with ArMarker marker.");
56 defs->optional(robotBaseNodeName, "robot.BaseNodeName", "Name of the base robot node.");
57 defs->optional(robotArMarkerMarkerNodeName,
58 "robot.ArMarkerMarkerNodeName",
59 "Name of the ArMarker marker robot node.");
60
61 defs->optional(calibrationFilePath, "calibrationFilePath", "Path to the calibration file.");
62
63 return defs;
64 }
65
66 std::string
68 {
69 return "ArMarkerExternalCameraCalibration";
70 }
71
72 void
74 {
75 namespace fs = std::filesystem;
76
77 {
78 robotArMarkerFileName = ArmarXDataPath::resolvePath(robotArMarkerFileName);
79 ARMARX_INFO << "Loading robot with ArMarker marker from: " << robotArMarkerFileName;
80 robotArMarker = VirtualRobot::RobotIO::loadRobot(
81 robotArMarkerFileName, VirtualRobot::RobotIO::RobotDescription::eStructure);
82 }
83
84 {
85 fs::path path = calibrationFilePath;
86 fs::path parent_path = ArmarXDataPath::resolvePath(path.parent_path());
87 this->calibrationFilePath = parent_path / path.filename();
88 ARMARX_INFO << "Calibration file: " << calibrationFilePath;
89 }
90 }
91
92 void
94 {
95 getProxyFromProperty(vis.pointCloudToArViz, "cmp.PointCloudToArViz", false, "", false);
96 if (vis.pointCloudToArViz)
97 {
98 ARMARX_INFO << "Found PointCloudToArViz.";
99 }
100
103
104 {
105 vis.layerCamera = arviz.layer("In Camera");
106 vis.layerCamera.add(viz::Pose("Origin"));
107 vis.layerCamera.add(vis.markerPoseInCamera);
108
109 vis.layerRobotBase = arviz.layer("In RobotBase");
110 vis.layerRobotBase.add(vis.markerPoseInRobotBase);
111 vis.layerRobotBase.add(vis.markerModelInRobotBase);
112 vis.layerRobotBase.add(vis.cameraPoseInRobotBase);
113 }
114
115
116 if (task)
117 {
118 task->stop();
119 task->join();
120 task = nullptr;
121 }
122 task = new SimpleRunningTask<>([this]() { this->run(); });
123 task->start();
124 }
125
126 void
128 {
129 task->stop();
130 localizer = nullptr;
131 }
132
133 void
137
138 void
139 ArMarkerExternalCameraCalibration::run()
140 {
141 CycleUtil cycle(50);
142 while (!task->isStopped())
143 {
144 if (!localizer)
145 {
146 break; // Localizer disconnected. Wait for reconnect.
147 }
148
149 visionx::ArMarkerLocalizationResultList localizationResults;
150 try
151 {
152 localizationResults = localizer->GetLatestLocalizationResult();
153 }
154 catch (const Ice::ConnectionRefusedException&)
155 {
156 break; // Localizer disconnected. Wait for reconnect.
157 }
158
159 ARMARX_VERBOSE << "Got " << localizationResults.size() << " localization results.";
160
161 std::optional<visionx::ArMarkerLocalizationResult> result;
162 if (localizationResults.size() > 0)
163 {
164 if (localizerMarkerID < 0)
165 {
166 result = localizationResults.front();
167 }
168 else
169 {
170 for (const auto& r : localizationResults)
171 {
172 if (r.id == localizerMarkerID)
173 {
174 result = r;
175 break;
176 }
177 }
178 }
179 }
180
181 if (result)
182 {
183 ARMARX_VERBOSE << "Using marker with id " << result->id;
184 FramedPosePtr framedPose = FramedPosePtr::dynamicCast(result->pose);
185 Eigen::Matrix4f pose = framedPose->toEigen();
186
187 onLocalizationResult(pose);
188 }
189 else
190 {
191 vis.markerPoseInCamera.scale(0.5);
192 }
193
194 arviz.commit({vis.layerCamera, vis.layerRobotBase});
195
196 cycle.waitForCycleDuration();
197 }
198 }
199
200 void
201 ArMarkerExternalCameraCalibration::onLocalizationResult(
202 const Eigen::Matrix4f& markerPoseInCamera)
203 {
205
206 Eigen::Matrix4f cameraPoseMarker = simox::math::inverted_pose(markerPoseInCamera);
207
208 VirtualRobot::RobotNodePtr arMarkerNode =
209 robotArMarker->getRobotNode(robotArMarkerMarkerNodeName);
210 VirtualRobot::RobotNodePtr baseNode = robotArMarker->getRobotNode(robotBaseNodeName);
211
212 FramedPose framedCameraPose(
213 cameraPoseMarker, arMarkerNode->getName(), robotArMarker->getName());
214 framedCameraPose.changeFrame(robotArMarker, baseNode->getName());
215
216 Eigen::Matrix4f cameraPoseInRobotBase = framedCameraPose.toEigen();
217 Eigen::Matrix4f markerInRobotBase = cameraPoseInRobotBase * markerPoseInCamera;
218
219 vis.markerPoseInCamera.pose(markerPoseInCamera).scale(1.0);
220 vis.markerPoseInRobotBase.pose(baseNode->getPoseInRootFrame() * markerInRobotBase);
221 vis.cameraPoseInRobotBase.pose(baseNode->getPoseInRootFrame() * cameraPoseInRobotBase);
222 {
223 FramedPose framedMarkerModelPose(
224 Eigen::Matrix4f::Identity(), arMarkerNode->getName(), robotArMarker->getName());
225 framedMarkerModelPose.changeFrame(robotArMarker, baseNode->getName());
226 vis.markerModelInRobotBase.pose(baseNode->getPoseInRootFrame() *
227 framedMarkerModelPose.toEigen());
228 }
229
230 {
231 std::scoped_lock lock(markerPoseMutex);
232 this->markerPoseInCamera = markerPoseInCamera;
233 this->cameraPoseInRobotBase = cameraPoseInRobotBase;
234 }
235 if (vis.pointCloudToArViz)
236 {
237 vis.pointCloudToArViz->setCustomTransform(
238 new Pose(baseNode->getPoseInRootFrame() * cameraPoseInRobotBase));
239 }
240 }
241
242 void
243 ArMarkerExternalCameraCalibration::storeCalibration()
244 {
245 ExternalCameraCalibration calibration;
246 {
247 std::scoped_lock lock(markerPoseMutex);
248 calibration.cameraPose = cameraPoseInRobotBase;
249 calibration.cameraPoseFrame = robotBaseNodeName;
250 calibration.timestamp = TimeUtil::GetTime();
251 }
252
253 const nlohmann::json j = calibration;
254
255 ARMARX_IMPORTANT << "Writing calibration to \n"
256 << calibrationFilePath << "\n\n"
257 << j.dump(2);
258 nlohmann::write_json(calibrationFilePath, j, 2);
259 }
260
261 void
263 {
264 using namespace armarx::RemoteGui::Client;
265
266 tab.storeButton.setLabel("Store calibration");
267
268 VBoxLayout root{tab.storeButton, VSpacer()};
269 RemoteGui_createTab(getName(), root, &tab);
270 }
271
272 void
274 {
275 if (tab.storeButton.wasClicked())
276 {
277 storeCalibration();
278 }
279 }
280
281} // namespace armarx
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
static std::string resolvePath(const std::string &path, bool verbose=true)
Resolves environment variables and home paths and tries to make path absolute.
Default component property definition container.
Definition Component.h:70
ProxyType getProxyFromProperty(const std::string &propertyName, bool addToDependencies=false, const std::string &endpoints="", bool throwOnProxyError=true)
Get a proxy whose name is specified by the given property.
Definition Component.h:242
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
This util class helps with keeping a cycle time during a control cycle.
Definition CycleUtil.h:41
std::string getName() const
Retrieve name of object.
bool synchronizeLocalClone(const VirtualRobot::RobotPtr &robot) const
bool isStopped()
Retrieve whether stop() has been called.
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
const VariantTypeId FramedPose
Definition FramedPose.h:36
Eigen::Isometry3f Pose
Definition basic_types.h:31
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
IceInternal::Handle< FramedPose > FramedPosePtr
Definition FramedPose.h:272
SimpleRunningTask(Ts...) -> SimpleRunningTask< std::function< void(void)> >
void RemoteGui_createTab(std::string const &name, RemoteGui::Client::Widget const &rootWidget, RemoteGui::Client::Tab *tab)