KITHandUnit.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 RobotAPI::ArmarXObjects::KITHandUnit
17 * @author Stefan Reither ( stefan dot reither at kit dot edu )
18 * @date 2019
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "KITHandUnit.h"
24
25#include <algorithm>
26
28
30
32
33using namespace KITHand;
34
35namespace armarx
36{
39 {
41 "ConnectionType",
42 KITHandCommunicationDriver::ScanMode::Bluetooth,
43 "Type of the connection to the hand, either Bluetooth or Serial")
44 .map("Bluetooth", KITHandCommunicationDriver::ScanMode::Bluetooth)
45 .map("Serial", KITHandCommunicationDriver::ScanMode::Serial);
47 "MAC-Address of the hand to connect to.");
49 "AutomaticReconnectActive",
50 false,
51 "Whether the hand unit should try to reconnect after the connection is lost.");
53 "ScanUntilHandFound",
54 true,
55 "Wheather to keep scanning until the hand with the given MAC-Address is found.");
56 defineOptionalProperty<int>("ScanTimeout", 5, "Timeout for scanning repeatedly.");
57 }
58
59 std::string
61 {
62 return "KITHandUnit";
63 }
64
65 void
67 {
68 //addShapeName("Open"); //is added by something else already
69 addShapeName("Close");
70 addShapeName("G0");
71 addShapeName("G1");
72 addShapeName("G2");
73 addShapeName("G3");
74 addShapeName("G4");
75 addShapeName("G5");
76 addShapeName("G6");
77 addShapeName("G7");
78 addShapeName("G8");
79
80 _driver = std::make_unique<KITHandCommunicationDriver>();
81 _driver->registerConnectionStateChangedCallback(
82 std::bind(&KITHandUnit::connectionStateChangedCallback, this, std::placeholders::_1));
83 }
84
85 void
87 {
88 std::string macAddress = getProperty<std::string>("MAC-Address");
89 KITHandCommunicationDriver::ScanMode mode =
90 getProperty<KITHandCommunicationDriver::ScanMode>("ConnectionType").getValue();
91 bool found = false;
92 auto start = std::chrono::system_clock::now();
93 do
94 {
95 std::vector<HandDevice> devices = _driver->scanForDevices(mode);
96 for (HandDevice& d : devices)
97 {
98 if (mode == KITHandCommunicationDriver::ScanMode::Bluetooth)
99 {
100 ARMARX_INFO << "Found device with MAC-Address: " << d.macAdress;
101 }
102 else if (mode == KITHandCommunicationDriver::ScanMode::Serial)
103 {
104 ARMARX_INFO << "Found device at serial port: " << d.serialDeviceFile;
105 }
106 else
107 {
108 ARMARX_INFO << "Found hand"; //TODO
109 }
110 if (d.macAdress == macAddress ||
111 (mode == KITHandCommunicationDriver::ScanMode::Serial))
112 {
113 d.hardwareTarget = mode == KITHandCommunicationDriver::ScanMode::Bluetooth
114 ? KITHand::HardwareTarget::Bluetooth
115 : KITHand::HardwareTarget::Serial;
116 _driver->connect(d);
117 while (!_driver->connected())
118 {
119 std::this_thread::sleep_for(std::chrono::milliseconds(100));
120 }
121 found = true;
122
123 //gui
125 buildGui(), [this](RemoteGui::TabProxy& prx) { processGui(prx); });
126 return;
127 }
128 }
129 } while (getProperty<bool>("ScanUntilHandFound").getValue() && !found &&
130 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() -
131 start)
132 .count() < getProperty<int>("ScanTimeout").getValue());
133
134 if (mode == KITHandCommunicationDriver::ScanMode::Bluetooth)
135 {
136 ARMARX_WARNING << "Could not find hand with the given MAC-Address: " << macAddress
137 << " Shutting down this KITHandUnit.";
138 }
139 else
140 {
142 << "Could not find hand ove serial ports. Shutting down this KITHHandUnit";
143 }
144 getArmarXManager()->asyncShutdown();
145 }
146
147 void
149 {
150 ARMARX_IMPORTANT << "Calling driver disconnect";
151 _driver->disconnect();
152 _driver.reset();
153 }
154
155 void
156 KITHandUnit::setShape(const std::string& shapeName, const Ice::Current&)
157 {
158 if (std::regex_match(shapeName, std::regex{"[gG](0|[1-9][0-9]*)"}) &&
159 _driver->getCurrentConnectedDevice()->abilities.receivesAdditionalGraspCommands)
160 {
161 _driver->sendGrasp(std::stoul(shapeName.substr(1)));
162 }
163 else if (shapeName == "Open")
164 {
165 _driver->sendGrasp(0);
166 }
167 else if (shapeName == "Close")
168 {
169 _driver->sendGrasp(1);
170 }
171 else if (!_shapes.count(shapeName))
172 {
173 ARMARX_WARNING << "Unknown shape name '" << shapeName << "'\nKnown shapes: " << _shapes;
174 }
175 else
176 {
177 setJointAngles(_shapes.at(shapeName));
178 }
179 }
180
181 void
182 KITHandUnit::setJointAngles(const NameValueMap& targetJointAngles, const Ice::Current&)
183 {
184 ARMARX_CHECK_NOT_NULL(_driver);
185
186 for (const std::pair<std::string, float>& pair : targetJointAngles)
187 {
188 if (pair.first == "Fingers")
189 {
190 const std::uint64_t pos =
191 std::clamp(static_cast<std::uint64_t>(pair.second *
192 KITHand::ControlOptions::maxPosFingers),
193 static_cast<std::uint64_t>(0),
194 KITHand::ControlOptions::maxPosFingers);
195 ARMARX_DEBUG << deactivateSpam(1, std::to_string(pos)) << "set fingers " << pos;
196 _driver->sendFingersPosition(pos);
197 }
198 else if (pair.first == "Thumb")
199 {
200 const std::uint64_t pos = std::clamp(
201 static_cast<std::uint64_t>(pair.second * KITHand::ControlOptions::maxPosThumb),
202 static_cast<std::uint64_t>(0),
203 KITHand::ControlOptions::maxPosThumb);
204 ARMARX_DEBUG << deactivateSpam(1, std::to_string(pos)) << "set thumb " << pos;
205 _driver->sendThumbPosition(pos);
206 }
207 else
208 {
209 ARMARX_WARNING << "Invalid HandJointName '" << pair.first << "', ignoring.";
210 }
211 _driver->waitForCommunicationMedium();
212 }
213 }
214
215 NameValueMap
217 {
218 NameValueMap jointValues;
219 jointValues["Fingers"] =
220 _driver->getFingersPos() * 1.f / KITHand::ControlOptions::maxPosFingers;
221 jointValues["Thumb"] = _driver->getThumbPos() * 1.f / KITHand::ControlOptions::maxPosThumb;
222 return jointValues;
223 }
224
225 void
226 KITHandUnit::addShape(const std::string& name, const std::map<std::string, float>& shape)
227 {
228 _shapes[name] = shape;
229 addShapeName(name);
230 }
231
232 void
233 KITHandUnit::addShapeName(const std::string& name)
234 {
235 Variant currentPreshape;
236 currentPreshape.setString(name);
237 shapeNames->addVariant(currentPreshape);
238 }
239
246
247 void
249 {
250 if (state == State::DeviceLost)
251 {
252 getArmarXManager()->asyncShutdown();
253 }
254 }
255
256 RemoteGui::WidgetPtr
258 {
260 .cols(3)
261 .addTextLabel("Fingers")
262 .addChild(RemoteGui::makeFloatSpinBox("Fingers").min(0).max(1).value(0))
263 .addChild(new RemoteGui::HSpacer)
264
265 .addTextLabel("Thumb")
266 .addChild(RemoteGui::makeFloatSpinBox("Thumb").min(0).max(1).value(0))
267 .addChild(new RemoteGui::HSpacer)
268
269 .addChild(RemoteGui::makeCheckBox("AutoSendValues").value(false).label("Auto send"))
270 .addChild(RemoteGui::makeButton("SendValues").label("Send"))
271 .addChild(new RemoteGui::HSpacer)
272
273 .addChild(RemoteGui::makeLineEdit("Raw").value("M2,1000,1000,100000"))
274 .addChild(RemoteGui::makeButton("SendRaw").label("Send Raw"))
275 .addChild(new RemoteGui::HSpacer);
276 }
277
278 void
280 {
281 prx.receiveUpdates();
282 if (prx.getValue<bool>("AutoSendValues").get() || prx.getButtonClicked("SendValues"))
283 {
284 const auto fingers = prx.getValue<float>("Fingers").get();
285 const auto thumb = prx.getValue<float>("Thumb").get();
286 ARMARX_INFO << "setting Fingers " << fingers << " and Thumb " << thumb;
287 setJointAngles({{"Fingers", fingers}, {"Thumb", thumb}});
288 }
289 if (prx.getButtonClicked("SendRaw") && _driver)
290 {
291 _driver->sendRaw(prx.getValue<std::string>("Raw").get());
292 }
293 }
294
296} // namespace armarx
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
HandUnitPropertyDefinitions(std::string prefix)
Definition HandUnit.h:45
SingleTypeVariantListPtr shapeNames
List containing the names of all valid shapes.
Definition HandUnit.h:169
KITHandUnitPropertyDefinitions(std::string prefix)
Brief description of class KITHandUnit.
Definition KITHandUnit.h:58
void addShapeName(const std::string &name)
void onInitHandUnit() override
void setShape(const std::string &shapeName, const Ice::Current &=Ice::emptyCurrent) override
void onExitHandUnit() override
void connectionStateChangedCallback(const KITHand::State state)
RemoteGui::WidgetPtr buildGui()
virtual armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void addShape(const std::string &name, const std::map< std::string, float > &shape)
void onStartHandUnit() override
void setJointAngles(const NameValueMap &targetJointAngles, const Ice::Current &=Ice::emptyCurrent) override
void processGui(RemoteGui::TabProxy &prx)
NameValueMap getCurrentJointValues(const Ice::Current &=Ice::emptyCurrent) override
virtual std::string getDefaultName() const override
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition Logging.cpp:99
ArmarXManagerPtr getArmarXManager() const
Returns the ArmarX manager used to add and remove components.
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
PropertyDefinition< PropertyType > & defineOptionalProperty(const std::string &name, PropertyType defaultValue, const std::string &description="", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
PropertyDefinition< PropertyType > & defineRequiredProperty(const std::string &name, const std::string &description="", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
bool getButtonClicked(std::string const &name)
ValueProxy< T > getValue(std::string const &name)
Class that offers the main functionality needed to create a statechart.
Definition State.h:54
The Variant class is described here: Variants.
Definition Variant.h:224
void setString(const std::string &s, const Ice::Current &c=Ice::emptyCurrent) override
Sets the Variant's value to s.
Definition Variant.cpp:428
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#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_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
detail::CheckBoxBuilder makeCheckBox(std::string const &name)
Definition BoolWidgets.h:27
detail::FloatSpinBoxBuilder makeFloatSpinBox(std::string const &name)
detail::SimpleGridLayoutBuilder makeSimpleGridLayout(std::string const &name="")
detail::ButtonBuilder makeButton(std::string const &name)
detail::LineEditBuilder makeLineEdit(std::string const &name)
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
std::vector< T > max(const std::vector< T > &v1, const std::vector< T > &v2)
std::vector< T > min(const std::vector< T > &v1, const std::vector< T > &v2)
SimpleGridLayoutBuilder & addTextLabel(std::string const &text, int colspan)
SimpleGridLayoutBuilder & addChild(WidgetPtr const &child, int colspan)