00001
00002
00003
00004
00005
00006
00007
00008 #include "Calibrator.hpp"
00009
00010 #include <telekyb_base/ROS/ROSModule.hpp>
00011
00012
00013 #include <telekyb_base/Options/CommonOptions.hpp>
00014
00015 #define CALIBRATION_YAW_ANGLE 0.0
00016 #define DEFAULT_ACC_OFFSET 512
00017
00018 #define VECTOR_ERROR_THRESHOLD 0.005
00019
00020
00021 PLUGINLIB_DECLARE_CLASS(tk_mk_tools, Calibrator, telekyb_behavior::Calibrator, TELEKYB_NAMESPACE::Behavior);
00022
00023 namespace telekyb_behavior {
00024
00025 Calibrator::Calibrator()
00026 : Behavior("tk_mk_tools/Calibrator", BehaviorType::Air),
00027 mkInterface(NULL),
00028 offsetRawAcc_X(MKDataDefines::OFFSET_RAW_ACC_X, DEFAULT_ACC_OFFSET),
00029 offsetRawAcc_Y(MKDataDefines::OFFSET_RAW_ACC_Y, DEFAULT_ACC_OFFSET)
00030
00031
00032 {
00033
00034 }
00035
00036 void Calibrator::initialize()
00037 {
00038 tMaxInitialVelocity = addOption<double>("tMaxInitialVelocity",
00039 "Defines the Maximal Initial Velocity to be able to switch into the Calibrator",
00040 0.1, false, true);
00041 tMaxInitialYawError = addOption<double>("tMaxInitialYawError",
00042 "Defines the Maximal Yaw Error in Radians to switch into the Calibrator",
00043 0.3, false, true);
00044 tSettleTime = addOption<double>("tSettleTime",
00045 "Settling Time in s for each Calibration step. Includes 2s transition time!",
00046 10.0, false, true);
00047
00048 tValueRange = addOption<int>("tValueRange",
00049 "Values to check around center X/Y. Results in a (2*Range + 1)^2 Matrix",
00050 50, false, true);
00051 tCenterValueX = addOption<int>("tCenterValueX",
00052 "Center Value for X",
00053 DEFAULT_ACC_OFFSET, false, true);
00054 tCenterValueY = addOption<int>("tCenterValueY",
00055 "Center Value for Y",
00056 DEFAULT_ACC_OFFSET, false, true);
00057
00058
00059 tPCIntegralGain = OptionContainer::getGlobalOptionByName<double>("PositionControl","tIntegGain");
00060 tDoMassEstimation = OptionContainer::getGlobalOptionByName<bool>("TrajectoryController","tDoMassEstimation");
00061
00062 nodeHandle = ROSModule::Instance().getMainNodeHandle();
00063
00064
00065 parameterInitialized = true;
00066 }
00067
00068 void Calibrator::destroy()
00069 {
00070
00071 std::cout << "Deleting MKInterface" << std::endl;
00072 if (mkInterface) {
00073 delete mkInterface;
00074 }
00075 std::cout << "Done Deleting MKInterface" << std::endl;
00076 }
00077
00078 bool Calibrator::willBecomeActive(const TKState& currentState, const Behavior& previousBehavior)
00079 {
00080
00081 if (currentState.linVelocity.norm() > tMaxInitialVelocity->getValue()) {
00082 ROS_ERROR_STREAM("Too fast to switch into the Calibrator! Current Velocity Norm: "
00083 << currentState.linVelocity.norm());
00084 return false;
00085 }
00086
00087
00088 double angleError = fabs(CALIBRATION_YAW_ANGLE - currentState.getEulerRPY()(2) );
00089 if (angleError > tMaxInitialYawError->getValue()) {
00090 ROS_ERROR_STREAM("Yaw Angle too big. Angle Error: " << angleError);
00091 return false;
00092 }
00093
00094
00095
00096 Option<int>* robotID = OptionContainer::getGlobalOptionByName<int>("TeleKybCore", "tRobotID");
00097 if (!robotID) {
00098 ROS_ERROR_STREAM("Could not get robotID Option");
00099 return false;
00100 }
00101
00102
00103 if (!mkInterface) {
00104 mkInterface = telekyb_interface::MKInterface::getMKInterface(robotID->getValue());
00105 }
00106
00107 if (!mkInterface) {
00108
00109 ROS_ERROR("Unable to get MKInterface for UAV with ID %d!", robotID->getValue());
00110 return false;
00111 }
00112
00113
00114 calibrationPosition = currentState.position;
00115
00116
00117 errorMatrix = Eigen::MatrixXd::Constant(
00118 2 * tValueRange->getValue() + 1,
00119 2 * tValueRange->getValue() + 1,
00120 std::numeric_limits<double>::quiet_NaN());
00121
00122
00123 currentField(0) = tValueRange->getValue();
00124 currentField(1) = tValueRange->getValue();
00125
00126
00127
00128 initialSetup = true;
00129 setValueThreadDone = true;
00130
00131 calibrationDone = false;
00132
00133
00134 tPCIntegralGainSave = tPCIntegralGain->getValue();
00135 tPCIntegralGain->setValue(0.0);
00136
00137
00138 tDoMassEstimationSave = tDoMassEstimation->getValue();
00139 tDoMassEstimation->setValue(false);
00140
00141
00142 behaviorActiveTimer.reset();
00143 return true;
00144 }
00145
00146 void Calibrator::didBecomeActive(const TKState& currentState, const Behavior& previousBehavior)
00147 {
00148
00149 }
00150
00151 void Calibrator::willBecomeInActive(const TKState& currentState, const Behavior& nextBehavior)
00152 {
00153
00154 tPCIntegralGain->setValue(tPCIntegralGainSave);
00155 tDoMassEstimation->setValue(tDoMassEstimationSave);
00156 }
00157
00158 void Calibrator::didBecomeInActive(const TKState& currentState, const Behavior& nextBehavior)
00159 {
00160
00161 }
00162
00163
00164
00165 void Calibrator::trajectoryStepCreation(const TKState& currentState, TKTrajectory& generatedTrajInput)
00166 {
00167 generatedTrajInput.setPosition(calibrationPosition);
00168 generatedTrajInput.setYawAngle(CALIBRATION_YAW_ANGLE);
00169 }
00170
00171
00172 void Calibrator::trajectoryStepActive(const TKState& currentState, TKTrajectory& generatedTrajInput)
00173 {
00174
00175
00176 generatedTrajInput.setPosition(calibrationPosition);
00177 generatedTrajInput.setYawAngle(CALIBRATION_YAW_ANGLE);
00178
00179
00180 if (behaviorActiveTimer.getElapsed().toDSec() < 3.0) {
00181
00182 return;
00183 }
00184
00185 if (initialSetup) {
00186
00187 int currentTestValueX = tCenterValueX->getValue() - tValueRange->getValue() +
00188 currentField(0);
00189
00190 int currentTestValueY = tCenterValueY->getValue() - tValueRange->getValue() +
00191 currentField(1);
00192
00193 ROS_INFO("Now Testing (%d,%d)",
00194 currentTestValueX,
00195 currentTestValueY);
00196
00197 offsetRawAcc_X.value = currentTestValueX;
00198 offsetRawAcc_Y.value = currentTestValueY;
00199 valuesSet = false;
00200
00201
00202
00203
00204
00205 setValueThreadDone = false;
00206 setValueThread = boost::thread(&Calibrator::setValueThreadFunc, this);
00207
00208 initialSetup = false;
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 if (!setValueThreadDone && setValueThread.timed_join(boost::posix_time::microseconds(10))) {
00222 ROS_INFO("Thread has finished");
00223 if (!valuesSet) {
00224 ROS_ERROR("Values could not be set to MK! Canceling Calibration... Implement Retry if this occurs frequently!");
00225 calibrationDone = true;
00226 }
00227 setValueThreadDone = true;
00228
00229
00230
00231
00232
00233
00234 transitionTimer.reset();
00235 testTimer.reset();
00236
00237
00238 acc = accumulator_set<double, stats<tag::median > >();
00239 accMedianX = accumulator_set<double, stats<tag::median > >();
00240 accMedianY = accumulator_set<double, stats<tag::median > >();
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00257 if (setValueThreadDone && valuesSet && transitionTimer.getElapsed().toDSec() > 2.0) {
00258 Eigen::Vector2d errorVector = (currentState.position.head(2) - calibrationPosition.head(2));
00259 double currentError = errorVector.norm();
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271 acc(currentError);
00272 accMedianX(errorVector(0));
00273 accMedianY(errorVector(1));
00274
00275
00276
00277
00278 if (testTimer.getElapsed().toDSec() > tSettleTime->getValue()) {
00279
00280
00281
00282
00283
00284 errorMatrix(
00285 currentField(0),
00286 currentField(1)) = median(acc);
00287
00288 Eigen::Vector2d medianErrorVector( median(accMedianX) , median(accMedianY) );
00289
00290
00291
00292 ROS_INFO_STREAM("ErrorMatrix: " << std::endl << errorMatrix.block(currentField(0)-3,currentField(1)-3,7,7));
00293
00294 ROS_INFO_STREAM("Median Error Vector: " << std::endl << medianErrorVector);
00295
00296
00297
00298
00299 double constantOffset = 1.0-15.0*sqrt(VECTOR_ERROR_THRESHOLD);
00300 for (int i = 0; i < 2; ++i) {
00301 double jumpStep = copysign((sqrt(fabs(medianErrorVector(i))) * 15) + constantOffset, medianErrorVector(i));
00302
00303 currentField(i) -= (int)jumpStep;
00304 }
00305
00306 int currentTestValueX = tCenterValueX->getValue() - tValueRange->getValue() +
00307 currentField(0);
00308
00309 int currentTestValueY = tCenterValueY->getValue() - tValueRange->getValue() +
00310 currentField(1);
00311
00312
00313 if (fabs(medianErrorVector(0)) <= VECTOR_ERROR_THRESHOLD &&
00314 fabs(medianErrorVector(1)) <= VECTOR_ERROR_THRESHOLD) {
00315
00316 ROS_WARN("X and Y below Threshold. Calibration done.");
00317 ROS_WARN("Calibrated Values (X,Y): (%d,%d)", currentTestValueX, currentTestValueY);
00318 calibrationDone = true;
00319 }
00320
00321 ROS_INFO("Now Testing (%d,%d)",
00322 currentTestValueX,
00323 currentTestValueY);
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 offsetRawAcc_X.value = currentTestValueX;
00341 offsetRawAcc_Y.value = currentTestValueY;
00342 valuesSet = false;
00343
00344
00345
00346
00347
00348 setValueThreadDone = false;
00349 setValueThread = boost::thread(&Calibrator::setValueThreadFunc, this);
00350
00351
00352
00353
00354 }
00355 }
00356 }
00357
00358
00359 void Calibrator::trajectoryStepTermination(const TKState& currentState, TKTrajectory& generatedTrajInput)
00360 {
00361 generatedTrajInput.setPosition(calibrationPosition);
00362 generatedTrajInput.setYawAngle(CALIBRATION_YAW_ANGLE);
00363 }
00364
00365
00366 bool Calibrator::isValid(const TKState& currentState) const
00367 {
00368
00369 return !calibrationDone;
00370 }
00371
00372
00373
00374
00375
00376 void Calibrator::setValueThreadFunc()
00377 {
00378 ROS_INFO("In Thread setValueThreadFunc!");
00379
00380 if (mkInterface->setMKValue(offsetRawAcc_X) && mkInterface->setMKValue(offsetRawAcc_Y)) {
00381
00382 ROS_INFO("Successfully set values for X and Y to MK");
00383 valuesSet = true;
00384 } else {
00385
00386 ROS_ERROR("Could not set values to MK!");
00387 }
00388 ROS_INFO("Done with Thread setValueThreadFunc!");
00389 }
00390
00391 }