GazeboTaskboard.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013 TopCoder Inc., All Rights Reserved.
00003  */
00004 
00012 #include "../include/GazeboTaskboard.h"
00013 #include <boost/bind.hpp>
00014 #include <stdio.h>
00015 #include <math.h>
00016 #include <common/Events.hh>
00017 #include <std_msgs/String.h>
00018 #include <math/Angle.hh>
00019 #include <math/Pose.hh>
00020 #include <msgs/MessageTypes.hh>
00021 
00022 using namespace gazebo;
00023 using namespace gazebo_taskboard;
00024 
00026 const double POWER_COVER_JOINT_THRESHOLD = M_PI/4;
00027 
00029 const std::string LED_MATERIAL_OFF = "Gazebo/Grey";
00031 const std::string LED_MATERIAL_GREEN = "Gazebo/GreenGlow";
00033 const std::string LED_MATERIAL_BLUE = "Gazebo/BlueGlow";
00034 
00036 const double SIMPLE_LED_LENGTH = 0.0004;
00038 const double SIMPLE_LED_RADIUS = 0.003;
00040 const double NUMPAD_LED_LENGTH = 0.0004;
00042 const double NUMPAD_LED_RADIUS = 0.0095;
00043 
00045 const double LED_HIDE_OFFSET = 100.0;
00047 const double LED_HIDE_OFFSET2 = 105.0;
00048 
00050 const double SAFE_TOGGLE_UPPER_LIMIT_ANGLE = 0.0;
00052 const double SAFE_TOGGLE_LOWER_LIMIT_ANGLE = -0.94;
00054 const double SAFE_TOGGLE_MIDDLE_LIMIT_ANGLE = -0.47;
00056 const double SAFE_TOGGLE_HALF_ANGLE = 0.47;
00057 
00059 const math::Vector3 ZERO_VECTOR = math::Vector3(0, 0, 0);
00060 
00062 enum LedColor
00063 {
00064     eLedColor_Green, // Green led
00065     eLedColor_Blue   // Blue led
00066 };
00067 
00077 struct GazeboTaskboardSlot1::Led
00078 {
00080     bool isOn;
00081 
00082     // We need separate models for different states since ros gazebo plugin does
00083     // not provide a way to change model's material properties
00085     physics::ModelPtr onModel;
00087     physics::ModelPtr offModel;
00088 
00089     // LED model and link names
00091     std::string onModelName;
00093     std::string offModelName;
00095     std::string onLinkName;
00097     std::string offLinkName;
00098 
00099     // LED model initialization parameters.
00100     // The LED model is initialized when gazebo world is fully loaded (first update frame)
00102     int index;
00104     bool numPadLed;
00106     LedColor color;
00108     math::Pose pose;
00109 
00111     Led();
00113     Led(int index_, bool numPadLed_, LedColor color_, math::Pose pose_);
00115     void CreateModel(physics::WorldPtr world);
00117     void SetupModel(physics::WorldPtr world);
00118 };
00119 
00128 struct GazeboTaskboardSlot1::TaskboardLeds
00129 {
00131     Led powerSwitchLed;
00133     Led rockerSwitchUpLed;
00135     Led rockerSwitchDownLed;
00137     Led numPadLeds[NUM_PAD_BUTTONS_COUNT];
00139     Led toggleA03Led;
00141     Led toggleA04TopLed;
00143     Led toggleA04BottomLed;
00145     Led toggleA05Led;
00146 
00148     TaskboardLeds(const math::Pose& pose);
00149 
00151     void CreateModels(physics::WorldPtr world);
00152 
00154     void SetupModels(physics::WorldPtr world);
00155 };
00156 
00163 struct GazeboTaskboardSlot1::TaskboardSlot1State
00164 {
00166     bool isCoverOpen; 
00167 
00169     TwoWayToggleSwitchState powerSwitchState; 
00170     
00172     ThreeWayToggleSwitchState rockerSwitchA01State; 
00173 
00175     bool numPadButtonsSelectedState[NUM_PAD_BUTTONS_COUNT];
00176 
00178     bool isSafeToggleOut[SAFE_TOGGLES_COUNT]; 
00179 
00182     TwoWayToggleSwitchState toggleA03State; 
00183     
00186     ThreeWayToggleSwitchState toggleA04State; 
00187     
00190     TwoWayToggleSwitchState toggleA05State;
00191 
00195     TaskboardSlot1State()
00196     {
00197         for (int i = 0; i < NUM_PAD_BUTTONS_COUNT; i++)
00198         {
00199             numPadButtonsSelectedState[i] = false;
00200         }
00201         for (int i = 0; i < SAFE_TOGGLES_COUNT; i++)
00202         {
00203             isSafeToggleOut[i] = false;
00204         }
00205         isCoverOpen = false;
00206         powerSwitchState = eTwoWayState_Down;
00207         rockerSwitchA01State = eThreeWayState_Center;
00208         toggleA03State = eTwoWayState_Down;
00209         toggleA04State = eThreeWayState_Center;
00210         toggleA05State = eTwoWayState_Down;
00211     }
00212 };
00213 
00220 struct BaseManipulationState
00221 {
00223     double startTime;
00225     double duration;
00226 
00228     BaseManipulationState()
00229     : startTime(0.0)
00230     , duration(0.0)
00231     {}
00232 };
00234 struct PowerCoverManipulationState : BaseManipulationState
00235 {
00237     math::Vector3 angularVelocity;
00238 };
00240 struct PowerSwitchManipulationState : BaseManipulationState
00241 {
00243     math::Vector3 angularVelocity;
00244 };
00246 struct RockerSwitchManipulationState : BaseManipulationState
00247 {
00249     math::Vector3 torque;
00250 };
00252 struct NumPadButtonManipulationState : BaseManipulationState
00253 {
00255     math::Vector3 force;
00256 };
00258 struct SafeToggleManipulationState : BaseManipulationState
00259 {
00261     double value;
00262     
00264     SafeToggleManipulationState()
00265     : value(0.0)
00266     {}
00267 };
00268 
00280 struct GazeboTaskboardSlot1::ManipulationState
00281 {
00283     PowerCoverManipulationState powerCover; 
00285     PowerSwitchManipulationState powerSwitch; 
00287     RockerSwitchManipulationState rockerSwitch; 
00289     NumPadButtonManipulationState numPadButtons[NUM_PAD_BUTTONS_COUNT]; 
00291     SafeToggleManipulationState safeToggles[SAFE_TOGGLES_COUNT][2]; 
00292 };
00293 
00300 inline double deg2rad(double degrees)
00301 {
00302     return M_PI / 180.0 * degrees;
00303 }
00304 
00305 //----------------------------------------------------------------------------------------
00309 GazeboTaskboardSlot1::GazeboTaskboardSlot1()
00310 : firstFrameInitializationDone(false)
00311 , ledsReady(false)
00312 , node("taskboard")
00313 {}
00314 
00320 GazeboTaskboardSlot1::~GazeboTaskboardSlot1()
00321 {
00322     if (updateConnection)
00323     {
00324         event::Events::DisconnectWorldUpdateStart(updateConnection);
00325         updateConnection.reset();
00326     }
00327 }
00328 
00335 void GazeboTaskboardSlot1::Load(physics::ModelPtr _parent, sdf::ElementPtr _sdf)
00336 {
00337     model = _parent;
00338     if (!model)
00339     {
00340         ROS_FATAL("No model is provided for GazeboTaskboard model plugin");
00341         return;
00342     }
00343     // Initialize links and joints from taskboard model
00344     if (!InitLinks() || !InitJoints()) // this also prints ROS_FATAL message in case of error
00345     {
00346         return;
00347     }
00348 
00349     // Listen to the update event.This event is broadcasted every simulation iteration.
00350     updateConnection = event::Events::ConnectWorldUpdateStart(
00351         boost::bind(&GazeboTaskboardSlot1::OnUpdate, this));
00352 
00353     // Init services
00354     srv_manipulatePowerCover = node.advertiseService("manipulate_power_cover", 
00355                                                      &GazeboTaskboardSlot1::ManipulatePowerCover, this);
00356     srv_manipulatePowerSwitch = node.advertiseService("manipulate_power_switch", 
00357                                                      &GazeboTaskboardSlot1::ManipulatePowerSwitch, this);
00358     srv_manipulateRockerSwitch = node.advertiseService("manipulate_rocker_switch_a01", 
00359                                                      &GazeboTaskboardSlot1::ManipulateRockerSwitch, this);
00360     srv_manipulateNumPad = node.advertiseService("manipulate_numpad",
00361                                                      &GazeboTaskboardSlot1::ManipulateNumPad, this);
00362     srv_manipulateSafeToggle = node.advertiseService("manipulate_safe_toggle",
00363                                                      &GazeboTaskboardSlot1::ManipulateSafeToggle, this);
00364 
00365     // Initialize publisher
00366     const int queueSize = 128;
00367     publisher = node.advertise<TaskboardPanelA>("TaskboardPanelA", queueSize);
00368 
00369     // Initialize manipulation state
00370     manipulationState.reset(new ManipulationState);
00371 
00372     //  Initialize LEDs
00373     leds.reset(new TaskboardLeds(model->GetWorldPose()));
00374 
00375     // Initialize controller according to the model state
00376     state.reset(new TaskboardSlot1State);
00377     DeriveStateFromModel();
00378 }
00379 
00390 static physics::LinkPtr getLink(physics::ModelPtr model, const std::string& linkName)
00391 {
00392     physics::LinkPtr link = model->GetLink(linkName);
00393     if (!link)
00394     {
00395         ROS_FATAL("Failed to get %s link from the model", linkName.c_str());
00396     }
00397     return link;
00398 }
00399 
00405 bool GazeboTaskboardSlot1::InitLinks()
00406 {
00407     struct
00408     {
00409         physics::LinkPtr& linkRef;
00410         std::string linkName;
00411     } linksInfo[] = 
00412     {
00413         { linkPowerCover        , "taskboard_slot1_switch1_cover"   },
00414         { linkPowerSwitch       , "taskboard_slot1_switch1"         },
00415         { linkA01Switch         , "taskboard_slot1_switch"          },
00416         { linksNumPad[0]        , "taskboard_slot1_A1"              },
00417         { linksNumPad[1]        , "taskboard_slot1_A2"              },
00418         { linksNumPad[2]        , "taskboard_slot1_A3"              },
00419         { linksNumPad[3]        , "taskboard_slot1_B1"              },
00420         { linksNumPad[4]        , "taskboard_slot1_B2"              },
00421         { linksNumPad[5]        , "taskboard_slot1_B3"              },
00422         { linksNumPad[6]        , "taskboard_slot1_C1"              },
00423         { linksNumPad[7]        , "taskboard_slot1_C2"              },
00424         { linksNumPad[8]        , "taskboard_slot1_C3"              },
00425         { linksBaseSafeToggle[0], "taskboard_slot1_switch2_pullout" },
00426         { linksBaseSafeToggle[1], "taskboard_slot1_switch3_pullout" },
00427         { linksBaseSafeToggle[2], "taskboard_slot1_switch4_pullout" },
00428         { linksSafeToggle[0]    , "taskboard_slot1_switch2"         },
00429         { linksSafeToggle[1]    , "taskboard_slot1_switch3"         },
00430         { linksSafeToggle[2]    , "taskboard_slot1_switch4"         }
00431     };
00432     const int numLinks = sizeof(linksInfo) / sizeof(linksInfo[0]);
00433     for (int i = 0; i < numLinks; i++)
00434     {
00435         linksInfo[i].linkRef = getLink(model, linksInfo[i].linkName);
00436         if (!linksInfo[i].linkRef)
00437         {
00438             return false;
00439         }
00440     }
00441     return true;
00442 }
00443 
00454 static physics::JointPtr getJoint(physics::ModelPtr model, const std::string& jointName)
00455 {
00456     physics::JointPtr joint = model->GetJoint(jointName);
00457     if (!joint)
00458     {
00459         ROS_FATAL("Failed to get %s joint from the model", jointName.c_str());
00460     }
00461     return joint;
00462 }
00463 
00469 bool GazeboTaskboardSlot1::InitJoints()
00470 {
00471     struct
00472     {
00473         physics::JointPtr& jointRef;
00474         std::string jointName;
00475     } jointsInfo[] = 
00476     {
00477         { safeTogglesRevoluteJoints[0] , "taskboard_lower/taskboard_slot1_switch2" },
00478         { safeTogglesRevoluteJoints[1] , "taskboard_lower/taskboard_slot1_switch3" },
00479         { safeTogglesRevoluteJoints[2] , "taskboard_lower/taskboard_slot1_switch4" }
00480     };
00481     const int numJoints = sizeof(jointsInfo) / sizeof(jointsInfo[0]);
00482     for (int i = 0; i < numJoints; i++)
00483     {
00484         jointsInfo[i].jointRef = getJoint(model, jointsInfo[i].jointName);
00485         if (!jointsInfo[i].jointRef)
00486         {
00487             return false;
00488         }
00489     }
00490     return true;
00491 }
00492 
00500 void GazeboTaskboardSlot1::DeriveStateFromModel()
00501 {
00502     // Initialize powerCoverState
00503     math::Pose pose = linkPowerCover->GetRelativePose();
00504     double angle = pose.rot.GetRoll();
00505     state->isCoverOpen = (angle < POWER_COVER_JOINT_THRESHOLD);
00506 
00507     // Initialize powerSwitchState.
00508     // If the power is on then turn on the leds that should be on in current state.
00509     pose = linkPowerSwitch->GetRelativePose();
00510     angle = pose.rot.GetRoll();
00511     state->powerSwitchState = (angle < M_PI_2) ? eTwoWayState_Up : eTwoWayState_Down;
00512 
00513     // Initialize toggleA03State
00514     pose = linksSafeToggle[0]->GetRelativePose();
00515     angle = pose.rot.GetRoll();
00516     state->toggleA03State = (angle < M_PI_2) ? eTwoWayState_Up : eTwoWayState_Down;
00517 
00518     // Initialize toggleA04State
00519     pose = linksSafeToggle[1]->GetRelativePose();
00520     angle = pose.rot.GetRoll();
00521     if (angle < M_PI_2 - SAFE_TOGGLE_HALF_ANGLE/2)
00522     {
00523         state->toggleA04State = eThreeWayState_Up;
00524     }
00525     else if (angle < M_PI_2 + SAFE_TOGGLE_HALF_ANGLE/2)
00526     {
00527         state->toggleA04State = eThreeWayState_Center;
00528     }
00529     else 
00530     {
00531         state->toggleA04State = eThreeWayState_Down;
00532     }
00533 
00534     // Initialize toggleA05State
00535     pose = linksSafeToggle[2]->GetRelativePose();
00536     angle = pose.rot.GetRoll();
00537     state->toggleA05State = (angle < M_PI_2) ? eTwoWayState_Up : eTwoWayState_Down;
00538 }
00539 
00546 void GazeboTaskboardSlot1::OnUpdate()
00547 {
00548     // If condition is true then LED models are available and 
00549     // we should set them up properly
00550     if (firstFrameInitializationDone && !ledsReady)
00551     {
00552         leds->SetupModels(model->GetWorld());
00553         TurnOnLeds(); // turn on necessary leds
00554         ledsReady = true;
00555         return;
00556     }
00557     // Create LED models on the first update frame.
00558     // This is necessary since physics engine is not ready when Load is called 
00559     if (!firstFrameInitializationDone)
00560     {
00561         leds->CreateModels(model->GetWorld());
00562         firstFrameInitializationDone = true;
00563         return;
00564     }
00565 
00566     // Monitor state changes in taskboard elements and simulate expected behavior
00567     MonitorPowerCoverStateChanges();
00568     MonitorPowerSwitchStateChanges();
00569     MonitorRockerSwitchA01StateChanges();
00570     MonitorNumpadStateChanges();
00571     MonitorSafeTogglesStateChanges();
00572 
00573     // Process external manipulation
00574     HandleManipulation();
00575 
00576     // Spin the wheel! Make sure all topic messages are sent
00577     ros::spinOnce();
00578 }
00579 
00583 void GazeboTaskboardSlot1::MonitorPowerCoverStateChanges()
00584 {
00585     math::Pose pose = linkPowerCover->GetRelativePose();
00586     const double angle = pose.rot.GetRoll();
00587     const double threshold = deg2rad(1.0);
00588 
00589     if (angle > threshold && angle < M_PI_2 - threshold)
00590     {
00591         math::Vector3 torque = computeEmpiricalTorque(angle - POWER_COVER_JOINT_THRESHOLD, 1.0, 1.0, 1.5, 15);
00592         linkPowerCover->SetTorque(torque);
00593     }
00594     else if (angle <= threshold)
00595     {
00596         if (!state->isCoverOpen)
00597         {
00598             state->isCoverOpen = true;
00599             PublishState();
00600             // Stabilize link
00601             linkPowerCover->SetAngularVel(ZERO_VECTOR);
00602             linkPowerCover->SetTorque(ZERO_VECTOR);
00603         }
00604     }
00605     else if (angle >= M_PI_2 - threshold)
00606     {
00607         if (state->isCoverOpen)
00608         {
00609             state->isCoverOpen = false;
00610             PublishState();
00611             // Stabilize link
00612             linkPowerCover->SetAngularVel(ZERO_VECTOR);
00613             linkPowerCover->SetTorque(ZERO_VECTOR);
00614         }
00615     }
00616 }
00617 
00621 void GazeboTaskboardSlot1::MonitorPowerSwitchStateChanges()
00622 {
00623     const double halfAngle = 0.419; // According to URDF
00624     const double upDirLimit = M_PI/2 - halfAngle;
00625     const double downDirLimit = M_PI/2 + halfAngle;
00626     const double threshold = deg2rad(1.0);
00627 
00628     math::Pose pose = linkPowerSwitch->GetRelativePose();
00629     const double angle = pose.rot.GetRoll();
00630 
00631     if (angle > upDirLimit + threshold && angle < downDirLimit - threshold)
00632     {
00633         math::Vector3 torque = computeEmpiricalTorque(angle - M_PI_2, 1.0, 1.0, 1.3, 20);
00634         linkPowerSwitch->SetTorque(torque);
00635     }
00636     else if (angle <= upDirLimit + threshold)
00637     {
00638         if (state->powerSwitchState == eTwoWayState_Down)
00639         {
00640             state->powerSwitchState = eTwoWayState_Up;
00641             TurnOnLeds();
00642             PublishState();
00643             // Stabilize link
00644             linkPowerSwitch->SetAngularVel(ZERO_VECTOR);
00645             linkPowerSwitch->SetTorque(ZERO_VECTOR);
00646         }
00647     }
00648     else if (angle >= downDirLimit - threshold)
00649     {
00650         if (state->powerSwitchState == eTwoWayState_Up)
00651         {
00652             state->powerSwitchState = eTwoWayState_Down;
00653             TurnOffAllLeds();
00654             PublishState();
00655             // Stabilize link
00656             linkPowerSwitch->SetAngularVel(ZERO_VECTOR);
00657             linkPowerSwitch->SetTorque(ZERO_VECTOR);
00658         }
00659     }
00660 }
00661 
00665 void GazeboTaskboardSlot1::MonitorRockerSwitchA01StateChanges()
00666 {
00667     const double halfAngle = 0.5; // According to URDF
00668     const double upStateLimit = M_PI_2 - halfAngle;
00669     const double downStateLimit = M_PI_2 + halfAngle;
00670     const double threshold = deg2rad(2.0);
00671 
00672     math::Pose pose = linkA01Switch->GetRelativePose();
00673     double angle = pose.rot.GetRoll();
00674 
00675     if (angle < M_PI_2 - threshold ||  angle > M_PI_2 + threshold)
00676     {
00677         // Switch is out of stable position, try to put it back
00678         const double sign = (angle < M_PI_2) ? 1.0 : -1.0;
00679         const double deviationAngle = sign * std::max(halfAngle - fabs(angle - M_PI_2), 0.0);
00680         math::Vector3 torque = computeEmpiricalTorque(deviationAngle, 8.5, 4.0, 2.5, 7);
00681         linkA01Switch->SetTorque(torque);
00682 
00683         // Check for new state (UP or DOWN)
00684         if (state->rockerSwitchA01State == eThreeWayState_Center)
00685         {
00686             if (angle < upStateLimit + threshold)
00687             {
00688                 state->rockerSwitchA01State = eThreeWayState_Up;
00689                 SetLedState(leds->rockerSwitchUpLed, true);
00690                 PublishState();
00691             }
00692             else if (angle > downStateLimit - threshold)
00693             {
00694                 state->rockerSwitchA01State = eThreeWayState_Down;
00695                 SetLedState(leds->rockerSwitchDownLed, true);
00696                 PublishState();
00697             }
00698         }
00699     }
00700     else 
00701     {
00702         // Check if switch just returned to center position
00703         if (state->rockerSwitchA01State != eThreeWayState_Center)
00704         {
00705             if (leds->rockerSwitchUpLed.isOn)
00706             {
00707                 SetLedState(leds->rockerSwitchUpLed, false);
00708             }
00709             else if (leds->rockerSwitchDownLed.isOn)
00710             {
00711                 SetLedState(leds->rockerSwitchDownLed, false);
00712             }
00713             linkA01Switch->SetAngularVel(ZERO_VECTOR); // Stabilize switch at center position
00714             state->rockerSwitchA01State = eThreeWayState_Center;
00715             PublishState();
00716         }
00717     }
00718 }
00719 
00723 void GazeboTaskboardSlot1::MonitorNumpadStateChanges()
00724 {
00725     const double selRelOffset = -0.4811;
00726     const double epsilon = 0.0003;
00727 
00728     // Simulate springs which influence the buttons, so when we release
00729     // the button it returns to UNSEL position
00730     for (int i = 0; i < NUM_PAD_BUTTONS_COUNT; i++)
00731     {
00732         linksNumPad[i]->SetForce(ZERO_VECTOR);
00733         linksNumPad[i]->AddRelativeForce(math::Vector3(0, 0, 5));
00734     }
00735     // Check for state changes
00736     for (int i = 0; i < NUM_PAD_BUTTONS_COUNT; i++)
00737     {
00738         const double offset = linksNumPad[i]->GetRelativePose().pos.y;
00739         
00740         bool selected = (offset < selRelOffset + epsilon);
00741         if (selected ^ state->numPadButtonsSelectedState[i])
00742         {
00743             state->numPadButtonsSelectedState[i] = selected;
00744             if (selected)
00745             {
00746                 SetLedState(leds->numPadLeds[i], !leds->numPadLeds[i].isOn);
00747             }
00748             PublishState();
00749         }
00750     }
00751 }
00752 
00763 bool GazeboTaskboardSlot1::UpdateTransitionFromOutState2Way(
00764     physics::LinkPtr link, physics::JointPtr joint, TwoWayToggleSwitchState& state) const
00765 {
00766     const double halfAngle = 0.47; // according to joint specification
00767     const double threshold = deg2rad(1.0);
00768     const double upDirLimit = M_PI_2 - halfAngle;
00769     const double downDirLimit = M_PI_2 + halfAngle;
00770 
00771     math::Pose pose = link->GetRelativePose();
00772     const double angle = pose.rot.GetRoll();
00773 
00774     if (angle > upDirLimit + threshold && angle < downDirLimit - threshold)
00775     {
00776         math::Vector3 torque = computeEmpiricalTorque(angle - M_PI_2, 0.8, 1.0, 1.5, 15);
00777         link->SetTorque(torque);
00778         return false;
00779     }
00780     if (angle <= upDirLimit + threshold)
00781     {
00782         state = eTwoWayState_Up;
00783         // Latch the joint
00784         joint->SetHighStop(0, math::Angle(SAFE_TOGGLE_LOWER_LIMIT_ANGLE + threshold));
00785         joint->SetLowStop(0, math::Angle(SAFE_TOGGLE_LOWER_LIMIT_ANGLE - threshold));
00786     }
00787     else
00788     {
00789         state = eTwoWayState_Down;
00790         // Latch the joint
00791         joint->SetHighStop(0, math::Angle(SAFE_TOGGLE_UPPER_LIMIT_ANGLE + threshold));
00792         joint->SetLowStop(0, math::Angle(SAFE_TOGGLE_UPPER_LIMIT_ANGLE - threshold));
00793     }
00794     return true;
00795 }
00796 
00807 bool GazeboTaskboardSlot1::UpdateTransitionFromOutState3Way(
00808     physics::LinkPtr link, physics::JointPtr joint, ThreeWayToggleSwitchState& state) const
00809 {
00810     const double halfAngle = 0.47;
00811     const double upDirLimit = M_PI/2 - halfAngle;
00812     const double downDirLimit = M_PI/2 + halfAngle;
00813     const double threshold = deg2rad(1.0);
00814 
00815     math::Pose pose = link->GetRelativePose();
00816     double angle = pose.rot.GetRoll();
00817     
00818     if (angle > upDirLimit + threshold && angle < M_PI_2 - threshold)
00819     {
00820         math::Vector3 torque = computeEmpiricalTorque(angle - (M_PI_2 - halfAngle/2), 0.8, 1.0, 1.5, 15);
00821         link->SetTorque(torque);
00822         return false;
00823     }
00824     else if (angle > M_PI_2 + threshold && angle < downDirLimit - threshold)
00825     {
00826         math::Vector3 torque = computeEmpiricalTorque(angle - (M_PI_2 + halfAngle/2), 0.8, 1.0, 1.5, 15);
00827         link->SetTorque(torque);
00828         return false;
00829     }
00830     if (angle <= upDirLimit + threshold)
00831     {
00832         state = eThreeWayState_Up;
00833         // Latch the joint
00834         joint->SetHighStop(0, math::Angle(SAFE_TOGGLE_LOWER_LIMIT_ANGLE + threshold));
00835         joint->SetLowStop(0, math::Angle(SAFE_TOGGLE_LOWER_LIMIT_ANGLE - threshold));
00836         link->SetTorque(ZERO_VECTOR);
00837     }
00838     else if (angle >= downDirLimit - threshold)
00839     {
00840         state = eThreeWayState_Down;
00841         // Latch the joint
00842         joint->SetHighStop(0, math::Angle(SAFE_TOGGLE_UPPER_LIMIT_ANGLE + threshold));
00843         joint->SetLowStop(0, math::Angle(SAFE_TOGGLE_UPPER_LIMIT_ANGLE - threshold));
00844         link->SetTorque(ZERO_VECTOR);
00845     } 
00846     else
00847     {
00848         state = eThreeWayState_Center;
00849         // Latch the joint
00850         joint->SetHighStop(0, math::Angle(SAFE_TOGGLE_MIDDLE_LIMIT_ANGLE + threshold));
00851         joint->SetLowStop(0, math::Angle(SAFE_TOGGLE_MIDDLE_LIMIT_ANGLE - threshold));
00852         link->SetTorque(ZERO_VECTOR);
00853     }
00854     return true;
00855 }
00856 
00860 void GazeboTaskboardSlot1::MonitorSafeTogglesStateChanges()
00861 {
00862     // The pull out distance as defined in URDF files. 
00863     const double pullOutDistance = 0.002;
00864     // The delta below should be smaller then pull out offset.
00865     const double delta = 0.0004;
00866     
00867     // Check which joints is pulled out
00868     bool isOut[SAFE_TOGGLES_COUNT];
00869     float offsets[SAFE_TOGGLES_COUNT]; // toggles pulled out offsets
00870     for (int i = 0; i < SAFE_TOGGLES_COUNT; i++)
00871     {
00872         const math::Pose outPose = linksBaseSafeToggle[i]->GetRelativePose();
00873         const math::Pose pose = linksSafeToggle[i]->GetRelativePose();
00874         offsets[i] = std::max(pullOutDistance - outPose.CoordPositionSub(pose).z, 0.0);
00875         isOut[i] = (offsets[i] > pullOutDistance - delta);
00876     }
00877      // Set OUT state
00878     for (int i = 0; i < SAFE_TOGGLES_COUNT; i++)
00879     {
00880         if (!state->isSafeToggleOut[i] && isOut[i])
00881         {
00882             state->isSafeToggleOut[i] = true;
00883             
00884             // Release revolute joint
00885             safeTogglesRevoluteJoints[i]->SetHighStop(0, math::Angle(SAFE_TOGGLE_UPPER_LIMIT_ANGLE));
00886             safeTogglesRevoluteJoints[i]->SetLowStop(0, math::Angle(SAFE_TOGGLE_LOWER_LIMIT_ANGLE));
00887             
00888             // turn off LEDs
00889             switch (i)
00890             {
00891                 case 0: // A03
00892                     SetLedState(leds->toggleA03Led, false);
00893                     break;
00894                 case 1: // A04
00895                     SetLedState(leds->toggleA04TopLed, false);
00896                     SetLedState(leds->toggleA04BottomLed, false);
00897                     break;
00898                 case 2: // A05
00899                     SetLedState(leds->toggleA05Led, false);
00900                     break;
00901             }
00902             PublishState();
00903         }
00904     }
00905     // Update two-way safe toggles that are in transition from OUT state
00906     if (state->isSafeToggleOut[0] && offsets[0] < pullOutDistance - 2*delta)
00907     {
00908         bool transitionDone = UpdateTransitionFromOutState2Way(
00909             linksSafeToggle[0], safeTogglesRevoluteJoints[0], state->toggleA03State);
00910         if (transitionDone)
00911         {
00912             state->isSafeToggleOut[0] = false;
00913             SetLedState(leds->toggleA03Led, state->toggleA03State == eTwoWayState_Up);
00914             PublishState();
00915         }
00916     }
00917     if (state->isSafeToggleOut[2] && offsets[2] < pullOutDistance - 2*delta)
00918     {
00919         bool transitionDone = UpdateTransitionFromOutState2Way(
00920             linksSafeToggle[2], safeTogglesRevoluteJoints[2], state->toggleA05State);
00921         if (transitionDone)
00922         {
00923             state->isSafeToggleOut[2] = false;
00924             SetLedState(leds->toggleA05Led, state->toggleA05State == eTwoWayState_Up);
00925             PublishState();
00926         }
00927     }
00928     // Update three-way safe toggles that are in transition from OUT state
00929     if (state->isSafeToggleOut[1] && offsets[1] < pullOutDistance - 2*delta)
00930     {
00931         bool transitionDone = UpdateTransitionFromOutState3Way(
00932             linksSafeToggle[1], safeTogglesRevoluteJoints[1], state->toggleA04State);
00933         if (transitionDone)
00934         {
00935             state->isSafeToggleOut[1] = false;
00936             SetLedState(leds->toggleA04TopLed, state->toggleA04State == eThreeWayState_Up);
00937             SetLedState(leds->toggleA04BottomLed, state->toggleA04State == eThreeWayState_Down);
00938             PublishState();
00939         }
00940     }
00941     // Simulate springs that pull the toggles in
00942     for (int i = 0; i < SAFE_TOGGLES_COUNT; i++)
00943     {
00944         if (state->isSafeToggleOut[i] || offsets[i] > delta)
00945         {
00946             linksSafeToggle[i]->SetForce(ZERO_VECTOR);
00947             linksSafeToggle[i]->AddRelativeForce(math::Vector3(0, 0, -2));
00948         }
00949         else if (offsets[i] <= delta/2)
00950         {
00951             linksSafeToggle[i]->SetForce(ZERO_VECTOR);
00952             linksSafeToggle[i]->SetLinearVel(ZERO_VECTOR);
00953             linksSafeToggle[i]->SetAngularVel(ZERO_VECTOR);
00954         }
00955     }
00956 }
00957 
00963 void GazeboTaskboardSlot1::PublishState()
00964 {
00965     const std::string UP     = "UP";
00966     const std::string DOWN   = "DOWN";
00967     const std::string CENTER = "CENTER";
00968     const std::string ON     = "ON";
00969     const std::string OFF    = "OFF";
00970     const std::string SEL    = "SEL";
00971     const std::string UNSEL  = "UNSEL";
00972     const std::string OUT    = "OUT";
00973 
00974     // Initialize the message by collecting information from all elements
00975     TaskboardPanelA msg;
00976 
00977     msg.PANEL_POWER_COVER  = state->isCoverOpen ? UP : DOWN;
00978     msg.PANEL_POWER_SWITCH = state->powerSwitchState == eTwoWayState_Up ? UP : DOWN;
00979     msg.PANEL_POWER_LED    = leds->powerSwitchLed.isOn ? ON : OFF;
00980     
00981     msg.A01_ROCKER_SWITCH  = state->rockerSwitchA01State == eThreeWayState_Center
00982                               ? CENTER 
00983                               : (state->rockerSwitchA01State == eThreeWayState_Up ? UP : DOWN);
00984 
00985     msg.A01_ROCKER_LED_TOP    = leds->rockerSwitchUpLed.isOn ? ON : OFF;
00986     msg.A01_ROCKER_LED_BOTTOM = leds->rockerSwitchDownLed.isOn ? ON : OFF;
00987 
00988     msg.A02_LED_NUM_PAD_A1 = leds->numPadLeds[0].isOn ? ON : OFF;
00989     msg.A02_LED_NUM_PAD_A2 = leds->numPadLeds[1].isOn ? ON : OFF;
00990     msg.A02_LED_NUM_PAD_A3 = leds->numPadLeds[2].isOn ? ON : OFF;
00991     msg.A02_LED_NUM_PAD_B1 = leds->numPadLeds[3].isOn ? ON : OFF;
00992     msg.A02_LED_NUM_PAD_B2 = leds->numPadLeds[4].isOn ? ON : OFF;
00993     msg.A02_LED_NUM_PAD_B3 = leds->numPadLeds[5].isOn ? ON : OFF;
00994     msg.A02_LED_NUM_PAD_C1 = leds->numPadLeds[6].isOn ? ON : OFF;
00995     msg.A02_LED_NUM_PAD_C2 = leds->numPadLeds[7].isOn ? ON : OFF;
00996     msg.A02_LED_NUM_PAD_C3 = leds->numPadLeds[8].isOn ? ON : OFF;
00997 
00998     msg.A02_NUM_PAD_A1 = state->numPadButtonsSelectedState[0] ? SEL : UNSEL;
00999     msg.A02_NUM_PAD_A2 = state->numPadButtonsSelectedState[1] ? SEL : UNSEL;
01000     msg.A02_NUM_PAD_A3 = state->numPadButtonsSelectedState[2] ? SEL : UNSEL;
01001     msg.A02_NUM_PAD_B1 = state->numPadButtonsSelectedState[3] ? SEL : UNSEL;
01002     msg.A02_NUM_PAD_B2 = state->numPadButtonsSelectedState[4] ? SEL : UNSEL;
01003     msg.A02_NUM_PAD_B3 = state->numPadButtonsSelectedState[5] ? SEL : UNSEL;
01004     msg.A02_NUM_PAD_C1 = state->numPadButtonsSelectedState[6] ? SEL : UNSEL;
01005     msg.A02_NUM_PAD_C2 = state->numPadButtonsSelectedState[7] ? SEL : UNSEL;
01006     msg.A02_NUM_PAD_C3 = state->numPadButtonsSelectedState[8] ? SEL : UNSEL;
01007     
01008     msg.A03_LED        = leds->toggleA03Led.isOn ? ON : OFF;
01009     msg.A04_LED_TOP    = leds->toggleA04TopLed.isOn ? ON : OFF;
01010     msg.A04_LED_BOTTOM = leds->toggleA04BottomLed.isOn ? ON : OFF;
01011     msg.A05_LED        = leds->toggleA05Led.isOn ? ON : OFF;
01012 
01013     msg.A03_TOGGLE = state->isSafeToggleOut[0] 
01014                       ? OUT 
01015                       : (state->toggleA03State == eTwoWayState_Up ? UP : DOWN);
01016 
01017     msg.A04_TOGGLE = state->isSafeToggleOut[1] 
01018                       ? OUT 
01019                       : (state->toggleA04State == eThreeWayState_Center
01020                           ? CENTER
01021                           : (state->toggleA04State == eThreeWayState_Up ? UP : DOWN));
01022 
01023     msg.A05_TOGGLE = state->isSafeToggleOut[2] 
01024                       ? OUT 
01025                       : (state->toggleA05State == eTwoWayState_Up ? UP : DOWN);
01026 
01027     // Finally publish the message
01028     publisher.publish(msg);
01029 }
01030 
01037 void GazeboTaskboardSlot1::SetLedState(Led& led, bool on)
01038 {
01039     // Do nothing if the led is already in the requested state
01040     if (led.isOn == on)
01041     {
01042         return;
01043     }
01044     // Do not turn LED on if the power switch is off
01045     if (state->powerSwitchState != eTwoWayState_Up && on)
01046     {
01047         return;
01048     }
01049 
01050     // Get current pose
01051     math::Pose pose = led.onModel->GetRelativePose();
01052     math::Pose pose2 = led.offModel->GetRelativePose();
01053     
01054     // Update pose based on new LED state
01055     if (on)
01056     {
01057         pose.pos.z -= LED_HIDE_OFFSET;
01058         pose2.pos.z += LED_HIDE_OFFSET2;
01059     }
01060     else
01061     {
01062         pose.pos.z += LED_HIDE_OFFSET;
01063         pose2.pos.z -= LED_HIDE_OFFSET2;
01064     }
01065     led.onModel->SetLinkWorldPose(pose, led.onLinkName);
01066     led.offModel->SetLinkWorldPose(pose2, led.offLinkName);
01067     led.isOn = on;
01068 }
01069 
01073 void GazeboTaskboardSlot1::TurnOnLeds()
01074 {
01075     if (state->powerSwitchState == eTwoWayState_Up)
01076     {
01077         // Power switch LED
01078         SetLedState(leds->powerSwitchLed, true);
01079         
01080         // Rocker switch LEDs
01081         if (state->rockerSwitchA01State == eThreeWayState_Up)
01082         {
01083             SetLedState(leds->rockerSwitchUpLed, true);
01084         }
01085         else if (state->rockerSwitchA01State == eThreeWayState_Down)
01086         {
01087             SetLedState(leds->rockerSwitchDownLed, true);
01088         }
01089         // A03 LED
01090         if (state->toggleA03State == eTwoWayState_Up)
01091         {
01092             SetLedState(leds->toggleA03Led, true);
01093         }
01094         // A05 LED
01095         if (state->toggleA05State == eTwoWayState_Up)
01096         {
01097             SetLedState(leds->toggleA05Led, true);
01098         }
01099         // A04 LEDs
01100         if (state->toggleA04State == eThreeWayState_Up)
01101         {
01102             SetLedState(leds->toggleA04TopLed, true);
01103         }
01104         else if (state->toggleA04State == eThreeWayState_Down)
01105         {
01106             SetLedState(leds->toggleA04BottomLed, true);
01107         }
01108     }
01109 }
01110 
01114 void GazeboTaskboardSlot1::TurnOffAllLeds()
01115 {
01116     SetLedState(leds->powerSwitchLed, false);
01117     SetLedState(leds->rockerSwitchUpLed, false);
01118     SetLedState(leds->rockerSwitchDownLed, false);
01119     SetLedState(leds->toggleA03Led, false);
01120     SetLedState(leds->toggleA05Led, false);
01121     SetLedState(leds->toggleA04TopLed, false);
01122     SetLedState(leds->toggleA04BottomLed, false);
01123 
01124     for (int i = 0; i < NUM_PAD_BUTTONS_COUNT; i++)
01125     {
01126         SetLedState(leds->numPadLeds[i], false);
01127     }
01128 }
01129 
01130 //----------------------------------------------------------------------------------------
01131 // Taskboard Manipulation
01132 //----------------------------------------------------------------------------------------
01143 bool GazeboTaskboardSlot1::ManipulatePowerCover(
01144     ManipulatePowerCover::Request& request, ManipulatePowerCover::Response& response)
01145 {
01146     math::Pose globalPose = model->GetWorldPose();
01147     const double velocity = request.angle / request.duration;
01148     
01149     PowerCoverManipulationState &manipState = manipulationState->powerCover;
01150 
01151     manipState.duration = request.duration;
01152     manipState.startTime = GetTime();
01153     manipState.angularVelocity = globalPose.rot * math::Vector3(velocity, 0, 0);
01154 
01155     linkPowerCover->SetAngularVel(manipState.angularVelocity);
01156     return true;
01157 }
01158 
01169 bool GazeboTaskboardSlot1::ManipulatePowerSwitch(
01170     ManipulatePowerSwitch::Request& request, ManipulatePowerSwitch::Response& response)
01171 {
01172     math::Pose globalPose = model->GetWorldPose();
01173     const double velocity = request.angle / request.duration;
01174     
01175     PowerSwitchManipulationState &manipState = manipulationState->powerSwitch;
01176 
01177     manipState.duration = request.duration;
01178     manipState.startTime = GetTime();
01179     manipState.angularVelocity = globalPose.rot * math::Vector3(velocity, 0, 0);
01180 
01181     linkPowerSwitch->SetAngularVel(manipState.angularVelocity);
01182     return true;
01183 }
01184 
01195 bool GazeboTaskboardSlot1::ManipulateRockerSwitch(
01196     ManipulateRockerSwitch::Request& request, ManipulateRockerSwitch::Response& response)
01197 {
01198     math::Pose globalPose = model->GetWorldPose();
01199     
01200     RockerSwitchManipulationState &manipState = manipulationState->rockerSwitch;
01201 
01202     manipState.startTime = GetTime();
01203     manipState.duration = request.duration;
01204     manipState.torque = globalPose.rot * math::Vector3(request.torque, 0, 0);
01205 
01206     linkA01Switch->SetTorque(manipState.torque);
01207     return true;
01208 }
01209 
01220 bool GazeboTaskboardSlot1::ManipulateNumPad(
01221     ManipulateNumPad::Request& request, ManipulateNumPad::Response& response)
01222 {
01223     if (request.index < 0 || request.index >= NUM_PAD_BUTTONS_COUNT)
01224     {
01225         return false;
01226     }
01227     NumPadButtonManipulationState &manipState = manipulationState->numPadButtons[request.index];
01228     
01229     manipState.startTime = GetTime();
01230     manipState.duration = request.duration;
01231     manipState.force = math::Vector3(0, 0, -request.force);
01232 
01233     linksNumPad[request.index]->AddRelativeForce(manipState.force);
01234     return true;
01235 }
01236 
01248 bool GazeboTaskboardSlot1::ManipulateSafeToggle(
01249     ManipulateSafeToggle::Request& request, ManipulateSafeToggle::Response& response)
01250 {
01251     if (request.index < 0 || request.index >= SAFE_TOGGLES_COUNT)
01252     {
01253         return false;
01254     }
01255     if (request.mode < 0 || request.mode >= 2)
01256     {
01257         return false;
01258     }
01259     SafeToggleManipulationState &manipState = manipulationState->safeToggles[request.index][request.mode];
01260 
01261     manipState.startTime = GetTime();
01262     manipState.duration = request.duration;
01263     manipState.value = request.value;
01264 
01265     physics::LinkPtr link = linksSafeToggle[request.index];
01266     if (request.mode == 0)
01267     {
01268         link->SetForce(ZERO_VECTOR);
01269         link->AddRelativeForce(math::Vector3(0, 0, manipState.value));
01270     }
01271     else
01272     {
01273         const double velocity = manipState.value / manipState.duration;
01274         math::Pose basePose = model->GetWorldPose();
01275         math::Vector3 angularVelocity =  basePose.rot * math::Vector3(velocity, 0, 0);
01276         link->SetAngularVel(angularVelocity);
01277     }
01278     return true;
01279 }
01280 
01284 void GazeboTaskboardSlot1::HandleManipulation()
01285 {
01286     const double time = GetTime();
01287     // Check power cover
01288     if (manipulationState->powerCover.startTime)
01289     {
01290         const double elapsedTime = time - manipulationState->powerCover.startTime;
01291         if (elapsedTime >= manipulationState->powerCover.duration)
01292         {
01293             linkPowerCover->SetAngularVel(ZERO_VECTOR);
01294             manipulationState->powerCover.startTime = 0.0;
01295         }
01296         else 
01297         {
01298             linkPowerCover->SetAngularVel(manipulationState->powerCover.angularVelocity);
01299         }
01300     }
01301     // Check power switch
01302     if (manipulationState->powerSwitch.startTime)
01303     {
01304         const double elapsedTime = time - manipulationState->powerSwitch.startTime;
01305         if (elapsedTime >= manipulationState->powerSwitch.duration)
01306         {
01307             linkPowerSwitch->SetAngularVel(ZERO_VECTOR);
01308             manipulationState->powerSwitch.startTime = 0.0;
01309         }
01310         else 
01311         {
01312             linkPowerSwitch->SetAngularVel(manipulationState->powerSwitch.angularVelocity);
01313         }
01314     }
01315     // Check rocker switch A01
01316     if (manipulationState->rockerSwitch.startTime)
01317     {
01318         const double elapsedTime = time - manipulationState->rockerSwitch.startTime;
01319         if (elapsedTime >= manipulationState->rockerSwitch.duration)
01320         {
01321             linkA01Switch->SetTorque(ZERO_VECTOR);
01322             manipulationState->rockerSwitch.startTime = 0.0;
01323         }
01324         else
01325         {
01326             linkA01Switch->SetTorque(manipulationState->rockerSwitch.torque);
01327         }
01328     }
01329     // Check num pad buttons
01330     for (int i = 0; i < NUM_PAD_BUTTONS_COUNT; i++)
01331     {
01332         NumPadButtonManipulationState &manipState = manipulationState->numPadButtons[i];
01333         if (manipState.startTime)
01334         {
01335             const double elapsedTime = time - manipState.startTime;
01336             if (elapsedTime >= manipState.duration)
01337             {
01338                 manipState.startTime = 0.0;
01339             }
01340             else
01341             {
01342                 linksNumPad[i]->AddRelativeForce(manipState.force);
01343             }
01344         }
01345     }
01346     // Check safe toggles
01347     for (int i = 0; i < SAFE_TOGGLES_COUNT; i++)
01348     {
01349         SafeToggleManipulationState &manipState = manipulationState->safeToggles[i][0];
01350         if (manipState.startTime)
01351         {
01352             physics::LinkPtr link = linksSafeToggle[i];
01353             const double elapsedTime = time - manipState.startTime;
01354             if (elapsedTime >= manipState.duration) // reset manipulation influence
01355             {
01356                 link->SetForce(ZERO_VECTOR);
01357                 manipState.startTime = 0.0;
01358             }
01359             else // refresh manipulation influence
01360             {
01361                 link->SetForce(ZERO_VECTOR);
01362                 link->AddRelativeForce(math::Vector3(0, 0,  manipState.value));
01363             }
01364         }
01365         SafeToggleManipulationState &manipState2 = manipulationState->safeToggles[i][1];
01366         if (manipState2.startTime)
01367         {
01368             physics::LinkPtr link = linksSafeToggle[i];
01369             const double elapsedTime = time - manipState2.startTime;
01370             if (elapsedTime >= manipState2.duration) // reset manipulation influence
01371             {
01372                 link->SetAngularVel(ZERO_VECTOR);
01373                 link->SetLinearVel(ZERO_VECTOR);
01374                 manipState2.startTime = 0.0;
01375             }
01376             else // refresh manipulation influence
01377             {
01378                 const double velocity = manipState2.value / manipState2.duration;
01379                 math::Pose basePose = model->GetWorldPose();
01380                 math::Vector3 angularVelocity =  basePose.rot * math::Vector3(velocity, 0, 0);
01381                 link->SetAngularVel(angularVelocity);
01382             }
01383         }
01384     }
01385 }
01386 
01398 math::Vector3 GazeboTaskboardSlot1::computeEmpiricalTorque(
01399     double deviationAngle, double initialValue,
01400     double snapCoeff, double snapExp, double torqueCoeff) const
01401 {
01402     // Horizontal direction along taskboard, it's an axis of rotation for the most switches.
01403     const math::Vector3 axis = model->GetWorldPose().rot * math::Vector3(1, 0, 0);
01404     // Rotation direction
01405     const double sign = (deviationAngle < 0) ? 1.0 : -1.0;
01406     // Torque amount expression for physically plausible behavior
01407     const double torqueValue = (initialValue + pow(snapCoeff * fabs(deviationAngle), snapExp)) * sign * torqueCoeff;
01408     return axis * torqueValue;
01409 }
01410 
01416 double GazeboTaskboardSlot1::GetTime() const
01417 {
01418     return model->GetWorld()->GetSimTime().Double();
01419 }
01420 
01421 //----------------------------------------------------------------------------------------
01425 GazeboTaskboardSlot1::Led::Led()
01426 : isOn(false)
01427 , index(-1)
01428 , color(eLedColor_Green)
01429 {}
01430 
01439 GazeboTaskboardSlot1::Led::Led(int index_, bool numPadLed_, LedColor color_, math::Pose pose_)
01440 : isOn(false)
01441 , index(index_)
01442 , numPadLed(numPadLed_)
01443 , color(color_)
01444 , pose(pose_)
01445 {}
01446 
01452 void GazeboTaskboardSlot1::Led::CreateModel(physics::WorldPtr world)
01453 {
01454     const std::string sdfTemplate =
01455         "<gazebo version ='1.0'>\
01456             <model name ='MODELNAME' static='1'>\
01457                 <origin pose='%1% %2% ZPOS %3% %4% %5%'/>\
01458                 <link name ='LINKNAME' kinematic='1'>\
01459                     <collision name='COLLISIONNAME'>\
01460                         <geometry>GEOMETRY</geometry>\
01461                     </collision>\
01462                     <visual name='VISUALNAME'>\
01463                         <geometry>GEOMETRY</geometry>\
01464                         <material script='MATERIAL'/>\
01465                     </visual>\
01466                     <inertial mass='0.5'> \
01467                         <inertia ixx='1' ixy='0.0' ixz='0.0' iyy='1' iyz='0.0' izz='1'/>\
01468                     </inertial>\
01469                 </link>\
01470             </model>\
01471         </gazebo>";
01472 
01473     // Figure out LED's material based on its color
01474     const std::string material = (color == eLedColor_Green) ? LED_MATERIAL_GREEN
01475                                                             : LED_MATERIAL_BLUE;
01476     // Create model and link names
01477     const std::string ledNameBase = boost::str(boost::format("taskboardLed%1%") % index);
01478     const std::string ledLinkNameBase = boost::str(boost::format("taskboardLedLink%1%") % index);
01479     const std::string ledCollisionNameBase = boost::str(boost::format("taskboardLedCollision%1%") % index);
01480     const std::string ledVisualNameBase = boost::str(boost::format("taskboardLedVisual%1%") % index);
01481 
01482     const std::string ledName = ledNameBase + "_ON";
01483     const std::string ledName2 = ledNameBase + "_OFF";
01484     const std::string ledLinkName = ledLinkNameBase + "_ON";
01485     const std::string ledLinkName2 = ledLinkNameBase + "_OFF";
01486     const std::string ledCollisionName = ledCollisionNameBase + "_ON";
01487     const std::string ledCollisionName2 = ledCollisionNameBase + "_OFF";
01488     const std::string ledVisualName = ledVisualNameBase + "_ON";
01489     const std::string ledVisualName2 = ledVisualNameBase + "_OFF";
01490 
01491     // Get LED model description depending on LED type
01492     std::string ledModel;
01493     ledModel = boost::str(boost::format("<cylinder length='%1%' radius='%2%'/>") 
01494                               % (numPadLed ? NUMPAD_LED_LENGTH : SIMPLE_LED_LENGTH)
01495                               % (numPadLed ? NUMPAD_LED_RADIUS : SIMPLE_LED_RADIUS));
01496 
01497     // Prepare template
01498     double roll = pose.rot.GetRoll();
01499     double pitch = pose.rot.GetPitch();
01500     double yaw = pose.rot.GetYaw();
01501     std::string xml = boost::str(boost::format(sdfTemplate) 
01502                                  % pose.pos.x % pose.pos.y 
01503                                  % roll % pitch % yaw);
01504     std::string xml2 = xml;
01505 
01506     // SDF xml for turned on LED
01507     boost::replace_all(xml, "MODELNAME", ledName); 
01508     boost::replace_all(xml, "ZPOS", boost::str(boost::format("%1%") % (pose.pos.z + LED_HIDE_OFFSET))); 
01509     boost::replace_all(xml, "LINKNAME", ledLinkName);
01510     boost::replace_all(xml, "COLLISIONNAME", ledCollisionName);
01511     boost::replace_all(xml, "VISUALNAME", ledVisualName);
01512     boost::replace_all(xml, "GEOMETRY", ledModel);
01513     boost::replace_all(xml, "MATERIAL", material);
01514 
01515     // SDF xml for turned off LED
01516     boost::replace_all(xml2, "MODELNAME", ledName2);
01517     boost::replace_all(xml2, "ZPOS", boost::str(boost::format("%1%") % (pose.pos.z + LED_HIDE_OFFSET2))); 
01518     boost::replace_all(xml2, "LINKNAME", ledLinkName2);
01519     boost::replace_all(xml2, "COLLISIONNAME", ledCollisionName2);
01520     boost::replace_all(xml2, "VISUALNAME", ledVisualName2);
01521     boost::replace_all(xml2, "GEOMETRY", ledModel);
01522     boost::replace_all(xml2, "MATERIAL", LED_MATERIAL_OFF);
01523 
01524     // Send request to physics engine to create LED models
01525     sdf::SDF ledSDF;
01526     ledSDF.SetFromString(xml);
01527     
01528     sdf::SDF ledSDF2;
01529     ledSDF2.SetFromString(xml2);
01530 
01531 #if ROS_VERSION_MINIMUM(1, 9, 0)
01532     // ROS Groovy or above
01533     world->InsertModelSDF(ledSDF);
01534     world->InsertModelSDF(ledSDF2);
01535 #else
01536     // ROS Fuerte
01537     world->InsertModel(ledSDF);
01538     world->InsertModel(ledSDF2);
01539 #endif
01540 
01541     // Initialize led structure.
01542     // NOTE: at this moment we don't initialize led.onModel, led.offModel:
01543     // they will be available only after physics engine does next step
01544     onModelName = ledName;
01545     onLinkName = ledLinkName;
01546     offModelName = ledName2;
01547     offLinkName = ledLinkName2;
01548 }
01549 
01555 void GazeboTaskboardSlot1::Led::SetupModel(physics::WorldPtr world)
01556 {
01557     if (!onModel)
01558     {
01559         onModel = world->GetModel(onModelName);
01560         if (!onModel)
01561         {
01562             ROS_FATAL("SetupModel: failed to get model %s", onModelName.c_str());
01563             return;
01564         }
01565         onModel->SetCollideMode("none");
01566 
01567         offModel = world->GetModel(offModelName);
01568         if (!offModel)
01569         {
01570             ROS_FATAL("SetupModel: failed to get model %s", offModelName.c_str());
01571             return;
01572         }
01573         offModel->SetCollideMode("none");
01574 
01575         math::Pose pose2 = offModel->GetRelativePose();
01576         pose2.pos.z -= LED_HIDE_OFFSET2;
01577         offModel->SetWorldPose(pose2);
01578     }
01579 }
01580 
01581 //----------------------------------------------------------------------------------------
01589 GazeboTaskboardSlot1::TaskboardLeds::TaskboardLeds(const math::Pose& modelPose)
01590 {
01591     struct LedsInfo {
01592         Led& led;
01593         bool numPadLed;
01594         LedColor color;
01595         math::Vector3 offset;
01596     } ledsInfo[] = {
01597         { powerSwitchLed,       false,  eLedColor_Green,  math::Vector3(0.3250, -0.4720, 1.4110) },
01598         { rockerSwitchUpLed,    false,  eLedColor_Green,  math::Vector3(0.3245, -0.4720, 1.3340) },
01599         { rockerSwitchDownLed,  false,  eLedColor_Blue,   math::Vector3(0.3245, -0.4720, 1.2834) },
01600         { numPadLeds[0],        true,   eLedColor_Blue,   math::Vector3(0.4496, -0.4755, 1.3358) },
01601         { numPadLeds[1],        true,   eLedColor_Green,  math::Vector3(0.4230, -0.4755, 1.3358) },
01602         { numPadLeds[2],        true,   eLedColor_Blue,   math::Vector3(0.3964, -0.4755, 1.3358) },
01603         { numPadLeds[3],        true,   eLedColor_Green,  math::Vector3(0.4496, -0.4755, 1.3095) },
01604         { numPadLeds[4],        true,   eLedColor_Blue,   math::Vector3(0.4230, -0.4755, 1.3095) },
01605         { numPadLeds[5],        true,   eLedColor_Green,  math::Vector3(0.3964, -0.4755, 1.3095) },
01606         { numPadLeds[6],        true,   eLedColor_Blue,   math::Vector3(0.4496, -0.4755, 1.2833) },
01607         { numPadLeds[7],        true,   eLedColor_Green,  math::Vector3(0.4230, -0.4755, 1.2833) },
01608         { numPadLeds[8],        true,   eLedColor_Blue,   math::Vector3(0.3964, -0.4755, 1.2833) },
01609         { toggleA03Led,         false,  eLedColor_Green,  math::Vector3(0.4449, -0.4720, 1.2365) },
01610         { toggleA04TopLed,      false,  eLedColor_Green,  math::Vector3(0.3812, -0.4720, 1.2365) },
01611         { toggleA04BottomLed,   false,  eLedColor_Blue,   math::Vector3(0.3812, -0.4720, 1.1855) },
01612         { toggleA05Led,         false,  eLedColor_Green,  math::Vector3(0.3185, -0.4720, 1.2365) }
01613     };
01614     const int ledsCount = sizeof(ledsInfo) / sizeof(ledsInfo[0]);
01615     const math::Quaternion rot = math::Quaternion(0.707, 0.707, 0, 0);
01616 
01617     for (int i = 0; i < ledsCount; i++)
01618     {
01619         const LedsInfo &info = ledsInfo[i];
01620         const math::Pose pose(modelPose.pos + modelPose.rot * info.offset, modelPose.rot * rot);
01621         info.led = Led(i, info.numPadLed, info.color, pose);
01622     }
01623 }
01624 
01633 void GazeboTaskboardSlot1::TaskboardLeds::CreateModels(physics::WorldPtr world)
01634 {
01635     for (int i = 0; i < NUM_PAD_BUTTONS_COUNT; i++)
01636     {
01637         numPadLeds[i].CreateModel(world);
01638     }
01639     powerSwitchLed.CreateModel(world);
01640     rockerSwitchUpLed.CreateModel(world);
01641     rockerSwitchDownLed.CreateModel(world);
01642     toggleA03Led.CreateModel(world);
01643     toggleA04TopLed.CreateModel(world);
01644     toggleA04BottomLed.CreateModel(world);
01645     toggleA05Led.CreateModel(world);
01646 }
01647 
01653 void GazeboTaskboardSlot1::TaskboardLeds::SetupModels(physics::WorldPtr world)
01654 {
01655     for (int i = 0; i < NUM_PAD_BUTTONS_COUNT; i++)
01656     {
01657         numPadLeds[i].SetupModel(world);
01658     }
01659     powerSwitchLed.SetupModel(world);
01660     rockerSwitchUpLed.SetupModel(world);
01661     rockerSwitchDownLed.SetupModel(world);
01662     toggleA03Led.SetupModel(world);
01663     toggleA04TopLed.SetupModel(world);
01664     toggleA04BottomLed.SetupModel(world);
01665     toggleA05Led.SetupModel(world);
01666 }


gazebo_taskboard
Author(s): TCSASSEMBLER
autogenerated on Mon Oct 6 2014 02:45:46