Calibrator.cpp
Go to the documentation of this file.
00001 /*
00002  * Calibrator.cpp
00003  *
00004  *  Created on: Feb 8, 2012
00005  *      Author: mriedel
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 //#define MAX_ALLOWED_ERROR 0.01
00018 #define VECTOR_ERROR_THRESHOLD 0.005
00019 
00020 // Declare
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         // no Parameters
00065         parameterInitialized = true;
00066 }
00067 
00068 void Calibrator::destroy()
00069 {
00070         // remove Options
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         // Velocity can should almost be 0
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         // Yaw Error should be almost 0
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         // Move RobotID back to CommonOptions???
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         // Get Interface
00103         if (!mkInterface) {
00104                 mkInterface = telekyb_interface::MKInterface::getMKInterface(robotID->getValue());
00105         }
00106         //mkInterface = telekyb_interface::MKInterface::getMKInterface(1); // BEWARE TEMPORARY!!!
00107         if (!mkInterface) {
00108                 // fail
00109                 ROS_ERROR("Unable to get MKInterface for UAV with ID %d!", robotID->getValue());
00110                 return false;
00111         }
00112 
00113         // save position
00114         calibrationPosition = currentState.position;
00115 
00116         // create Matrix -> setValues NAN
00117         errorMatrix = Eigen::MatrixXd::Constant(
00118                         2 * tValueRange->getValue() + 1,
00119                         2 * tValueRange->getValue() + 1,
00120                         std::numeric_limits<double>::quiet_NaN());
00121 
00122         // Initial Field -> Middle
00123         currentField(0) = tValueRange->getValue();
00124         currentField(1) = tValueRange->getValue();
00125 
00126         // Initial Testfield
00127         //currentTestOffset = -1; // IMPORTANT AUTOMATIC FIRST INCREASE!
00128         initialSetup = true;
00129         setValueThreadDone = true;
00130 
00131         calibrationDone = false;
00132 
00133         // save and put to 0.0;
00134         tPCIntegralGainSave = tPCIntegralGain->getValue();
00135         tPCIntegralGain->setValue(0.0);
00136 
00137         // save put off
00138         tDoMassEstimationSave = tDoMassEstimation->getValue();
00139         tDoMassEstimation->setValue(false);
00140 
00141         // temp!
00142         behaviorActiveTimer.reset();
00143         return true;
00144 }
00145 
00146 void Calibrator::didBecomeActive(const TKState& currentState, const Behavior& previousBehavior)
00147 {
00148         // not used
00149 }
00150 
00151 void Calibrator::willBecomeInActive(const TKState& currentState, const Behavior& nextBehavior)
00152 {
00153         // set back
00154         tPCIntegralGain->setValue(tPCIntegralGainSave);
00155         tDoMassEstimation->setValue(tDoMassEstimationSave);
00156 }
00157 
00158 void Calibrator::didBecomeInActive(const TKState& currentState, const Behavior& nextBehavior)
00159 {
00160         // not used
00161 }
00162 
00163 
00164 // called everytime a new TKState is available AND it is the NEW Behavior of an active Switch
00165 void Calibrator::trajectoryStepCreation(const TKState& currentState, TKTrajectory& generatedTrajInput)
00166 {
00167         generatedTrajInput.setPosition(calibrationPosition);
00168         generatedTrajInput.setYawAngle(CALIBRATION_YAW_ANGLE);
00169 }
00170 
00171 // called everytime a new TKState is available. Should return false if invalid (swtich to next behavior, or Hover if undef).
00172 void Calibrator::trajectoryStepActive(const TKState& currentState, TKTrajectory& generatedTrajInput)
00173 {
00174         //std::cout << "Call Calibrator::trajectoryStep" << std::endl;
00175         // always set to the calibration position with constant YawAngle (here it's 0)
00176         generatedTrajInput.setPosition(calibrationPosition);
00177         generatedTrajInput.setYawAngle(CALIBRATION_YAW_ANGLE);
00178 
00179 
00180         if (behaviorActiveTimer.getElapsed().toDSec() < 3.0) {
00181                 // do not do anything
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 //                      mkInterface->setMKValueAsync(offsetRawAcc_X);
00202 //                      mkInterface->setMKValueAsync(offsetRawAcc_Y);
00203                 // spawn thread
00204                 //ROS_INFO("Creating Thread");
00205                 setValueThreadDone = false;
00206                 setValueThread = boost::thread(&Calibrator::setValueThreadFunc, this);
00207 
00208                 initialSetup = false;
00209         }
00210         // don't do anthing within the first two seconds // parameterize
00211 //      if (fabs(currentState.getEulerRPY()(2) - CALIBRATION_YAW_ANGLE) > 0.01)
00212 //              ROS_INFO("Yaw not correct yet.");
00213 //              return true;
00214 //      }
00215 
00216         // Calibration logic
00217 
00218         //ROS_INFO("Error: %f", currentError);
00219 
00220         // Catch Setting Thread done
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                 // set initial conditions
00230                 //maxErrorTest = 0.0;
00231                 //meanErrorTest = 0.0;
00232                 //meanErrorVector = Eigen::Vector2d::Zero();
00233                 //meanNrSamples = 0;
00234                 transitionTimer.reset();
00235                 testTimer.reset();
00236 
00237                 // Start new accumulator
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         // currently testing?
00244 //      if (activeTest) {
00245 
00246 
00247                 //std::cout << "Done Checking Thread with Timed_join" << std::endl;
00248 
00249 //              if (valuesSet &&
00250 //                              mkInterface->getMKCompleteSingeValue(offsetRawAcc_X.id).value == offsetRawAcc_X.value &&
00251 //                              mkInterface->getMKCompleteSingeValue(offsetRawAcc_Y.id).value == offsetRawAcc_Y.value) {
00252 //                      ROS_ERROR("Values successfully set!");
00253 //                      valuesSet = true;
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                         // Test
00262                         //maxErrorTest = std::max(currentError, maxErrorTest);
00263 
00264                         //meanNrSamples++;
00265                         //meanErrorTest = ((double)(meanNrSamples-1) / meanNrSamples)
00266                         //              * meanErrorTest + (currentError / meanNrSamples);
00267 
00268                         //meanErrorVector = (double)((meanNrSamples-1) / meanNrSamples) * meanErrorVector +
00269                         //              (errorVector / (double)meanNrSamples);
00270 
00271                         acc(currentError);
00272                         accMedianX(errorVector(0));
00273                         accMedianY(errorVector(1));
00274 
00275 
00276 
00277                         // Stop test if timer is done
00278                         if (testTimer.getElapsed().toDSec() > tSettleTime->getValue()) {
00279                                 // write fields
00280                                 //double result = 1;
00281                                 //std::cout << "test" << median(acc) << std::endl;
00282 
00283 
00284                                 errorMatrix(
00285                                                 currentField(0),
00286                                                 currentField(1)) = median(acc);
00287 
00288                                 Eigen::Vector2d medianErrorVector( median(accMedianX) , median(accMedianY) );
00289 
00290 //                              activeTest = false;
00291 //
00292                                 ROS_INFO_STREAM("ErrorMatrix: " << std::endl << errorMatrix.block(currentField(0)-3,currentField(1)-3,7,7));
00293                                 //ROS_INFO_STREAM("Mean Error Vector: " << std::endl << meanErrorVector);
00294                                 ROS_INFO_STREAM("Median Error Vector: " << std::endl << medianErrorVector);
00295                                 // Where to change into
00296 
00297 
00298                                 // X and Y jump
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                                         //ROS_INFO("Value for %d: %f", i, jumpStep);
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                                 // We can do this here, because we know(!) there was no field change!
00313                                 if (fabs(medianErrorVector(0)) <= VECTOR_ERROR_THRESHOLD &&
00314                                                 fabs(medianErrorVector(1)) <= VECTOR_ERROR_THRESHOLD) {
00315                                         // BREAK Condition
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                                 // TODO: Test for Bordercondition
00326 
00327 
00328                                 //ROS_INFO("CurrentOffset: %d", currentTestOffset);
00329 
00330 //                              if (!isnan(errorMatrix(
00331 //                                                      currentField(0),
00332 //                                                      currentField(1)))) {
00333 //
00334 //                                      ROS_ERROR("Field already tested. Jumped back?");
00335 //                                      return false;
00336 //                              }
00337 
00338 
00339                                 // set values on QC
00340                                 offsetRawAcc_X.value = currentTestValueX;
00341                                 offsetRawAcc_Y.value = currentTestValueY;
00342                                 valuesSet = false;
00343 
00344         //                      mkInterface->setMKValueAsync(offsetRawAcc_X);
00345         //                      mkInterface->setMKValueAsync(offsetRawAcc_Y);
00346                                 // spawn thread
00347                                 //ROS_INFO("Creating Thread");
00348                                 setValueThreadDone = false;
00349                                 setValueThread = boost::thread(&Calibrator::setValueThreadFunc, this);
00350                                 //ROS_INFO("Done creating Thread");
00351 
00352                                 // set initial conditions next test
00353                                 //activeTest = true;
00354                         }
00355                 }
00356 }
00357 
00358 // called everytime a new TKState is available AND it is the OLD Behavior of an active Switch
00359 void Calibrator::trajectoryStepTermination(const TKState& currentState, TKTrajectory& generatedTrajInput)
00360 {
00361         generatedTrajInput.setPosition(calibrationPosition);
00362         generatedTrajInput.setYawAngle(CALIBRATION_YAW_ANGLE);
00363 }
00364 
00365 // Return true if the active Behavior is (still) valid. Initiate Switch otherwise
00366 bool Calibrator::isValid(const TKState& currentState) const
00367 {
00368         // never turns invalid
00369         return !calibrationDone;
00370 }
00371 
00372 
00373 
00374 
00375 // Threaded SetValue
00376 void Calibrator::setValueThreadFunc()
00377 {
00378         ROS_INFO("In Thread setValueThreadFunc!");
00379         // set X and Y
00380         if (mkInterface->setMKValue(offsetRawAcc_X) && mkInterface->setMKValue(offsetRawAcc_Y)) {
00381                 // everything ok
00382                 ROS_INFO("Successfully set values for X and Y to MK");
00383                 valuesSet = true;
00384         } else {
00385                 // error
00386                 ROS_ERROR("Could not set values to MK!");
00387         }
00388         ROS_INFO("Done with Thread setValueThreadFunc!");
00389 }
00390 
00391 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Defines


tk_mk_tools
Author(s): Martin Riedel
autogenerated on Thu Apr 25 2013 11:16:03