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
28
29#include <SimoxUtility/json.h>
30#include <SimoxUtility/math/pose/invert.h>
31#include <SimoxUtility/math/pose/pose.h>
32#include <VirtualRobot/XML/RobotIO.h>
33
36
38
39namespace armarx
40{
41
44 {
47
48 defs->component(localizer);
49 defs->defineOptionalProperty<std::string>("cmp.PointCloudToArViz",
50 "PointCloudToArViz",
51 "Name of the PointCloudToArViz component.");
52
53 defs->optional(localizerMarkerID, "loc.MarkerID", "The marker ID to use (-1 for any ID).");
54
55 defs->optional(robotArMarkerFileName,
56 "robot.ArMarkerRobotFileName",
57 "File name of robot model with ArMarker marker.");
58 defs->optional(robotBaseNodeName, "robot.BaseNodeName", "Name of the base robot node.");
59 defs->optional(robotArMarkerMarkerNodeName,
60 "robot.ArMarkerMarkerNodeName",
61 "Name of the ArMarker marker robot node.");
62
63 defs->optional(calibrationFilePath, "calibrationFilePath", "Path to the calibration file.");
64
65 return defs;
66 }
67
68 std::string
73
74 std::string
76 {
77 return "ArMarkerExternalCameraCalibration";
78 }
79
80 void
82 {
83 namespace fs = std::filesystem;
84
85 {
86 robotArMarkerFileName = ArmarXDataPath::resolvePath(robotArMarkerFileName);
87 ARMARX_INFO << "Loading robot with ArMarker marker from: " << robotArMarkerFileName;
88 robotArMarker = VirtualRobot::RobotIO::loadRobot(
89 robotArMarkerFileName, VirtualRobot::RobotIO::RobotDescription::eStructure);
90 }
91
92 {
93 fs::path path = calibrationFilePath;
94 fs::path parent_path = ArmarXDataPath::resolvePath(path.parent_path());
95 this->calibrationFilePath = parent_path / path.filename();
96 ARMARX_INFO << "Calibration file: " << calibrationFilePath;
97 }
98 }
99
100 void
102 {
103 getProxyFromProperty(vis.pointCloudToArViz, "cmp.PointCloudToArViz", false, "", false);
104 if (vis.pointCloudToArViz)
105 {
106 ARMARX_INFO << "Found PointCloudToArViz.";
107 }
108
111
112 {
113 vis.layerCamera = arviz.layer("In Camera");
114 vis.layerCamera.add(viz::Pose("Origin"));
115 vis.layerCamera.add(vis.markerPoseInCamera);
116
117 vis.layerRobotBase = arviz.layer("In RobotBase");
118 vis.layerRobotBase.add(vis.markerPoseInRobotBase);
119 vis.layerRobotBase.add(vis.markerModelInRobotBase);
120 vis.layerRobotBase.add(vis.cameraPoseInRobotBase);
121 }
122
123
124 if (task)
125 {
126 task->stop();
127 task->join();
128 task = nullptr;
129 }
130 task = new SimpleRunningTask<>([this]() { this->run(); });
131 task->start();
132 }
133
134 void
136 {
137 task->stop();
138 localizer = nullptr;
139 }
140
141 void
145
146 void
147 ArMarkerExternalCameraCalibration::run()
148 {
149 CycleUtil cycle(50);
150 while (!task->isStopped())
151 {
152 if (!localizer)
153 {
154 break; // Localizer disconnected. Wait for reconnect.
155 }
156
157 visionx::ArMarkerLocalizationResultList localizationResults;
158 try
159 {
160 localizationResults = localizer->GetLatestLocalizationResult();
161 }
162 catch (const Ice::ConnectionRefusedException&)
163 {
164 break; // Localizer disconnected. Wait for reconnect.
165 }
166
167 ARMARX_VERBOSE << "Got " << localizationResults.size() << " localization results.";
168
169 std::optional<visionx::ArMarkerLocalizationResult> result;
170 if (localizationResults.size() > 0)
171 {
172 if (localizerMarkerID < 0)
173 {
174 result = localizationResults.front();
175 }
176 else
177 {
178 for (const auto& r : localizationResults)
179 {
180 if (r.id == localizerMarkerID)
181 {
182 result = r;
183 break;
184 }
185 }
186 }
187 }
188
189 if (result)
190 {
191 ARMARX_VERBOSE << "Using marker with id " << result->id;
192 FramedPosePtr framedPose = FramedPosePtr::dynamicCast(result->pose);
193 Eigen::Matrix4f pose = framedPose->toEigen();
194
195 onLocalizationResult(pose);
196 }
197 else
198 {
199 vis.markerPoseInCamera.scale(0.5);
200 }
201
202 arviz.commit({vis.layerCamera, vis.layerRobotBase});
203
204 cycle.waitForCycleDuration();
205 }
206 }
207
208 void
209 ArMarkerExternalCameraCalibration::onLocalizationResult(
210 const Eigen::Matrix4f& markerPoseInCamera)
211 {
213
214 Eigen::Matrix4f cameraPoseMarker = simox::math::inverted_pose(markerPoseInCamera);
215
216 VirtualRobot::RobotNodePtr arMarkerNode =
217 robotArMarker->getRobotNode(robotArMarkerMarkerNodeName);
218 VirtualRobot::RobotNodePtr baseNode = robotArMarker->getRobotNode(robotBaseNodeName);
219
220 FramedPose framedCameraPose(
221 cameraPoseMarker, arMarkerNode->getName(), robotArMarker->getName());
222 framedCameraPose.changeFrame(robotArMarker, baseNode->getName());
223
224 Eigen::Matrix4f cameraPoseInRobotBase = framedCameraPose.toEigen();
225 Eigen::Matrix4f markerInRobotBase = cameraPoseInRobotBase * markerPoseInCamera;
226
227 vis.markerPoseInCamera.pose(markerPoseInCamera).scale(1.0);
228 vis.markerPoseInRobotBase.pose(baseNode->getPoseInRootFrame() * markerInRobotBase);
229 vis.cameraPoseInRobotBase.pose(baseNode->getPoseInRootFrame() * cameraPoseInRobotBase);
230 {
231 FramedPose framedMarkerModelPose(
232 Eigen::Matrix4f::Identity(), arMarkerNode->getName(), robotArMarker->getName());
233 framedMarkerModelPose.changeFrame(robotArMarker, baseNode->getName());
234 vis.markerModelInRobotBase.pose(baseNode->getPoseInRootFrame() *
235 framedMarkerModelPose.toEigen());
236 }
237
238 {
239 std::scoped_lock lock(markerPoseMutex);
240 this->markerPoseInCamera = markerPoseInCamera;
241 this->cameraPoseInRobotBase = cameraPoseInRobotBase;
242 }
243 if (vis.pointCloudToArViz)
244 {
245 vis.pointCloudToArViz->setCustomTransform(
246 new Pose(baseNode->getPoseInRootFrame() * cameraPoseInRobotBase));
247 }
248 }
249
250 void
251 ArMarkerExternalCameraCalibration::storeCalibration()
252 {
253 ExternalCameraCalibration calibration;
254 {
255 std::scoped_lock lock(markerPoseMutex);
256 calibration.cameraPose = cameraPoseInRobotBase;
257 calibration.cameraPoseFrame = robotBaseNodeName;
258 calibration.timestamp = TimeUtil::GetTime();
259 }
260
261 const nlohmann::json j = calibration;
262
263 ARMARX_IMPORTANT << "Writing calibration to \n"
264 << calibrationFilePath << "\n\n"
265 << j.dump(2);
266 nlohmann::write_json(calibrationFilePath, j, 2);
267 }
268
269 void
271 {
272 using namespace armarx::RemoteGui::Client;
273
274 tab.storeButton.setLabel("Store calibration");
275
276 VBoxLayout root{tab.storeButton, VSpacer()};
277 RemoteGui_createTab(getName(), root, &tab);
278 }
279
280 void
282 {
283 if (tab.storeButton.wasClicked())
284 {
285 storeCalibration();
286 }
287 }
288
290
291} // namespace armarx
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
Brief description of class ArMarkerExternalCameraCalibration.
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)