00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <nao_teleop/teleop_nao_joy.h>
00033 #include <naoqi_bridge_msgs/BodyPoseActionGoal.h>
00034 #include <naoqi_bridge_msgs/CmdVelService.h>
00035 #include <naoqi_bridge_msgs/JointTrajectoryAction.h>
00036
00037 using sensor_msgs::Joy;
00038
00039 namespace nao_teleop{
00040 TeleopNaoJoy::TeleopNaoJoy()
00041 : privateNh("~"), m_enabled(false),
00042 m_xAxis(3), m_yAxis(2), m_turnAxis(0), m_headYawAxis(4), m_headPitchAxis(5),
00043 m_crouchBtn(8), m_initPoseBtn(0), m_enableBtn(9), m_modifyHeadBtn(5),
00044 m_maxVx(1.0), m_maxVy(1.0), m_maxVw(0.5),
00045 m_maxHeadYaw(2.0943), m_maxHeadPitch(0.7853),
00046 m_bodyPoseTimeOut(5.0),
00047 m_inhibitCounter(0), m_previousJoystick_initialized(false),
00048 m_bodyPoseClient("body_pose", true),
00049 m_prevMotionZero(true), m_prevHeadZero(true)
00050 {
00051 privateNh.param("axis_x", m_xAxis, m_xAxis);
00052 privateNh.param("axis_y", m_yAxis, m_yAxis);
00053 privateNh.param("axis_turn", m_turnAxis, m_turnAxis);
00054 privateNh.param("axis_head_yaw", m_headYawAxis, m_headYawAxis);
00055 privateNh.param("axis_head_pitch", m_headPitchAxis, m_headPitchAxis);
00056 privateNh.param("btn_crouch", m_crouchBtn, m_crouchBtn);
00057 privateNh.param("btn_init_pose", m_initPoseBtn, m_initPoseBtn);
00058 privateNh.param("btn_enable_control", m_enableBtn, m_enableBtn);
00059 privateNh.param("btn_head_mod", m_modifyHeadBtn, m_modifyHeadBtn);
00060 privateNh.param("max_vx", m_maxVx, m_maxVx);
00061 privateNh.param("max_vy", m_maxVy, m_maxVy);
00062 privateNh.param("max_vw", m_maxVw, m_maxVw);
00063
00064 privateNh.param("max_head_yaw", m_maxHeadYaw, m_maxHeadYaw);
00065 privateNh.param("max_head_pitch", m_maxHeadPitch, m_maxHeadPitch);
00066
00067 m_motion.linear.x = m_motion.linear.y = m_motion.angular.z = 0.0;
00068 m_headAngles.joint_names.push_back("HeadYaw");
00069 m_headAngles.joint_names.push_back("HeadPitch");
00070 m_headAngles.joint_angles.resize(2, 0.0f);
00071 m_headAngles.relative = 0;
00072 m_headAngles.speed = 0.2;
00073
00074 m_movePub = nh.advertise<geometry_msgs::Twist>("cmd_vel", 10);
00075 m_headPub = nh.advertise<naoqi_bridge_msgs::JointAnglesWithSpeed>("joint_angles", 1);
00076 m_speechPub = nh.advertise<std_msgs::String>("speech", 1);
00077 m_inhibitWalkSrv = nh.advertiseService("inhibit_walk", &TeleopNaoJoy::inhibitWalk, this);
00078 m_uninhibitWalkSrv = nh.advertiseService("uninhibit_walk", &TeleopNaoJoy::uninhibitWalk, this);
00079 m_cmdVelClient = nh.serviceClient<naoqi_bridge_msgs::CmdVelService>("cmd_vel_srv");
00080 m_stiffnessDisableClient = nh.serviceClient<std_srvs::Empty>("body_stiffness/disable");
00081 m_stiffnessEnableClient = nh.serviceClient<std_srvs::Empty>("body_stiffness/enable");
00082
00083
00084 if (!m_bodyPoseClient.waitForServer(ros::Duration(3.0))){
00085 ROS_WARN_STREAM("Could not connect to \"body_pose\" action server, "
00086 << "there will be no body poses available on button presses.\n"
00087 << "Is the pose_manager node running?");
00088 }
00089
00090 std::cout << "starting button is set to " << m_enableBtn << std::endl;
00091 }
00092
00093
00094 ros::Subscriber TeleopNaoJoy::subscribeToJoystick() {
00095 return subscribeToJoystick(&TeleopNaoJoy::joyCallback, this);
00096 }
00097
00098 bool TeleopNaoJoy::callBodyPoseClient(const std::string& poseName){
00099 if (!m_bodyPoseClient.isServerConnected()){
00100 return false;
00101 }
00102
00103 naoqi_bridge_msgs::BodyPoseGoal goal;
00104 goal.pose_name = poseName;
00105 m_bodyPoseClient.sendGoalAndWait(goal, m_bodyPoseTimeOut);
00106 actionlib::SimpleClientGoalState state = m_bodyPoseClient.getState();
00107 if (state != actionlib::SimpleClientGoalState::SUCCEEDED){
00108 ROS_ERROR("Pose action \"%s\" did not succeed (%s): %s", goal.pose_name.c_str(), state.toString().c_str(), state.text_.c_str());
00109 return false;
00110 } else{
00111 ROS_INFO("Pose action \"%s\" succeeded", goal.pose_name.c_str());
00112 return true;
00113 }
00114
00115 }
00116
00117
00118 void TeleopNaoJoy::initializePreviousJoystick(const Joy::ConstPtr& joy) {
00119 if(!m_previousJoystick_initialized) {
00120
00121
00122
00123 Joy::Ptr pJoy(new Joy());
00124 pJoy->buttons.resize( joy->buttons.size(), 0);
00125 pJoy->axes.resize( joy->axes.size(), 0.0);
00126 m_previousJoystick = pJoy;
00127 m_previousJoystick_initialized = true;
00128 }
00129
00130 }
00131
00132
00138 void TeleopNaoJoy::joyCallback(const Joy::ConstPtr& joy){
00139 initializePreviousJoystick(joy);
00140
00141
00142
00143
00144 if (m_enabled && buttonTriggered(m_crouchBtn, joy) && m_bodyPoseClient.isServerConnected()){
00145 if (callBodyPoseClient("crouch")){
00146 std_srvs::Empty e;
00147 m_stiffnessDisableClient.call(e);
00148 }
00149 }
00150
00151 if (m_enabled && buttonTriggered(m_initPoseBtn, joy) && m_bodyPoseClient.isServerConnected()){
00152 callBodyPoseClient("init");
00153 }
00154
00155 if (buttonTriggered(m_enableBtn, joy)){
00156 std_msgs::String string;
00157 if (m_enabled){
00158 m_enabled = false;
00159 string.data = "Gamepad control disabled";
00160
00161 } else{
00162 m_enabled = true;
00163 string.data = "Gamepad control enabled";
00164 std_srvs::Empty e;
00165 m_stiffnessEnableClient.call(e);
00166 }
00167 m_speechPub.publish(string);
00168 ROS_INFO("%s", (string.data).c_str());
00169
00170 }
00171
00172
00173
00174
00175 if (!axisValid(m_xAxis, joy) || !axisValid(m_yAxis, joy) || !axisValid(m_turnAxis, joy)){
00176 m_motion.linear.x = m_motion.linear.y = m_motion.angular.z = 0.0f;
00177 m_headAngles.joint_angles[0] = m_headAngles.joint_angles[1] = 0.0f;
00178 ROS_WARN("Joystick message too short for Move or Turn axis!\n");
00179 } else{
00180 if (buttonPressed(m_modifyHeadBtn, joy)){
00181
00182 m_headAngles.header.stamp = ros::Time::now();
00183 m_headAngles.relative = 1;
00184 m_headAngles.joint_angles[0] = joy->axes[m_turnAxis];
00185 m_headAngles.joint_angles[1] = joy->axes[m_xAxis];
00186
00187 } else {
00188
00189 m_headAngles.joint_angles[0] = m_headAngles.joint_angles[1] = 0.0f;
00190
00191 m_motion.linear.x = m_maxVx * std::max(std::min(joy->axes[m_xAxis], 1.0f), -1.0f);
00192 m_motion.linear.y = m_maxVy * std::max(std::min(joy->axes[m_yAxis], 1.0f), -1.0f);
00193 m_motion.angular.z = m_maxVw * std::max(std::min(joy->axes[m_turnAxis], 1.0f), -1.0f);
00194
00195 }
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 setPreviousJoystick(joy);
00212
00213 }
00214
00222 bool TeleopNaoJoy::buttonPressed(int button, const Joy::ConstPtr& joy) const{
00223 return (button >= 0 && unsigned(button) < joy->buttons.size() && joy->buttons[button] == 1);
00224 }
00225
00233 bool TeleopNaoJoy::buttonTriggered(int button, const Joy::ConstPtr& joy) const{
00234 return (buttonPressed(button, joy) && buttonChanged(button, joy, m_previousJoystick));
00235 }
00236
00237
00238
00248 bool TeleopNaoJoy::buttonChanged(int button, const Joy::ConstPtr& joy, const Joy::ConstPtr& prevJoy) const{
00249 return (unsigned(button) < joy->buttons.size() && joy->buttons[button] != prevJoy->buttons[button] );
00250 }
00251
00259 bool TeleopNaoJoy::axisValid(int axis, const Joy::ConstPtr& joy) const{
00260 return (axis >= 0 && unsigned(axis) < joy->buttons.size());
00261 }
00262
00266 void TeleopNaoJoy::pubMsg(){
00267 if (m_enabled && m_inhibitCounter == 0)
00268 {
00269 const bool headZero = m_headAngles.joint_angles[0] == 0.0f && m_headAngles.joint_angles[1] == 0.0f;
00270
00271
00272
00273 if (!headZero || !m_prevHeadZero)
00274 {
00275 m_headPub.publish(m_headAngles);
00276 std::cout << "going to publish head angles" << std::endl;
00277 }
00278 m_prevHeadZero = headZero;
00279
00280 const bool motionZero = m_motion.linear.x == 0.0f && m_motion.linear.y == 0.0f && m_motion.angular.z == 0.0f;
00281 if (!motionZero || !m_prevMotionZero)
00282 {
00283 m_movePub.publish(m_motion);
00284 std::cout << "going to publish motion commands" << std::endl;
00285 }
00286 m_prevMotionZero = motionZero;
00287
00288 }
00289 }
00290
00303 bool TeleopNaoJoy::inhibitWalk(std_srvs::EmptyRequest& , std_srvs::EmptyResponse& res) {
00304 if(m_inhibitCounter == 0) {
00305
00306 m_motion.linear.x = 0.0;
00307 m_motion.linear.y = 0.0;
00308 m_motion.linear.z = 0.0;
00309 m_motion.angular.x = 0.0;
00310 m_motion.angular.y = 0.0;
00311 m_motion.angular.z = 0.0;
00312 naoqi_bridge_msgs::CmdVelService service_call;
00313 service_call.request.twist = m_motion;
00314 m_cmdVelClient.call(service_call);
00315 }
00316 m_inhibitCounter++;
00317 ROS_DEBUG("Inhibit counter: %d", m_inhibitCounter);
00318 return true;
00319 }
00320
00331 bool TeleopNaoJoy::uninhibitWalk(std_srvs::EmptyRequest &req, std_srvs::EmptyResponse& res) {
00332 if(m_inhibitCounter > 0) {
00333 m_inhibitCounter--;
00334 ROS_DEBUG("Inhibit counter: %d", m_inhibitCounter);
00335 } else {
00336 m_inhibitCounter = 0;
00337 ROS_WARN("/uninhibit_walk called more times than /inhibit_walk - ignoring");
00338 }
00339 return true;
00340 }
00341 }
00342