PlatformFollowerController.cpp
Go to the documentation of this file.
2
3#include <VirtualRobot/Nodes/RobotNode.h>
4#include <VirtualRobot/RobotNodeSet.h>
5#include <VirtualRobot/math/Helpers.h>
6
12
15
18#include <armarx/control/njoint_controller/platform/platform_follower_controller/aron/PlatformFollowerControllerConfig.aron.generated.h>
20
22{
23 const std::string NAME = "PlatformFollowerController";
24
26
28 const armarx::NJointControllerConfigPtr& config,
30 {
31 // config
32 ConfigPtrT cfg = ConfigPtrT::dynamicCast(config);
34 // ARMARX_CHECK_EXPRESSION(!cfg->nodeSetName.empty());
35
36 ARMARX_CHECK_EXPRESSION(robotUnit);
37
38 const auto robot = useSynchronizedRtRobot();
39
40 platformTarget = useControlTarget(robotUnit->getRobotPlatformName(),
41 armarx::ControlModes::HolonomicPlatformVelocity)
43 ARMARX_CHECK_EXPRESSION(platformTarget)
44 << "The actuator " << robotUnit->getRobotPlatformName() << " has no control mode "
45 << armarx::ControlModes::HolonomicPlatformVelocity;
46
47 const Config configData = ::armarx::fromAron<arondto::Config, Config>(cfg->config);
48
50 configBuffer.reinitAllBuffers(configData);
51
52 // TODO init tcps
53 const VirtualRobot::RobotNodeSetPtr rnsRight =
54 robot->getRobotNodeSet(configData.params.nodeSetNameRight);
55 ARMARX_CHECK(rnsRight);
56 const VirtualRobot::RobotNodeSetPtr rnsLeft =
57 robot->getRobotNodeSet(configData.params.nodeSetNameLeft);
58 ARMARX_CHECK(rnsLeft);
59 tcpRight = rnsRight->getTCP();
60 tcpLeft = rnsLeft->getTCP();
61 }
62
63 std::string
64 Controller::getClassName(const Ice::Current& iceCurrent) const
65 {
66 return NAME;
67 }
68
69 void
70 Controller::rtRun(const IceUtil::Time& sensorValuesTimestamp,
71 const IceUtil::Time& timeSinceLastIteration)
72 {
73 // update state
74 stateBuffer.getWriteBuffer().handPositionRight = tcpRight->getPositionInRootFrame();
75 stateBuffer.getWriteBuffer().handPositionLeft = tcpLeft->getPositionInRootFrame();
76 stateBuffer.getWriteBuffer().time = armarx::Clock::Now();
77 stateBuffer.getWriteBuffer().currentVel.setZero();
78 stateBuffer.commitWrite();
79
80 // write control targets
82
83 // FIXME remove
84 //platformTarget->velocityX = 0;
85 //platformTarget->velocityY = 0;
86 //platformTarget->velocityRotation = 0;
87
88 // FIXME uncomment
89 platformTarget->velocityX = rtGetControlStruct().platformVelocityTargets.x;
90 platformTarget->velocityY = rtGetControlStruct().platformVelocityTargets.y;
91 platformTarget->velocityRotation = rtGetControlStruct().platformVelocityTargets.yaw;
92 }
93
94 void
95 Controller::updateConfig(const ::armarx::aron::data::dto::DictPtr& dto,
96 const Ice::Current& iceCurrent)
97 {
98 ARMARX_IMPORTANT << "Controller::updateConfig";
99
100 // TODO maybe update pid controller
101
103 configBuffer.reinitAllBuffers(updateConfig);
104 }
105
106 void
108 {
109 if (not rtReady.load())
110 {
111 // store result
112 getWriterControlStruct().platformVelocityTargets.x = 0;
113 getWriterControlStruct().platformVelocityTargets.y = 0;
114 getWriterControlStruct().platformVelocityTargets.yaw = 0;
115
117 }
118
119 configBuffer.updateReadBuffer();
120 stateBuffer.updateReadBuffer();
121
122 const auto state = stateBuffer.getReadBuffer();
123 const auto params = configBuffer.getReadBuffer().params;
124
125 const double deltaT = (state.time - additionalTaskData.lastTime).toSecondsDouble();
126 additionalTaskData.lastTime = state.time;
127
128 if (deltaT == 0)
129 return;
130
131 const Eigen::Vector3f currentVel = state.currentVel;
132 const Eigen::Vector3f currentPositionRight = state.handPositionRight;
133 const Eigen::Vector3f currentPositionLeft = state.handPositionLeft;
134 const Eigen::Vector3f positionDeltaRight =
135 currentPositionRight - initialState.handPositionRight;
136 const Eigen::Vector3f positionDeltaLeft =
137 currentPositionLeft - initialState.handPositionLeft;
138
139 Eigen::Vector2f positionDelta = ((positionDeltaLeft + positionDeltaRight) / 2).head<2>();
140 Eigen::Vector2f velocity = Eigen::Vector2f::Zero();
141 if (positionDelta.norm() >= params.minPosTolerance)
142 {
143 positionDelta =
144 positionDelta - params.minPosTolerance * positionDelta / positionDelta.norm();
145 velocity = positionDelta * params.kPos - currentVel.head<2>() * params.dPos;
146 }
147 const float Tstar = 1 / ((params.filterTimeConstant / deltaT) + 1);
148 additionalTaskData.filteredLinearVel =
149 Tstar * (velocity - additionalTaskData.filteredLinearVel) +
150 additionalTaskData.filteredLinearVel;
151 if (!std::isfinite(additionalTaskData.filteredLinearVel(0)))
152 {
153 additionalTaskData.filteredLinearVel(0) = 0;
154 }
155 if (!std::isfinite(additionalTaskData.filteredLinearVel(1)))
156 {
157 additionalTaskData.filteredLinearVel(1) = 0;
158 }
159 velocity = additionalTaskData.filteredLinearVel.norm() > params.maxPosVel
160 ? additionalTaskData.filteredLinearVel.normalized() * params.maxPosVel
161 : additionalTaskData.filteredLinearVel;
162
163
164 const Eigen::Vector3f currentDirection = state.direction();
165 const float cosAlpha = currentDirection.dot(initialState.direction());
166 const Eigen::Vector3f directionDiff = currentDirection - initialState.direction();
167 float alpha = 0;
168 if (directionDiff(1) < 0)
169 {
170 alpha = -acos(cosAlpha);
171 }
172 else
173 {
174 alpha = acos(cosAlpha);
175 }
176 float angularVelocity;
177 if (fabs(alpha) < params.minAngleTolerance)
178 {
179 angularVelocity = 0;
180 }
181 else
182 {
183 if (alpha > 0)
184 {
185 alpha -= params.minAngleTolerance;
186 }
187 else
188 {
189 alpha += params.minAngleTolerance;
190 }
191 angularVelocity = params.kAngle * alpha - params.dAngle * currentVel.z();
192 }
193 additionalTaskData.filteredAngularVel =
194 Tstar * (angularVelocity - additionalTaskData.filteredAngularVel) +
195 additionalTaskData.filteredAngularVel;
196 if (!std::isfinite(additionalTaskData.filteredAngularVel))
197 {
198 additionalTaskData.filteredAngularVel = 0;
199 }
200 angularVelocity = std::min(additionalTaskData.filteredAngularVel, params.maxAngleVel);
201
202
203 {
204 auto& onPublishData = onPublishBuffer.getWriteBuffer();
205
206 onPublishData.target.platformVelocityTargets.x = velocity.x();
207 onPublishData.target.platformVelocityTargets.y = velocity.y();
208 onPublishData.target.platformVelocityTargets.yaw = angularVelocity;
209
210 onPublishData.position_error_left = positionDeltaLeft;
211 onPublishData.position_error_right = positionDeltaRight;
212 onPublishBuffer.commitWrite();
213 }
214
215
216 // store result
217 getWriterControlStruct().platformVelocityTargets.x = velocity.x();
218 getWriterControlStruct().platformVelocityTargets.y = velocity.y();
219 getWriterControlStruct().platformVelocityTargets.yaw = angularVelocity;
220
222 }
223
224 void
226 const armarx::DebugDrawerInterfacePrx& /*debugDrawer*/,
227 const armarx::DebugObserverInterfacePrx& debugObservers)
228 {
230
231 onPublishBuffer.updateReadBuffer();
232 const auto& data = onPublishBuffer.getReadBuffer();
233
234 datafields["vx"] = new armarx::Variant(data.target.platformVelocityTargets.x);
235 datafields["vy"] = new armarx::Variant(data.target.platformVelocityTargets.y);
236 datafields["vyaw"] = new armarx::Variant(data.target.platformVelocityTargets.yaw);
237
238 datafields["position_error_left_x"] = new armarx::Variant(data.position_error_left.x());
239 datafields["position_error_left_y"] = new armarx::Variant(data.position_error_left.y());
240 datafields["position_error_left_z"] = new armarx::Variant(data.position_error_left.z());
241 datafields["position_error_right_x"] = new armarx::Variant(data.position_error_right.x());
242 datafields["position_error_right_y"] = new armarx::Variant(data.position_error_right.y());
243 datafields["position_error_right_z"] = new armarx::Variant(data.position_error_right.z());
244
245 debugObservers->setDebugChannel(NAME, datafields);
246 }
247
248 void
250 {
251 runTask(NAME + "AdditionalTask",
252 [&]
253 {
255 4); // please don't set this to 0 as it is the rtRun/control thread
258
260 getObjectScheduler()->waitForObjectStateMinimum(
261 armarx::eManagedIceObjectStarted);
262 ARMARX_IMPORTANT << "Create a new thread alone PlatformTrajectory controller";
263 while (getState() == armarx::eManagedIceObjectStarted)
264 {
265 if (isControllerActive() and rtReady.load())
266 {
267 ARMARX_VERBOSE << "additional task";
269 }
270 c.waitForCycleDuration();
271 }
272 });
273
274 ARMARX_INFO << "PlatformTrajectoryVelocityController::onInitNJointController";
275 }
276
277 void
279 {
280 initialState.handPositionRight = tcpRight->getPositionInRootFrame();
281 initialState.handPositionLeft = tcpLeft->getPositionInRootFrame();
282 initialState.time = armarx::core::time::DateTime::Now();
283
284 ARMARX_INFO << "Init done.";
285
286 rtReady.store(true);
287 }
288
289 Controller::~Controller() = default;
290
291} // namespace armarx::control::njoint_controller::platform::platform_follower_controller
constexpr T c
static DateTime Now()
Current time on the virtual clock.
Definition Clock.cpp:93
Brief description of class ControlTargetHolonomicPlatformVelocity.
This util class helps with keeping a cycle time during a control cycle.
Definition CycleUtil.h:41
ArmarXObjectSchedulerPtr getObjectScheduler() const
int getState() const
Retrieve current state of the ManagedIceObject.
bool isControllerActive(const Ice::Current &=Ice::emptyCurrent) const final override
void runTask(const std::string &taskName, Task &&task)
Executes a given task in a separate thread from the Application ThreadPool.
const VirtualRobot::RobotPtr & useSynchronizedRtRobot(bool updateCollisionModel=false)
Requests a VirtualRobot for use in rtRun *.
ControlTargetBase * useControlTarget(const std::string &deviceName, const std::string &controlMode)
Declares to calculate the ControlTarget for the given ControlDevice in the given ControlMode when rtR...
The Variant class is described here: Variants.
Definition Variant.h:224
static bool pinThreadToCPU(unsigned int cpu)
Pins the calling thread to the CPU with the given id.
Definition RTUtility.cpp:52
static bool elevateThreadPriority(int priority)
Elevate the thread priority of the calling thread to the given priority.
Definition RTUtility.cpp:17
static constexpr int RT_THREAD_PRIORITY
The thread priority for rt-threads.
Definition RTUtility.h:24
Controller(const armarx::RobotUnitPtr &robotUnit, const armarx::NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
void rtRun(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration) override
TODO make protected and use attorneys.
void updateConfig(const ::armarx::aron::data::dto::DictPtr &dto, const Ice::Current &iceCurrent=Ice::emptyCurrent) override
void onPublish(const armarx::SensorAndControl &sac, const armarx::DebugDrawerInterfacePrx &debugDrawer, const armarx::DebugObserverInterfacePrx &debugObservers) override
std::string getClassName(const Ice::Current &iceCurrent=Ice::emptyCurrent) const override
void rtPreActivateController() override
This function is called before the controller is activated.
static DateTime Now()
Definition DateTime.cpp:51
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#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
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
const armarx::NJointControllerRegistration< Controller > Registration(NAME)
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface > DebugObserverInterfacePrx
std::map< std::string, VariantBasePtr > StringVariantBaseMap
void fromAron(const arondto::PackagePath &dto, PackageFileLocation &bo)
IceUtil::Handle< class RobotUnit > RobotUnitPtr
Definition FTSensor.h:34
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugDrawerInterface > DebugDrawerInterfacePrx
detail::ControlThreadOutputBufferEntry SensorAndControl
bool isfinite(const std::vector< T, Ts... > &v)
Definition algorithm.h:366