00001
00002 #include <pluginlib/class_list_macros.h>
00003 #include <vrep_ros_plugin/GenericObjectHandler.h>
00004 #include <quadrotor_tk_handler/Quadrotor_tk_Handler.h>
00005 #include <stdio.h>
00006 #include <v_repLib.h>
00007
00008 #include <telekyb_msgs/TKState.h>
00009 #include <sensor_msgs/Imu.h>
00010
00011 #include <eigen3/Eigen/Geometry>
00012
00013 #include <vrep_ros_plugin/access.h>
00014 #include <vrep_ros_plugin/ConsoleHandler.h>
00015
00016 Quadrotor_tk_Handler::Quadrotor_tk_Handler() : GenericObjectHandler(),
00017 _torqueToForceRatio(0.01738),
00018 _handleOfCoM(-1),
00019 _ctrlMode(CustomDataHeaders::DIRECT),
00020 _tkMotorCommands(4,0),
00021
00022 _quadrotorMass(0.8),
00023
00024 _att_cutoff(2.9),
00025 _att_damping(1.0),
00026 _kp_yaw(1),
00027 _lastReceivedCmdTime(ros::Time::now()),
00028 _previousTime(ros::Time::now()),
00029 _integralTermRoll(0.0),
00030 _integralTermPitch(0.0)
00031 {
00032 }
00033
00034 Quadrotor_tk_Handler::~Quadrotor_tk_Handler(){
00035 }
00036
00037 unsigned int Quadrotor_tk_Handler::getObjectType() const {
00038 return CustomDataHeaders::QUADROTOR_TK_DATA_MAIN;
00039 }
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 void Quadrotor_tk_Handler::synchronize(){
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 simFloat intertia[9];
00087 simFloat compos[3];
00088
00089
00090 simGetShapeMassAndInertia(_associatedObjectID,&_quadrotorMass,intertia,compos,NULL);
00091
00092
00093 _associatedObjectName = simGetObjectName(_associatedObjectID);
00094 std::string objectName(_associatedObjectName);
00095 std::replace( objectName.begin(), objectName.end(), '#', '_');
00096
00097
00098 _pub = _nh.advertise<telekyb_msgs::TKState>(objectName+"/status", 1000);
00099
00100
00101 _pubIMU = _nh.advertise<sensor_msgs::Imu>(objectName+"/IMU", 1000);
00102
00103
00104
00105 }
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135 void Quadrotor_tk_Handler::handleSimulation(){
00136
00137 if(!_initialized){
00138 _initialize();
00139 }
00140
00141
00142 ros::Time now = ros::Time::now();
00143 ros::Duration timeStep = now - _previousTime;
00144
00145
00146
00147
00148 Eigen::Matrix<simFloat, 3, 1> position;
00149
00150 Eigen::Quaternion< simFloat > orientation;
00151 Eigen::Matrix<simFloat, 3, 1> linVelocity;
00152 Eigen::Matrix<simFloat, 3, 1> angVelocity;
00153 const static Eigen::Quaternion< simFloat > nwuToNed(0,1,0,0);
00154
00155 if(simGetObjectPosition(_handleOfCoM, -1, position.data())!=-1 &&
00156 simGetObjectQuaternion(_handleOfCoM, -1, orientation.coeffs().data())!=-1 &&
00157 simGetObjectVelocity(_handleOfCoM, linVelocity.data(), angVelocity.data())!=-1){
00158
00159
00160
00161 position = nwuToNed*position;
00162 linVelocity = nwuToNed*linVelocity;
00163 angVelocity = orientation.conjugate()*angVelocity;
00164 orientation = nwuToNed*orientation;
00165
00166
00167
00168
00169 if (orientation.w()<0){
00170 orientation.coeffs() *=-1;
00171 }
00172
00173
00174 telekyb_msgs::TKState msg;
00175 msg.header.stamp = now;
00176 msg.pose.position.x = position[0];
00177 msg.pose.position.y = position[1];
00178 msg.pose.position.z = position[2];
00179 msg.pose.orientation.w = orientation.w();
00180 msg.pose.orientation.x = orientation.x();
00181 msg.pose.orientation.y = orientation.y();
00182 msg.pose.orientation.z = orientation.z();
00183 msg.twist.linear.x = linVelocity[0];
00184 msg.twist.linear.y = linVelocity[1];
00185 msg.twist.linear.z = linVelocity[2];
00186 msg.twist.angular.x = angVelocity[0];
00187 msg.twist.angular.y = angVelocity[1];
00188 msg.twist.angular.z = angVelocity[2];
00189 std::stringstream ss;
00190
00191
00192 _pub.publish(msg);
00193 }
00194
00195 simFloat TotforceZ = 0.0;
00196
00197 if (_ctrlMode == CustomDataHeaders::DIRECT){
00198
00199 std::cout<<"DEBUG: DIRECT MODE ";
00200
00201 for(uint motorIdx = 0; motorIdx < 4; ++motorIdx){
00202 const simFloat force[3] = {0.0, 0.0, -(simFloat)_tkMotorCommands[motorIdx]};
00203 const simFloat torque[3] = {0.0, 0.0, _torqueToForceRatio*(1-2*((int)(motorIdx/2)))*(simFloat)_tkMotorCommands[motorIdx]};
00204
00205
00206 TotforceZ =+ -(simFloat)_tkMotorCommands[motorIdx];
00207
00208
00209 if(simAddForce(_associatedObjectID, _jointPosition[motorIdx], force)==-1){
00210 simSetLastError( _associatedObjectName.c_str(), "Error applying force.");
00211 } else if(simAddForceAndTorque(_associatedObjectID, NULL, torque)==-1){
00212 simSetLastError( _associatedObjectName.c_str(), "Error applying torque.");
00213 } else if(simSetJointTargetVelocity(_handleOfJoint[motorIdx], 10*_tkMotorCommands[motorIdx])==-1){
00214 simSetLastError( simGetObjectName(_handleOfJoint[motorIdx]), "Error applying velocity.");
00215 }
00216 }
00217 } else if (_ctrlMode == CustomDataHeaders::INTERNAL){
00218
00219
00220
00221
00222
00223
00224
00225
00226 TotforceZ = (simFloat)_tkCommands.thrust;
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 Eigen::Matrix< simFloat, 3, 3> R = orientation.toRotationMatrix();
00240 Eigen::Matrix< simFloat, 3, 1> rpy;
00241 rpy(0) = atan2((double)R(2,1), (double)R(2,2));
00242 rpy(1) = atan2(-R(2,0), sqrt( R(2,1)*R(2,1) + R(2,2)*R(2,2) ) );
00243 rpy(2) = atan2((double)R(1,0),(double)R(0,0));
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 const double cos_r = cos((double)rpy(0));
00254
00255 const double sin_r = sin((double)rpy(0));
00256
00257 const double cos_p = cos((double)rpy(1));
00258
00259 const double sin_p = sin((double)rpy(1));
00260
00261 const double tan_p = tan((double)rpy(1));
00262
00263 const Eigen::Matrix<simFloat, 3, 3> angVelToEulerRate = (Eigen::Matrix<simFloat, 3, 3>() <<
00264 1.0, sin_r*tan_p, cos_r*tan_p,
00265 0.0, cos_r, -sin_r,
00266 0.0, sin_r/cos_p, cos_r/cos_p).finished();
00267
00268 Eigen::Matrix< simFloat, 3, 1> rpyRate = angVelToEulerRate*angVelocity;
00269 const simFloat kp_att = _att_cutoff;
00270 const simFloat kd_att = _att_damping;
00271
00272
00273 const simFloat errorRoll = (_tkCommands.roll)-(rpy(0));
00274 const simFloat errorPitch = (_tkCommands.pitch)-(rpy(1));
00275
00276
00277 _integralTermRoll = _integralTermRoll + timeStep.toSec() * errorRoll;
00278 _integralTermPitch = _integralTermPitch + timeStep.toSec() * errorPitch;
00279 if(_integralTermRoll<0.0001)_integralTermRoll=0.0;
00280 if(_integralTermPitch<0.0001)_integralTermPitch=0.0;
00281
00282
00283
00284
00285
00286
00287
00288
00289 Eigen::Matrix< simFloat, 3, 1> rpyTorque(
00290
00291 kp_att*(errorRoll) + kd_att*(0-rpyRate(0))+0*0.001*_integralTermRoll,
00292
00293
00294 kp_att*(errorPitch) + kd_att*(0-rpyRate(1))+0*0.002*_integralTermPitch,
00295
00296 _kp_yaw*(_tkCommands.yaw- rpyRate(2)));
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 rpyTorque = nwuToNed*orientation*rpyTorque;
00307
00308
00309 Eigen::Matrix< simFloat, 3, 1> worldForce = nwuToNed*orientation*Eigen::Matrix< simFloat, 3, 1>(0.0,0.0,(simFloat)_tkCommands.thrust);
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 if(simAddForceAndTorque(_associatedObjectID, worldForce.data(), rpyTorque.data())==-1){
00325
00326 simSetLastError( _associatedObjectName.c_str(), "Error applying force.");
00327 } else {
00328 for (uint motorIdx = 0; motorIdx < 4; ++motorIdx){
00329
00330 if(simSetJointTargetVelocity(_handleOfJoint[motorIdx], _tkCommands.thrust)==-1){
00331 simSetLastError( simGetObjectName(_handleOfJoint[motorIdx]), "Error applying velocity.");
00332 }
00333 }
00334 }
00335 _previousTime=now;
00336 }
00337
00338 Eigen::Matrix<simFloat, 3, 1> TotCommandforces(0.0, 0.0, TotforceZ);
00339 Eigen::Matrix<simFloat, 3, 1> VectorG (0.0, 0.0, 9.8);
00340 VectorG = orientation.conjugate()*VectorG;
00341
00342
00343 sensor_msgs::Imu msg1;
00344 msg1.header.stamp = ros::Time::now();
00345 msg1.angular_velocity.x = angVelocity[0];
00346 msg1.angular_velocity.y = angVelocity[1];
00347 msg1.angular_velocity.z = angVelocity[2];
00348 msg1.linear_acceleration.x = TotCommandforces[0]/_quadrotorMass + VectorG[0];
00349 msg1.linear_acceleration.y = TotCommandforces[1]/_quadrotorMass + VectorG[1];
00350 msg1.linear_acceleration.z = TotCommandforces[2]/_quadrotorMass + VectorG[2];
00351 _pubIMU.publish(msg1);
00352
00353 if ((now-_lastReceivedCmdTime).toSec() > 0.1){
00354 _tkMotorCommands = std::vector<double>(4,0);
00355 _tkCommands.pitch = 0.0;
00356 _tkCommands.roll = 0.0;
00357 _tkCommands.yaw = 0.0;
00358 _tkCommands.thrust = _quadrotorMass*9.8;
00359 std::stringstream ss;
00360 ss << "I am here" << std::endl;
00361 simAddStatusbarMessage(ss.str().c_str());
00362 ConsoleHandler::printInConsole(ss);
00363 if ((now-_lastPrintedMsg).toSec() >= 1){
00364 std::stringstream ss;
00365 ss << "- [" << _associatedObjectName << "] No command received since more than " << (now-_lastReceivedCmdTime).toSec() << "s!" << std::endl;
00366 simAddStatusbarMessage(ss.str().c_str());
00367 ConsoleHandler::printInConsole(ss);
00368 _lastPrintedMsg = now;
00369 }
00370 }
00371
00372
00373
00374
00375
00376
00377
00378 }
00379
00380
00381 void Quadrotor_tk_Handler::_initialize(){
00382 if (_initialized)
00383 return;
00384
00385
00386 std::vector<unsigned char> developerCustomData;
00387 getDeveloperCustomData(developerCustomData);
00388
00389
00390 std::vector<unsigned char> tempMainData;
00391 std::stringstream ss;
00392
00393 if (CAccess::extractSerializationData(developerCustomData, CustomDataHeaders::IMU_DATA_MASS,tempMainData)){
00394
00395 _quadrotorMass=CAccess::pop_float(tempMainData);
00396 ss << "- [" << _associatedObjectName << "] Setting mass to: " << _quadrotorMass << "." << std::endl;
00397 } else {
00398 _quadrotorMass = 24.0;
00399 ss << "- [" << _associatedObjectName << "] Mass of the quadrotor not specified. using " << _quadrotorMass << " as default." << std::endl;
00400 }
00401
00402 if (CAccess::extractSerializationData(developerCustomData, CustomDataHeaders::QUADROTOR_DATA_TF_RATIO,tempMainData)){
00403 _torqueToForceRatio=CAccess::pop_float(tempMainData);
00404 ss << "- [" << _associatedObjectName << "] Setting torque to force ratio to: " << _torqueToForceRatio << "." << std::endl;
00405 } else {
00406 _torqueToForceRatio = 0.01738;
00407 ss << "- [" << _associatedObjectName << "] Torque to force ratio not specified. using " << _torqueToForceRatio << " as default." << std::endl;
00408 }
00409
00410 if (CAccess::extractSerializationData(developerCustomData, CustomDataHeaders::QUADROTOR_DATA_CTRL_MODE,tempMainData)){
00411 const int ctrlMode = CAccess::pop_int(tempMainData);
00412 if (ctrlMode == (int)(CustomDataHeaders::DIRECT)){
00413 _ctrlMode = CustomDataHeaders::DIRECT;
00414 ss << "- [" << _associatedObjectName << "] Using DIRECT control mode." << std::endl;
00415 } else if (ctrlMode == (int)(CustomDataHeaders::INTERNAL)){
00416 _ctrlMode = CustomDataHeaders::INTERNAL;
00417 ss << "- [" << _associatedObjectName << "] Using INTERNAL control mode." << std::endl;
00418 } else {
00419 _ctrlMode = CustomDataHeaders::DIRECT;
00420 ss << "- [" << _associatedObjectName << "] Invalid control mode specified. using DIRECT as default." << std::endl;
00421 }
00422
00423 } else {
00424 _ctrlMode = CustomDataHeaders::DIRECT;
00425 ss << "- [" << _associatedObjectName << "] Control mode not specified. using DIRECT as default." << std::endl;
00426 }
00427
00428
00429 for(uint motorIdx = 0; motorIdx < 4; ++motorIdx){
00430 _handleOfJoint[motorIdx] = -1;
00431 }
00432 std::vector<int> toExplore;
00433 toExplore.push_back(_associatedObjectID);
00434 while (toExplore.size()!=0)
00435 {
00436 int objHandle=toExplore[toExplore.size()-1];
00437 toExplore.pop_back();
00438
00439 int index=0;
00440 int childHandle=simGetObjectChild(objHandle,index++);
00441 while (childHandle!=-1) {
00442 toExplore.push_back(childHandle);
00443
00444 childHandle=simGetObjectChild(objHandle,index++);
00445 }
00446
00447
00448 int buffSize=simGetObjectCustomDataLength(objHandle,CustomDataHeaders::DEVELOPER_DATA_HEADER);
00449 if (buffSize!=0) {
00450 char* datBuff=new char[buffSize];
00451 simGetObjectCustomData(objHandle,CustomDataHeaders::DEVELOPER_DATA_HEADER,datBuff);
00452 std::vector<unsigned char> developerCustomData(datBuff,datBuff+buffSize);
00453 delete[] datBuff;
00454
00455 std::vector<unsigned char> quadrotorTagData;
00456 for (uint motorIdx = 0; motorIdx < 4; ++motorIdx){
00457 if (CAccess::extractSerializationData(developerCustomData,CustomDataHeaders::QUADROTOR_DATA_MOTOR_0+motorIdx,quadrotorTagData)){
00458 _handleOfJoint[motorIdx]=objHandle;
00459 simGetObjectPosition(objHandle,_associatedObjectID,_jointPosition[motorIdx]);
00460 ss << "- [" << _associatedObjectName << "] Found motor " << motorIdx << " in position ["
00461 << _jointPosition[motorIdx][0] << ", "
00462 << _jointPosition[motorIdx][1] << ", "
00463 << _jointPosition[motorIdx][2] << "]." << std::endl;
00464 }
00465 }
00466 if (CAccess::extractSerializationData(developerCustomData,CustomDataHeaders::QUADROTOR_DATA_COM,quadrotorTagData)){
00467 _handleOfCoM=objHandle;
00468 ss << "- [" << _associatedObjectName << "] Found CENTER OF MASS in '"<< simGetObjectName(objHandle) <<"'." << std::endl;
00469 }
00470 }
00471 }
00472
00473
00474
00475 std::string objectName(_associatedObjectName);
00476 std::replace( objectName.begin(), objectName.end(), '#', '_');
00477
00478 if (_ctrlMode == CustomDataHeaders::DIRECT){
00479 try{
00480 _sub = _nh.subscribe(objectName+"/command", 1000, &Quadrotor_tk_Handler::tkMotorCommandsCallback, this);
00481 } catch (ros::Exception &e) {
00482 std::stringstream ss(e.what());
00483 ss << std::endl;
00484 ConsoleHandler::printInConsole(ss);
00485 }
00486
00487 } else if (_ctrlMode == CustomDataHeaders::INTERNAL){
00488 try{
00489
00490 std::cout<< "Subscribed to Commands";
00491
00492 _sub = _nh.subscribe("/TeleKyb/TeleKybCore_0/Commands", 1000, &Quadrotor_tk_Handler::tkCommandsCallback, this);
00493
00494 } catch (ros::Exception &e) {
00495 std::stringstream ss(e.what());
00496 ss << std::endl;
00497 ConsoleHandler::printInConsole(ss);
00498 }
00499 } else {
00500 simSetLastError( _associatedObjectName.c_str(), "Unknown control mode.");
00501 }
00502
00503
00504
00505 ConsoleHandler::printInConsole(ss);
00506 _initialized=true;
00507 }
00508
00509 void Quadrotor_tk_Handler::tkMotorCommandsCallback(const telekyb_msgs::TKMotorCommands::ConstPtr& msg){
00510 if (msg->force.size() == 4){
00511 _tkMotorCommands = msg->force;
00512 _lastReceivedCmdTime = ros::Time::now();
00513 } else {
00514 simSetLastError( _associatedObjectName.c_str(), "Received wrong command size.");
00515
00516 }
00517 }
00518
00519 void Quadrotor_tk_Handler::tkCommandsCallback(const telekyb_msgs::TKCommands::ConstPtr& msg){
00520 _tkCommands = *msg;
00521 _lastReceivedCmdTime = ros::Time::now();
00522 }
00523
00524
00525 PLUGINLIB_EXPORT_CLASS(Quadrotor_tk_Handler, GenericObjectHandler)
00526
00527
00528
00529