GamepadUnit.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::GamepadUnit
17 * @author Simon Ottenhaus ( simon dot ottenhaus at kit dot edu )
18 * @date 2017
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "GamepadUnit.h"
24
29
30#include <linux/joystick.h>
31
32using namespace armarx;
33
35
36void
38{
40 offeringTopic(getProperty<std::string>("GamepadTopicName").getValue());
41 deviceName = getProperty<std::string>("GamepadDeviceName").getValue();
42 deviceEventName = getProperty<std::string>("GamepadForceFeedbackName").getValue();
43 readTask = new RunningTask<GamepadUnit>(this, &GamepadUnit::run, "GamepadUnit");
44}
45
46void
48{
50 topicPrx =
51 getTopic<GamepadUnitListenerPrx>(getProperty<std::string>("GamepadTopicName").getValue());
53 sendTask = new SimplePeriodicTask<>(
54 [&]
55 {
57 std::unique_lock lock(mutex);
58 if (!js.opened())
59 {
60 return;
61 }
63 if (!dataTimestamp)
64 {
65 ARMARX_INFO << deactivateSpam(1) << "dataTimestamp is null, waiting for value";
66 return;
67 }
68 ARMARX_CHECK_NOT_NULL(dataTimestamp);
69 const IceUtil::Time age = IceUtil::Time::now() - dataTimestamp->toTime();
70 if (age.toMilliSeconds() < getProperty<int>("PublishTimeout").getValue())
71 {
73 ARMARX_CHECK_NOT_NULL(topicPrx) << "Topic proxy must not be null.";
74 topicPrx->reportGamepadState(deviceName, js.name, data, dataTimestamp);
75 }
76 else
77 {
79 ARMARX_INFO << deactivateSpam(100000, std::to_string(dataTimestamp->getTimestamp()))
80 << "No new signal from gamepad for " << age.toMilliSecondsDouble()
81 << " milliseconds. Not sending data. Timeout: "
82 << getProperty<int>("PublishTimeout").getValue() << " ms";
83 }
84 },
85 30);
86
87 sendTask->start();
90}
91
92void
93GamepadUnit::vibrate(const ::Ice::Current&)
94{
95 ARMARX_INFO << "vibration!";
96 js.executeEffect();
97}
98
99bool
101{
102 if (js.open(deviceName, deviceEventName))
103 {
104
106 ARMARX_INFO << "opened a gamepad named " << js.name << " with " << js.numberOfAxis
107 << " axis and " << js.numberOfButtons << " buttons.";
108 if (js.numberOfAxis == 8 && js.numberOfButtons == 11)
109 {
111 readTask->start();
112 }
113 else
114 {
116 ARMARX_WARNING << "this is not our trusty logitech gamepad.";
117 js.close();
118 return false;
119 }
120 }
121 else
122 {
124 ARMARX_WARNING << "Could not open gamepad device " << deviceName;
125 js.close();
126 return false;
127 }
128 return true;
129}
130
131void
132GamepadUnit::run()
133{
135 while (readTask->isRunning())
136 {
138 if (!js.pollEvent())
139 {
141 ARMARX_WARNING << "failed to read gamepad data - trying to reconnect";
142 js.close();
143 sleep(1);
144 while (readTask->isRunning() && !openGamepadConnection())
145 {
146 sleep(1);
147 }
148 }
150 std::unique_lock lock(mutex);
151 IceUtil::Time now = IceUtil::Time::now();
152 dataTimestamp = new TimestampVariant(now);
153
154 //mapping found with command line tool jstest <device file>
155
156 float axisFactor = 1.0f / 32768.f;
157
158 data.leftStickY = js.axis[0] * axisFactor;
159 data.leftStickX = js.axis[1] * axisFactor;
160 data.rightStickX = js.axis[3] * axisFactor;
161 data.rightStickY = js.axis[4] * axisFactor;
162 data.dPadX = js.axis[7] * axisFactor;
163 data.dPadY = js.axis[6] * axisFactor;
164 data.leftTrigger = js.axis[2] * axisFactor;
165 data.rightTrigger = js.axis[5] * axisFactor;
167
168 data.leftButton = js.buttonsPressed[4];
169 data.rightButton = js.buttonsPressed[5];
170 data.backButton = js.buttonsPressed[6];
171 data.startButton = js.buttonsPressed[7];
172 data.xButton = js.buttonsPressed[2];
173 data.yButton = js.buttonsPressed[3];
174 data.aButton = js.buttonsPressed[0];
175 data.bButton = js.buttonsPressed[1];
176 data.theMiddleButton = js.buttonsPressed[8];
177 data.leftStickButton = js.buttonsPressed[9];
178 data.rightStickButton = js.buttonsPressed[10];
180
181 ARMARX_VERBOSE << "left x (integer): " << js.axis[0]
182 << " left x (float): " << data.leftStickX
183 << " right trigger: " << data.rightTrigger;
184
185 //usleep(1000); // 10ms
186 }
187}
188
189void
191{
193 if (sendTask)
194 {
196 sendTask->stop();
197 }
198 if (readTask)
199 {
201 readTask->stop();
202 }
203}
204
205void
209
#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)
Brief description of class GamepadUnit.
Definition GamepadUnit.h:81
void onInitComponent() override
void onDisconnectComponent() override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void onConnectComponent() override
void vibrate(const ::Ice::Current &=::Ice::emptyCurrent) override
void onExitComponent() 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
void offeringTopic(const std::string &name)
Registers a topic for retrival after initialization.
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
#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_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
SimplePeriodicTask(Ts...) -> SimplePeriodicTask< std::function< void(void)> >
#define ARMARX_TRACE
Definition trace.h:77