YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
controlThread.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2024 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
6#include <yarp/os/Log.h>
7#include <yarp/os/LogStream.h>
8
9#include "robotDriver.h"
10#include "robotAction.h"
11#include "controlThread.h"
12
14{
15 std::lock_guard<std::mutex> lg(m_mtx);
16 return m_status;
17}
18
19bool ControlThread::action_getname(std::string& name)
20{
21 std::lock_guard<std::mutex> lg(m_mtx);
22 name = m_current_action->action_name;
23 return true;
24}
25
27{
28 std::lock_guard<std::mutex> lg(m_mtx);
29 m_status = ACTION_STOP;
30 //the clock is paused in ACTION_STOP
31 return true;
32}
33
35{
36 std::lock_guard<std::mutex> lg(m_mtx);
37 m_current_action->print();
38 return true;
39}
40
42{
43 std::lock_guard<std::mutex> lg(m_mtx);
44 m_status = ACTION_RESET;
45 m_current_action->current_frame = 0;
46 //the clock is resetted in ACTION_RESET
47 return true;
48}
49
51{
52 std::lock_guard<std::mutex> lg(m_mtx);
53 if (m_current_action->current_frame == 0)
54 {
55 m_status = ACTION_START;
56 //if the action is just started the clock will be started in ACTION_START
57 }
58 else
59 {
60 m_status = ACTION_RUNNING;
61 //if we are resuming a paused action, start the timer previously stopped by aCTION_STOP
63 }
64 m_current_action->forever = true;
65 return true;
66}
67
69{
70 std::lock_guard<std::mutex> lg(m_mtx);
71 if (m_current_action->current_frame == 0)
72 {
73 m_status = ACTION_START;
74 //if the action is just started the clock will be started in ACTION_START
75 }
76 else
77 {
78 m_status = ACTION_RUNNING;
79 //if we are resuming a paused action, start the timer previously stopped by aCTION_STOP
81 }
82 m_current_action->forever = false;
83 return true;
84}
85
87{
88 std::lock_guard<std::mutex> lg(m_mtx);
89 m_current_action = action;
90 m_current_driver = driver;
91 m_status = ACTION_IDLE;
92 m_current_action->current_frame = 0;
93 return true;
94}
95
97{
98 std::lock_guard<std::mutex> lg(m_mtx);
99 m_current_action->speed_factor = factor;
100 //also reset the action to avoid issue if it is playing..
101 m_status = ACTION_RESET;
102 m_current_action->current_frame = 0;
103 return true;
104}
105
107{
108 std::lock_guard<std::mutex> lg(m_mtx);
109 m_current_action->interpolate_action_frames(value);
110
111 //also reset the action to avoid issue if it is playing..
112 m_status = ACTION_RESET;
113 m_current_action->current_frame = 0;
114 return true;
115}
116
117ControlThread::ControlThread(std::string name, double period): PeriodicThread(period)
118{
119 yInfo() << "Control thread period set to: " << period;
120 m_module_name = name;
121}
122
124{
125 m_port_command_out.interrupt();
126 m_port_command_out.close();
127 m_port_command_joints.interrupt();
128 m_port_command_joints.close();
129}
130
132{
133 if (!m_port_command_out.open(std::string("/")+m_module_name+"/port_command_out:o"))
134 {
135 return false;
136 }
137
138 if (!m_port_command_joints.open(std::string("/")+m_module_name+"/port_joints:o"))
139 {
140 return false;
141 }
142 return true;
143}
144
145bool ControlThread::execute_joint_command(int frame_id)
146{
147 if (!m_current_driver) return false;
148 if (!m_enable_execute_joint_command) return true;
149
150 double *ll = m_current_action->action_frames_vector[frame_id].q_joints.data();
151 size_t nj = m_current_action->get_njoints();
152
153 for (size_t j = 0; j < nj; j++)
154 {
155 m_current_driver->setPosition((int)j, ll[j]);
156 }
157 return true;
158}
159
160void ControlThread::compute_and_send_command(int frame_id)
161{
162 //prepare the output command
163 yarp::os::Bottle& bot = m_port_command_out.prepare();
164 bot.clear();
165 bot.addInt32((int)m_current_action->action_frames_vector[frame_id].counter);
166 bot.addFloat64(m_current_action->action_frames_vector[frame_id].time);
167
168 //send the output command
169 m_port_command_out.write();
170
171 //execute the command
172 if (!execute_joint_command(frame_id))
173 {
174 yError("failed to execute command");
175 }
176
177 //quick reads the current position
178 std::vector<double> encs;
179 if (m_current_driver)
180 {
181 size_t nj = m_current_action->get_njoints();
182 encs.resize(nj);
183 for (size_t j = 0; j < nj; j++)
184 {
185 m_current_driver->getEncoder((int)j, &encs[j]);
186 }
187 }
188 else
189 {
190 //invalid driver
191 yError("Critical error: invalid driver");
192 }
193
194 //send the joints angles on debug port
195 double *ll = m_current_action->action_frames_vector[frame_id].q_joints.data();
196 yarp::os::Bottle& bot2 = this->m_port_command_joints.prepare();
197 bot2.clear();
198 bot2.addInt32((int)m_current_action->action_frames_vector[frame_id].counter);
199 bot2.addFloat64(m_current_action->action_frames_vector[frame_id].time);
200 size_t nj = m_current_action->get_njoints();
201 bot2.addString("commands:");
202 for (size_t ix=0;ix<nj;ix++)
203 {
204 bot2.addFloat64(ll[ix]);
205 }
206 bot2.addString("encoders:");
207 for (size_t ix=0;ix<nj;ix++)
208 {
209 bot2.addFloat64(encs[ix]);
210 }
211 this->m_port_command_joints.write();
212}
213
214size_t getCurrentFrame(double elapsed, std::deque<action_frame>& dq)
215{
216 //example
217 // 0 0.0 > 1.1 ? no, continue
218 // 1 0.5 > 1.1 ? no, continue
219 // 2 1.0 > 1.1 ? no, continue
220 // 3 1.5 > 1.1 ? yes, return 3
221 // 4 2.0
222
223 size_t i = 0;
224 for (i = 0; i < dq.size(); i++)
225 {
226 if (dq[i].time > elapsed)
227 return i;
228 }
229 return i;
230}
231
233{
234 std::lock_guard<std::mutex> lck(m_mtx);
235
236 size_t nj = m_current_action->get_njoints();
237
238 if (this->m_status == ACTION_IDLE)
239 {
240 // do nothing
241 //yDebug() << "ACTION_IDLE";
242 }
243 else if (this->m_status == ACTION_STOP)
244 {
245 yInfo() << "ACTION_STOP";
247 this->m_status = ACTION_IDLE;
248 }
249 else if (this->m_status == ACTION_RESET)
250 {
251 yInfo() << "ACTION_RESET";
252
253 for (size_t j = 0; j < nj; j++)
254 {
255 m_current_driver->setControlMode((int)j, VOCAB_CM_POSITION);
256 }
258 this->m_status = ACTION_IDLE;
259 }
260 else if (this->m_status == ACTION_RUNNING)
261 {
262 size_t last_frame = m_current_action->action_frames_vector.size();
263 if (last_frame == 0)
264 {
265 yError("ACTION_RUNNING: sequence empty!");
266 this->m_status = ACTION_RESET;
267 return;
268 }
269
270 //if it's not the last frame
271 double curr_frame_time = m_clock.getElapsedTime() * m_current_action->speed_factor;
272 size_t newcurrframe = getCurrentFrame(curr_frame_time, m_current_action->action_frames_vector);
273 m_current_action->current_frame = newcurrframe;
274
275 // not the last frame
276 if (m_current_action->current_frame < last_frame - 1)
277 {
278 compute_and_send_command((int)m_current_action->current_frame);
279 yDebug("Executing action: %4zd/%4zd (%.3fs)", m_current_action->current_frame , last_frame, m_clock.getElapsedTime());
280 }
281 else //the action is complete
282 {
283 if (m_current_action->forever)
284 {
285 yInfo("sequence completed in: %.3f s, restarting", m_clock.getElapsedTime());
286 m_current_action->current_frame=0;
289 }
290 else
291 {
292 yInfo("sequence completed in: %.3f s", m_clock.getElapsedTime());
293 for (size_t j = 0; j < nj; j++)
294 {
295 m_current_driver->setControlMode((int)j, VOCAB_CM_POSITION);
296 }
297 this->m_status=ACTION_IDLE;
298 }
299 }
300 }
301 else if (this->m_status == ACTION_START)
302 {
303 if (m_current_action->action_frames_vector.size() > 0)
304 {
305 double *ll = m_current_action->action_frames_vector[0].q_joints.data();
306 size_t nj = m_current_action->get_njoints();
307
308 //first go to first frame in standard position mode
309 yDebug() << "ACTION_START: switch to position mode";
310 for (size_t j = 0; j < nj; j++)
311 {
312 m_current_driver->setControlMode((int)j, VOCAB_CM_POSITION);
313 }
315 for (size_t j = 0; j < nj; j++)
316 {
317 m_current_driver->positionMove((int)j, ll[j]);
318 }
319
320 //check if it reached the position within the desired tolerance
321 yInfo() << "ACTION_START: going to start position";
322 double enc= 0.0;
323 bool check = true;
324 double move_start_time = yarp::os::Time::now();
325 do
326 {
327 for (size_t j = 0; j < nj; j++)
328 {
329 m_current_driver->getEncoder((int)j, &enc);
330 double err = fabs(enc - ll[j]);
331 check = (err < m_home_position_tolerance);
332 }
334 if (check)
335 {
336 yInfo() << "ACTION_START: start position reached successfully";
337 break;
338 }
339 if (yarp::os::Time::now() - move_start_time > m_home_position_timeout)
340 {
341 yWarning() << "ACTION_START: timeout while trying to reach start position";
342 break;
343 }
344 } while (1);
345
346 //switch to position direct mode
347 if (check)
348 {
349 yDebug() << "ACTION_START: switch to position mode";
350
351 for (int j = 0; j <nj; j++)
352 {
353 m_current_driver->setControlMode(j, VOCAB_CM_POSITION_DIRECT);
354 }
356 compute_and_send_command(0);
357
358 this->m_status = ACTION_RUNNING;
359 }
360 else
361 {
362 yError() << "ACTION_START: unable to reach start position!";
363 if (m_home_position_strict_check_enabled)
364 {
365 //very strict behavior! if your are controlling fingers, you will probably end here
366 this->m_status = ACTION_STOP;
367 }
368 else
369 {
370 yDebug() << "ACTION_START: switch to position direct mode";
371 for (int j = 0; j <nj; j++)
372 {
373 m_current_driver->setControlMode(j, VOCAB_CM_POSITION_DIRECT);
374 }
376 compute_and_send_command(0);
377
378 this->m_status = ACTION_RUNNING;
379 }
380 }
382 yInfo() << "ACTION_START: sequence started";
383 }
384 else
385 {
386 yWarning("no sequence in memory");
388 this->m_status = ACTION_STOP;
389 }
390 }
391 else
392 {
393 yError() << "unknown current_status";
394 }
395}
396
398{
399 if (tolerance > 0)
400 {
401 m_home_position_tolerance = tolerance;
402 }
403}
404
406{
407 if (timeout > 0)
408 {
409 m_home_position_timeout = timeout;
410 }
411}
412
414{
415 m_home_position_strict_check_enabled=enable;
416}
constexpr yarp::conf::vocab32_t VOCAB_CM_POSITION
constexpr yarp::conf::vocab32_t VOCAB_CM_POSITION_DIRECT
#define yInfo(...)
Definition Log.h:319
#define yError(...)
Definition Log.h:361
#define yDebug(...)
Definition Log.h:275
#define yWarning(...)
Definition Log.h:340
double getElapsedTime()
bool threadInit() override
Initialization method.
bool action_getname(std::string &name)
void setPositionStrictCheck(bool enable)
bool m_enable_execute_joint_command
void run() override
Loop function.
action_status_enum getStatus()
bool action_resample(double value)
bool action_setSpeedFactor(double factor=1)
void setPositionTolerance(double tolerance)
bool action_change(action_class *action, robotDriver *driver)
ControlThread(std::string name, double period)
ControlClock m_clock
void setPositionTimeout(double timeloops)
void interpolate_action_frames(double timestep)
std::string action_name
Definition robotAction.h:48
size_t get_njoints()
size_t current_frame
Definition robotAction.h:50
double speed_factor
Definition robotAction.h:52
std::deque< action_frame > action_frames_vector
Definition robotAction.h:53
bool setPosition(int j, double ref)
bool setControlMode(const int j, const int mode)
bool getEncoder(int j, double *v)
bool positionMove(int j, double ref)
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
void addFloat64(yarp::conf::float64_t x)
Places a 64-bit floating point number in the bottle, at the end of the list.
Definition Bottle.cpp:158
void clear()
Empties the bottle of any objects it contains.
Definition Bottle.cpp:121
void addInt32(std::int32_t x)
Places a 32-bit integer in the bottle, at the end of the list.
Definition Bottle.cpp:140
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition Bottle.cpp:170
void close() override
Stop port activity.
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
void interrupt() override
Interrupt any current reads or writes attached to the port.
void write(bool forceStrict=false)
Write the current object being returned by BufferedPort::prepare.
T & prepare()
Access the object which will be transmitted by the next call to yarp::os::BufferedPort::write.
size_t getCurrentFrame(double elapsed, std::deque< action_frame > &dq)
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition Time.cpp:121
void delay(double seconds)
Wait for a certain number of seconds.
Definition Time.cpp:111
action_status_enum
Definition robotAction.h:18
@ ACTION_STOP
Definition robotAction.h:22
@ ACTION_IDLE
Definition robotAction.h:19
@ ACTION_RESET
Definition robotAction.h:23
@ ACTION_START
Definition robotAction.h:20
@ ACTION_RUNNING
Definition robotAction.h:21