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 
37 namespace 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
135  {
136  }
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  {
204  RobotState::synchronizeLocalClone(robotArMarker);
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::ArmarXDataPath::resolvePath
static std::string resolvePath(const std::string &path, bool verbose=true)
Resolves environment variables and home paths and tries to make path absolute.
Definition: ArmarXDataPath.cpp:538
armarx::SimpleRunningTask
Usage:
Definition: TaskUtil.h:85
armarx::viz::Client::commit
CommitResult commit(StagedCommit const &commit)
Definition: Client.cpp:89
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:190
armarx::navigation::core::Pose
Eigen::Isometry3f Pose
Definition: basic_types.h:31
armarx::VariantType::FramedPose
const VariantTypeId FramedPose
Definition: FramedPose.h:36
armarx::RemoteGui::Client::VBoxLayout
Definition: Widgets.h:167
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:650
armarx::ArMarkerExternalCameraCalibration::getDefaultName
std::string getDefaultName() const override
Definition: ArMarkerExternalCameraCalibration.cpp:67
armarx::FramedPosePtr
IceInternal::Handle< FramedPose > FramedPosePtr
Definition: FramedPose.h:272
armarx::CycleUtil
This util class helps with keeping a cycle time during a control cycle.
Definition: CycleUtil.h:40
armarx::ArMarkerExternalCameraCalibration::RemoteGui_update
void RemoteGui_update() override
Definition: ArMarkerExternalCameraCalibration.cpp:273
armarx::RemoteGui::Client::VSpacer
Definition: Widgets.h:204
armarx::RobotStateComponentPluginUser::synchronizeLocalClone
bool synchronizeLocalClone(const VirtualRobot::RobotPtr &robot) const
Definition: RobotStateComponentPlugin.cpp:470
armarx::ArMarkerExternalCameraCalibration::onExitComponent
void onExitComponent() override
Definition: ArMarkerExternalCameraCalibration.cpp:134
armarx::Component::getProxyFromProperty
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
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:570
armarx::ArMarkerExternalCameraCalibration::createRemoteGuiTab
void createRemoteGuiTab()
Definition: ArMarkerExternalCameraCalibration.cpp:262
FramedPose.h
armarx::ArMarkerExternalCameraCalibration::onConnectComponent
void onConnectComponent() override
Definition: ArMarkerExternalCameraCalibration.cpp:93
armarx::viz::Pose
Definition: Elements.h:178
armarx::ArMarkerExternalCameraCalibration::onInitComponent
void onInitComponent() override
Definition: ArMarkerExternalCameraCalibration.cpp:73
armarx::TimeUtil::GetTime
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition: TimeUtil.cpp:42
armarx::LightweightRemoteGuiComponentPluginUser::RemoteGui_startRunningTask
void RemoteGui_startRunningTask()
Definition: LightweightRemoteGuiComponentPlugin.cpp:119
CycleUtil.h
ExpressionException.h
armarx::Component::getConfigIdentifier
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition: Component.cpp:79
armarx::ArMarkerExternalCameraCalibration::onDisconnectComponent
void onDisconnectComponent() override
Definition: ArMarkerExternalCameraCalibration.cpp:127
armarx::ComponentPropertyDefinitions
Default component property definition container.
Definition: Component.h:69
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
armarx::ArVizComponentPluginUser::arviz
armarx::viz::Client arviz
Definition: ArVizComponentPlugin.h:42
armarx::LightweightRemoteGuiComponentPluginUser::RemoteGui_createTab
void RemoteGui_createTab(std::string const &name, RemoteGui::Client::Widget const &rootWidget, RemoteGui::Client::Tab *tab)
Definition: LightweightRemoteGuiComponentPlugin.cpp:103
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::ArMarkerExternalCameraCalibration::createPropertyDefinitions
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: ArMarkerExternalCameraCalibration.cpp:41
armarx::ManagedIceObject::getName
std::string getName() const
Retrieve name of object.
Definition: ManagedIceObject.cpp:108
armarx::viz::Client::layer
Layer layer(std::string const &name) const
Definition: Client.cpp:80
ArMarkerExternalCameraCalibration.h
armarx::RemoteGui::Client
Definition: EigenWidgets.cpp:8
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27