Skip to content

Commit d0c1435

Browse files
authored
Merge pull request #35 from florent-lamiraux/devel
[RSSotController] Better handle subsampling.
2 parents ac02067 + 56046f5 commit d0c1435

File tree

2 files changed

+117
-27
lines changed

2 files changed

+117
-27
lines changed

src/roscontrol-sot-controller.cpp

Lines changed: 96 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,18 @@ RCSotController::RCSotController()
7474
// -> 124 Mo of data.
7575
type_name_("RCSotController"),
7676
simulation_mode_(false),
77-
accumulated_time_(0.0),
78-
jitter_(0.0),
79-
verbosity_level_(0) {
77+
subSampling_(0),
78+
step_(0),
79+
verbosity_level_(0),
80+
io_service_(),
81+
io_work_(io_service_),
82+
sotComputing_(false) {
8083
RESETDEBUG4();
8184
}
8285

8386
RCSotController::~RCSotController() {
87+
io_service_.stop();
88+
thread_pool_.join_all();
8489
std::string afilename("/tmp/sot.log");
8590

8691
RcSotLog_.record(DataOneIter_);
@@ -617,12 +622,6 @@ bool RCSotController::readParamsControlMode(ros::NodeHandle &robot_nh) {
617622
}
618623

619624
bool RCSotController::readParamsdt(ros::NodeHandle &robot_nh) {
620-
/// Reading the jitter is optional but it is a very good idea.
621-
if (robot_nh.hasParam("/sot_controller/jitter")) {
622-
robot_nh.getParam("/sot_controller/jitter", jitter_);
623-
if (verbosity_level_ > 0) ROS_INFO_STREAM("jitter: " << jitter_);
624-
}
625-
626625
/// Read /sot_controller/dt to know what is the control period
627626
if (robot_nh.hasParam("/sot_controller/dt")) {
628627
robot_nh.getParam("/sot_controller/dt", dt_);
@@ -940,13 +939,19 @@ void RCSotController::readControl(
940939
DataOneIter_.controls[i] = command_[i];
941940
}
942941

943-
} else
942+
} else {
944943
ROS_INFO_STREAM("no control.");
944+
localStandbyEffortControlMode(ros::Duration(dtRos_));
945+
localStandbyVelocityControlMode(ros::Duration(dtRos_));
946+
localStandbyPositionControlMode();
947+
}
945948
}
946949

947950
void RCSotController::one_iteration() {
951+
sotComputing_ = true;
948952
// Chrono start
949953
RcSotLog_.start_it();
954+
950955
/// Update the sensors.
951956
fillSensors();
952957

@@ -961,21 +966,24 @@ void RCSotController::one_iteration() {
961966

962967
throw e;
963968
}
964-
965969
try {
966-
sotController_->getControl(controlValues_);
970+
sotController_->getControl(controlValues_copy_);
967971
} catch (std::exception &e) {
968972
std::cerr << "Failure happened during one_iteration(): "
969973
<< "when calling getControl " << std::endl;
970974
std::cerr << __FILE__ << " " << __LINE__ << std::endl
971975
<< e.what() << std::endl;
972-
;
973976
throw e;
974977
}
975978

976-
/// Read the control values
977-
readControl(controlValues_);
978-
979+
// Wait until last subsampling step to write result in controlValues_
980+
while (step_ != subSampling_ - 1) {
981+
ros::Duration(.01 * dtRos_).sleep();
982+
}
983+
// mutex
984+
mutex_.lock();
985+
controlValues_ = controlValues_copy_;
986+
mutex_.unlock();
979987
// Chrono stop.
980988
double it_duration = RcSotLog_.stop_it();
981989
if (it_duration > dt_) {
@@ -985,6 +993,7 @@ void RCSotController::one_iteration() {
985993

986994
/// Store everything in Log.
987995
RcSotLog_.record(DataOneIter_);
996+
sotComputing_ = false;
988997
}
989998

990999
void RCSotController::localStandbyEffortControlMode(
@@ -1073,16 +1082,81 @@ void RCSotController::localStandbyPositionControlMode() {
10731082
first_time = false;
10741083
}
10751084

1085+
void RCSotController::computeSubSampling(const ros::Duration &period) {
1086+
if (subSampling_ != 0) return; // already computed
1087+
dtRos_ = period.toSec();
1088+
double ratio = dt_ / dtRos_;
1089+
if (fabs(ratio - std::round(ratio)) > 1e-8) {
1090+
std::ostringstream os;
1091+
os << "SoT period (" << dt_ << ") is not a multiple of roscontrol period ("
1092+
<< dtRos_
1093+
<< "). Modify rosparam /sot_controller/dt to a "
1094+
"multiple of roscontrol period.";
1095+
throw std::runtime_error(os.str().c_str());
1096+
}
1097+
subSampling_ = static_cast<std::size_t>(std::round(ratio));
1098+
// First time method update is called, step_ will turn to 1.
1099+
step_ = subSampling_ - 1;
1100+
ROS_INFO_STREAM("Subsampling SoT graph computation by ratio "
1101+
<< subSampling_);
1102+
if (subSampling_ != 1) {
1103+
// create thread in this method instead of in constructor to inherit the
1104+
// same priority level.
1105+
// If subsampling is equal to one, the control graph is evaluated in the
1106+
// same thread.
1107+
thread_pool_.create_thread(
1108+
boost::bind(&boost::asio::io_service::run, &io_service_));
1109+
}
1110+
}
10761111
void RCSotController::update(const ros::Time &, const ros::Duration &period) {
10771112
// Do not send any control if the dynamic graph is not started
10781113
if (!isDynamicGraphStopped()) {
1114+
// Increment step at beginning of this method since the end time may
1115+
// vary a lot.
1116+
++step_;
1117+
if (step_ == subSampling_) step_ = 0;
10791118
try {
1080-
double periodInSec = period.toSec();
1081-
if (periodInSec + accumulated_time_ > dt_ - jitter_) {
1119+
// If subsampling is equal to 1, i.e. no subsampling, evaluate
1120+
// control graph in this thread
1121+
if (subSampling_ == 1) {
10821122
one_iteration();
1083-
accumulated_time_ = 0.0;
1084-
} else
1085-
accumulated_time_ += periodInSec;
1123+
} else {
1124+
if (step_ == 0) {
1125+
// If previous graph evaluation is not finished, do not start a new
1126+
// one.
1127+
if (!sotComputing_) {
1128+
io_service_.post(
1129+
boost::bind(&RCSotController::one_iteration, this));
1130+
} else {
1131+
ROS_INFO_STREAM("Sot computation not finished yet.");
1132+
}
1133+
// protected read control
1134+
mutex_.lock();
1135+
/// Read the control values
1136+
readControl(controlValues_);
1137+
mutex_.unlock();
1138+
} else {
1139+
// protected read control
1140+
mutex_.lock();
1141+
// If the robot is controlled in position, update the reference
1142+
// posture with the latest velocity.
1143+
// Note that the entry "velocity" only exists if the robot is
1144+
// controlled in position.
1145+
if (controlValues_.find("velocity") != controlValues_.end()) {
1146+
std::vector<double> control = controlValues_["control"].getValues();
1147+
const std::vector<double> &velocity =
1148+
controlValues_["velocity"].getValues();
1149+
for (std::size_t i = 0; i < control.size(); ++i) {
1150+
control[i] += dtRos_ * velocity[i];
1151+
}
1152+
controlValues_["control"].setValues(control);
1153+
}
1154+
/// Read the control values
1155+
readControl(controlValues_);
1156+
mutex_.unlock();
1157+
}
1158+
}
1159+
10861160
} catch (std::exception const &exc) {
10871161
ROS_ERROR_STREAM("Failure happened during one_iteration evaluation: "
10881162
<< exc.what()
@@ -1097,6 +1171,7 @@ void RCSotController::update(const ros::Time &, const ros::Duration &period) {
10971171
throw;
10981172
}
10991173
} else {
1174+
computeSubSampling(period);
11001175
/// Update the sensors.
11011176
fillSensors();
11021177
try {

src/roscontrol-sot-controller.hh

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#ifndef RC_SOT_CONTROLLER_H
66
#define RC_SOT_CONTROLLER_H
77

8+
#include <atomic>
9+
#include <boost/asio/io_service.hpp>
10+
#include <boost/thread/thread.hpp>
811
#include <map>
912
#include <string>
1013

@@ -75,6 +78,7 @@ class RCSotController : public lci::ControllerBase, SotLoaderBasic {
7578
rc_sot_system::DataToLog DataOneIter_;
7679

7780
private:
81+
void computeSubSampling(const ros::Duration &period);
7882
/// @{ \name Ros-control related fields
7983

8084
/// \brief Vector of joint handles.
@@ -141,12 +145,12 @@ class RCSotController : public lci::ControllerBase, SotLoaderBasic {
141145
/// * torques
142146
std::map<std::string, std::string> mapFromRCToSotDevice_;
143147

144-
/// To be able to subsample control period.
145-
double accumulated_time_;
146-
147-
/// Jitter for the subsampling.
148-
double jitter_;
149-
148+
/// ratio between sot control period and roscontrol control period
149+
std::size_t subSampling_;
150+
/// iteration index of the subsampling. Ranges from 0 to subSampling_-1
151+
std::atomic<std::size_t> step_;
152+
/// double roscontrol sampling period
153+
double dtRos_;
150154
/// \brief Verbosity level for ROS messages during initRequest/initialization
151155
/// phase. 0: no messages or error 1: info 2: debug
152156
int verbosity_level_;
@@ -157,6 +161,16 @@ class RCSotController : public lci::ControllerBase, SotLoaderBasic {
157161
/// Profile log
158162
rc_sot_system::ProfileLog profileLog_;
159163

164+
/// thread pool
165+
boost::asio::io_service io_service_;
166+
boost::asio::io_service::work io_work_;
167+
boost::thread_group thread_pool_;
168+
// mutex to protect access to controlValues_
169+
std::mutex mutex_;
170+
// Flag informing whether the graph computation is running to avoid starting
171+
// a computation if the previous one has no finished.
172+
bool sotComputing_;
173+
160174
public:
161175
RCSotController();
162176

@@ -274,6 +288,7 @@ class RCSotController : public lci::ControllerBase, SotLoaderBasic {
274288

275289
/// Map of control values
276290
std::map<std::string, dgs::ControlValues> controlValues_;
291+
std::map<std::string, dgs::ControlValues> controlValues_copy_;
277292

278293
/// Control period
279294
double dt_;

0 commit comments

Comments
 (0)