PlatformGlobalTrajectoryController.cpp
Go to the documentation of this file.
2
3#include <string>
4
5#include <Ice/Current.h>
6#include <IceUtil/Time.h>
7
8#include <SimoxUtility/math/convert/mat4f_to_rpy.h>
9#include <VirtualRobot/VirtualRobot.h>
10
15#include <ArmarXCore/interface/core/ManagedIceObjectDefinitions.h>
16#include <ArmarXCore/interface/observers/ObserverInterface.h>
17#include <ArmarXCore/interface/observers/VariantBase.h>
20
26#include <RobotAPI/interface/units/RobotUnit/NJointController.h>
27#include <RobotAPI/interface/visualization/DebugDrawerInterface.h>
28
29#include <armarx/control/interface/ConfigurableNJointControllerInterface.h> // IWYU pragma: keep
31#include <armarx/navigation/platform_controller/aron/PlatformGlobalTrajectoryControllerConfig.aron.generated.h>
34
36{
39
41 const NJointControllerConfigPtr& config,
43 {
44 ARMARX_IMPORTANT << "Creating "
47 // config
48 ConfigPtrT cfg = ConfigPtrT::dynamicCast(config);
50 // ARMARX_CHECK_EXPRESSION(!cfg->nodeSetName.empty());
51
52 ARMARX_CHECK_EXPRESSION(robotUnit);
53
54 const auto robot = useSynchronizedRtRobot();
55
56 // Control target
57 {
58 const std::string controlTargetName = robotUnit->getRobotPlatformName();
59
60 ARMARX_INFO << "Using control target " << controlTargetName;
61 auto* ct = useControlTarget(controlTargetName, ControlModes::HolonomicPlatformVelocity);
62 ARMARX_CHECK_NOT_NULL(ct) << "Cannot use control target " << QUOTED(controlTargetName);
63
64 platformTarget = ct->asA<ControlTargetHolonomicPlatformVelocity>();
65
66 ARMARX_CHECK_EXPRESSION(platformTarget)
67 << "The actuator " << controlTargetName << " has no control mode "
68 << ControlModes::HolonomicPlatformVelocity;
69 }
70
71
72 const auto configData = ::armarx::fromAron<arondto::Config, Config>(cfg->config);
73 const auto trajectoryFollowingControllerParams = configData.params;
74
76 configBuffer_updateConfigToAdditionalTask.reinitAllBuffers(configData);
77 configBuffer_updateConfigToOnPublish.reinitAllBuffers(configData);
78
79 trajectoryFollowingController.emplace(trajectoryFollowingControllerParams);
80
81 ARMARX_INFO << "Init done.";
82 }
83
84 std::string
90
91 void
92 Controller::rtRun(const IceUtil::Time& sensorValuesTimestamp,
93 const IceUtil::Time& timeSinceLastIteration)
94 {
96
97 // update control devices
98 platformTarget->velocityX = rtGetControlStruct().linear.x();
99 platformTarget->velocityY = rtGetControlStruct().linear.y();
100 platformTarget->velocityRotation = rtGetControlStruct().angular;
101
102 // read data (for non-rt)
103 robotStateBuffer_rtToAdditionalTask.getWriteBuffer().global_T_robot.matrix() =
104 rtGetRobot()->getGlobalPose();
105 robotStateBuffer_rtToAdditionalTask.commitWrite();
106 }
107
108 void
109 Controller::updateConfig(const ::armarx::aron::data::dto::DictPtr& dto,
110 const Ice::Current& iceCurrent)
111 {
112 // TODO maybe update pid controller
113
115
116 configBuffer_updateConfigToAdditionalTask.getWriteBuffer() = updateConfig;
117 configBuffer_updateConfigToAdditionalTask.commitWrite();
118
119 configBuffer_updateConfigToOnPublish.getWriteBuffer() = updateConfig;
120 configBuffer_updateConfigToOnPublish.commitWrite();
121
122 ARMARX_VERBOSE << "Trajectory with " << updateConfig.targets.trajectory.points().size();
123 }
124
125 void
127 {
129 ARMARX_CHECK(trajectoryFollowingController.has_value());
130
131 const auto& configBuffer =
132 configBuffer_updateConfigToAdditionalTask.getUpToDateReadBuffer();
133
134
135 // if trajectory is empty, set velocity to 0
136 if (configBuffer.targets.trajectory.points().empty())
137 {
138 ARMARX_INFO << deactivateSpam(1) << "Trajectory is empty!";
139
140 filteredTwist.reset();
141
142 getWriterControlStruct().reset();
144 return;
145 }
146
147 // update controller
149
150 // make sure the parameters are up to date
151 // i.e. velocityFactor and limits, as they can be changed on the fly
152 trajectoryFollowingController->updateParams(configBuffer.params);
153
154 // run the controller, resulting in the required twist and other values
156 trajectoryFollowingController->control(
157 configBuffer.targets.trajectory,
158 robotStateBuffer_rtToAdditionalTask.getUpToDateReadBuffer().global_T_robot);
159
160 // low-pass filter the twist
161 {
162 const float alpha = configBuffer.params.alpha;
163 filteredTwist.linear =
164 alpha * filteredTwist.linear + (1. - alpha) * result.twist.linear.head<2>();
165 filteredTwist.angular =
166 alpha * filteredTwist.angular + (1. - alpha) * result.twist.angular.z();
167 }
168
169 // store result
170 getWriterControlStruct() = filteredTwist;
173
174 // store results (onPublish)
175 targetBuffer_additionalTaskToOnPublish.getWriteBuffer().target = filteredTwist;
176 targetBuffer_additionalTaskToOnPublish.getWriteBuffer().dropPointVelocity =
177 result.dropPoint.velocity;
178 targetBuffer_additionalTaskToOnPublish.getWriteBuffer().currentOrientation =
179 result.currentOrientation;
180 targetBuffer_additionalTaskToOnPublish.getWriteBuffer().desiredOrientation =
181 result.desiredOrientation;
182 targetBuffer_additionalTaskToOnPublish.getWriteBuffer().orientationError =
183 result.orientationError;
184 targetBuffer_additionalTaskToOnPublish.getWriteBuffer().positionError =
185 result.positionError;
186 targetBuffer_additionalTaskToOnPublish.getWriteBuffer().isFinalSegment =
187 result.isFinalSegment;
188 targetBuffer_additionalTaskToOnPublish.getWriteBuffer().global_T_robot =
189 robotStateBuffer_rtToAdditionalTask.getReadBuffer().global_T_robot;
190 targetBuffer_additionalTaskToOnPublish.commitWrite();
191 }
192
193 void
195 const DebugDrawerInterfacePrx& /*debugDrawer*/,
196 const DebugObserverInterfacePrx& debugObservers)
197 {
198 StringVariantBaseMap datafields;
199
200 const auto& debugStuff = targetBuffer_additionalTaskToOnPublish.getUpToDateReadBuffer();
201 const auto& config = configBuffer_updateConfigToOnPublish.getUpToDateReadBuffer();
202
203
204 datafields["vx"] = new Variant(debugStuff.target.linear.x());
205 datafields["vy"] = new Variant(debugStuff.target.linear.y());
206 datafields["v_linear"] = new Variant(debugStuff.target.linear.norm());
207 datafields["vyaw"] = new Variant(debugStuff.target.angular);
208 datafields["trajectory_points"] = new Variant(config.targets.trajectory.points().size());
209
210 datafields["drop_point_velocity"] = new Variant(debugStuff.dropPointVelocity);
211
212 datafields["orientationError"] = new Variant(debugStuff.orientationError);
213 datafields["desiredOrientation"] = new Variant(debugStuff.desiredOrientation);
214 datafields["currentOrientation"] = new Variant(debugStuff.currentOrientation);
215 datafields["isFinalSegment"] = new Variant(debugStuff.isFinalSegment);
216
217 datafields["positionError"] = new Variant(debugStuff.positionError);
218
219 datafields["global_T_robot.x"] = new Variant(debugStuff.global_T_robot.translation().x());
220 datafields["global_T_robot.y"] = new Variant(debugStuff.global_T_robot.translation().y());
221 datafields["global_T_robot.o"] =
222 new Variant(simox::math::mat4f_to_rpy(debugStuff.global_T_robot.matrix()).z());
223
224 datafields["limitLinear"] = new Variant(config.params.limits.linear);
225 datafields["limitAngular"] = new Variant(config.params.limits.angular);
226
227 debugObservers->setDebugChannel(
229 datafields);
230 }
231
232 void
234 {
236 ARMARX_INFO << "PlatformGlobalTrajectoryController::onInitNJointController";
237
238 runTask(
239 "PlatformGlobalTrajectoryControllerAdditionalTask",
240 [&]
241 {
242 CycleUtil c(10);
243 getObjectScheduler()->waitForObjectStateMinimum(eManagedIceObjectStarted);
245 << "Create a new thread alone PlatformGlobalTrajectoryController controller";
246 while (getState() == eManagedIceObjectStarted)
247 {
248 if (isControllerActive() and rtReady.load())
249 {
250 ARMARX_VERBOSE << "additional task";
252 }
253 c.waitForCycleDuration();
254 }
255 });
256
257 ARMARX_INFO << "PlatformGlobalTrajectoryController::onInitNJointController done.";
258 }
259
260 void
262 {
263 // additionalTask() is not executed. Thus, we can access lastTwist without mutex.
264 filteredTwist.reset();
265
266 robotStateBuffer_rtToAdditionalTask.getWriteBuffer().global_T_robot.matrix() =
267 rtGetRobot()->getGlobalPose();
268 robotStateBuffer_rtToAdditionalTask.commitWrite();
269
270 rtReady.store(true);
271 }
272
273 void
275 {
276 rtReady.store(false);
277 }
278
279 Controller::~Controller() = default;
280
282 Controller::getConfig(const ::Ice::Current&)
283 {
284 ARMARX_ERROR << "NYI";
285 return nullptr;
286 }
287} // namespace armarx::navigation::platform_controller::platform_global_trajectory
#define QUOTED(x)
constexpr T c
Brief description of class ControlTargetHolonomicPlatformVelocity.
This util class helps with keeping a cycle time during a control cycle.
Definition CycleUtil.h:41
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
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 *.
const VirtualRobot::RobotPtr & rtGetRobot()
TODO make protected and use attorneys.
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
::armarx::aron::data::dto::DictPtr getConfig(const ::Ice::Current &=::Ice::emptyCurrent) override
Controller(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
void rtPostDeactivateController() override
This function is called after the controller is deactivated.
void rtRun(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration) override
TODO make protected and use attorneys.
void onPublish(const SensorAndControl &sac, const DebugDrawerInterfacePrx &debugDrawer, const DebugObserverInterfacePrx &debugObservers) override
void updateConfig(const ::armarx::aron::data::dto::DictPtr &dto, const Ice::Current &iceCurrent=Ice::emptyCurrent) override
std::string getClassName(const Ice::Current &iceCurrent=Ice::emptyCurrent) const override
void rtPreActivateController() override
This function is called before the controller is activated.
#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_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_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
::IceInternal::Handle< Dict > DictPtr
const simox::meta::EnumNames< ControllerType > ControllerTypeNames
const NJointControllerRegistration< Controller > Registration(common::ControllerTypeNames.to_name(common::ControllerType::PlatformGlobalTrajectory))
::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
#define ARMARX_TRACE
Definition trace.h:77