/*
* Copyright (c) 2016, Commonplace Robotics GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Willow Garage, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
// based on the RViz teleop panel tutorial, thank you!.
// First version: November 1st, 2014
// Current versin: Nov. 11th, 2016
//
// RViz plugin to operate the Mover4 or Mover6 robot arms
// Which robot to use is defined in the launch file:
// or
//
// Allows to push commands like connect or enable, and to jog the joints
// Displays the joint values
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "teleop_panel.h"
namespace cpr_rviz_plugin
{
TeleopPanel::TeleopPanel( QWidget* parent )
: rviz::Panel( parent )
{
ROS_INFO("CPR RViz Panel V01.5 Nov. 11th, 2016");
flagMover4 = true; // default choice
flagMover6 = false;
override_value = 40; // Value in percent
// whicht robot to operate?
// should be defined in the launch file / parameter server
//
std::string global_name, relative_name, default_param;
if (nh_.getParam("/robot_type", global_name)){
ROS_INFO(global_name.c_str());
if(global_name == "mover4"){
flagMover4 = true;
flagMover6 = false;
}else if(global_name == "mover6"){
flagMover4 = false;
flagMover6 = true;
}else{
flagMover4 = true;
flagMover6 = false;
}
}else{
ROS_INFO("no robot name found");
}
initGUI();
initROS();
output_timer->start( 100 ); // Start the timer.
}
//********************************************************
void TeleopPanel::initROS()
{
velocity_publisher_ = nh_.advertise( "CPRMoverJointVel", 1 );
velMsg.name.resize(6); // prepare the Message, both usable for Mover4 and Mover6
velMsg.velocity.resize(6);
velMsg.position.resize(6);
commands_publisher_ = nh_.advertise("CPRMoverCommands", 1);
subErrorState_ = nh_.subscribe("/CPRMoverErrorCodes", 1, &TeleopPanel::errorStateCallback, this);
subJointState_ = nh_.subscribe("/joint_states", 1, &TeleopPanel::jointStateCallback, this);
}
//*************************************************************************************
// receive joint state messages
void TeleopPanel::jointStateCallback(const sensor_msgs::JointState::ConstPtr& msg){
float r2d = 180.0 / 3.141;
labelJ0->setText(QString::number( (int)(r2d * msg->position[0]) ));
labelJ1->setText(QString::number( (int)(r2d * msg->position[1]) ));
labelJ2->setText(QString::number( (int)(r2d * msg->position[2]) ));
labelJ3->setText(QString::number( (int)(r2d * msg->position[3]) ));
if(flagMover6){
labelJ4->setText(QString::number( (int)(r2d * msg->position[4]) ));
labelJ5->setText(QString::number( (int)(r2d * msg->position[5]) ));
}
// The joint state messages are 6 (Mover4) resp. 8 (Mover6) joints long, 4 resp. 6 robot joints (Joint0 .. Joint5) and 2 gripper joints (Gripper1, Gripper2)
// the gripper joints are not shown here, but only used by RViz
}
//*************************************************************************************
// Here we receive the discrete commands like Connect, Reset, Enable
// the commands are forwarded to the interface class
void TeleopPanel::errorStateCallback(const std_msgs::String::ConstPtr& msg){
QString rec = msg->data.c_str();
labelStatus->setText(rec);
if(rec != lastError){
ROS_INFO("New ErrorState: %s ", msg->data.c_str()) ;
}
lastError = rec;
}
//********************************************************
void TeleopPanel::btPressedConnect(){
std_msgs::String msgCommands;
msgCommands.data = "Connect";
commands_publisher_.publish(msgCommands);
}
//********************************************************
void TeleopPanel::btPressedReset(){
std_msgs::String msgCommands;
msgCommands.data = "Reset";
commands_publisher_.publish(msgCommands);
}
//********************************************************
void TeleopPanel::btPressedEnable(){
std_msgs::String msgCommands;
msgCommands.data = "Enable";
commands_publisher_.publish(msgCommands);
}
//********************************************************
void TeleopPanel::btPressedGripperClose(){
std_msgs::String msgCommands;
msgCommands.data = "GripperClose";
commands_publisher_.publish(msgCommands);
}
//********************************************************
void TeleopPanel::btPressedGripperOpen(){
std_msgs::String msgCommands;
msgCommands.data = "GripperOpen";
commands_publisher_.publish(msgCommands);
}
//********************************************************
void TeleopPanel::btPressedOverrideMinus(){
std_msgs::String msgCommands;
override_value -= 10;
if(override_value <0)
override_value = 0;
QString cmd = "Override ";
cmd.append(QString::number(override_value));
msgCommands.data = cmd.toStdString().c_str();
commands_publisher_.publish(msgCommands);
labelOverride->setText(QString::number(override_value));
}
//********************************************************
void TeleopPanel::btPressedOverridePlus(){
std_msgs::String msgCommands;
override_value += 10;
if(override_value > 100)
override_value = 100;
QString cmd = "Override ";
cmd.append(QString::number(override_value));
msgCommands.data = cmd.toStdString().c_str();
commands_publisher_.publish(msgCommands);
labelOverride->setText(QString::number(override_value));
}
//********************************************************
// Publish the control velocities if ROS is not shutting down and the
// publisher is ready with a valid topic name.
void TeleopPanel::sendVel()
{
if( ros::ok() && velocity_publisher_ )
{
velMsg.header.stamp = ros::Time::now();
if(buttonJog0Plus->isDown()) jointVelocities[0] = 50.0;
else if(buttonJog0Minus->isDown()) jointVelocities[0] = -50.0;
else jointVelocities[0] = 0.0;
if(buttonJog1Plus->isDown()) jointVelocities[1] = 50.0;
else if(buttonJog1Minus->isDown()) jointVelocities[1] = -50.0;
else jointVelocities[1] = 0.0;
if(buttonJog2Plus->isDown()) jointVelocities[2] = 50.0;
else if(buttonJog2Minus->isDown()) jointVelocities[2] = -50.0;
else jointVelocities[2] = 0.0;
if(buttonJog3Plus->isDown()) jointVelocities[3] = 50.0;
else if(buttonJog3Minus->isDown()) jointVelocities[3] = -50.0;
else jointVelocities[3] = 0.0;
if(flagMover6){
if(buttonJog4Plus->isDown()) jointVelocities[4] = 50.0;
else if(buttonJog4Minus->isDown()) jointVelocities[4] = -50.0;
else jointVelocities[4] = 0.0;
if(buttonJog5Plus->isDown()) jointVelocities[5] = 50.0;
else if(buttonJog5Minus->isDown()) jointVelocities[5] = -50.0;
else jointVelocities[5] = 0.0;
}
for(int i=0; i<6; i++)
velMsg.velocity[i] = jointVelocities[i];
velocity_publisher_.publish( velMsg );
}
}
//********************************************************
// Initializes the QT user interface, buttons etc
void TeleopPanel::initGUI()
{
QHBoxLayout* hboxStatus = new QHBoxLayout; // Status fields on top
hboxStatus->addWidget( new QLabel( "Status: " ));
labelStatus = new QLabel;
labelStatus->setText("not connected");
hboxStatus->addWidget(labelStatus);
buttonConnect = new QPushButton; // buttons to connect. ..
buttonConnect -> setText("Connect");
buttonReset = new QPushButton;
buttonReset -> setText("Reset");
buttonEnable = new QPushButton;
buttonEnable -> setText("Enable");
labelOverride = new QLabel;
labelOverride->setText(QString::number(override_value));
buttonOverridePlus = new QPushButton;
buttonOverridePlus -> setText("Override Plus");
buttonOverrideMinus = new QPushButton;
buttonOverrideMinus -> setText("Override Minus");
buttonGripperOpen = new QPushButton;
buttonGripperOpen -> setText("Open Gripper");
buttonGripperClose = new QPushButton;
buttonGripperClose -> setText("Close Gripper");
buttonJog0Plus = new QPushButton; // Jog Buttons
buttonJog0Plus -> setText("J1 Plus");
buttonJog0Minus = new QPushButton;
buttonJog0Minus -> setText("J1 Minus");
labelJ0 = new QLabel;
labelJ0 -> setText("0.0");
buttonJog1Plus = new QPushButton;
buttonJog1Plus -> setText("J2 Plus");
buttonJog1Minus = new QPushButton;
buttonJog1Minus -> setText("J2 Minus");
labelJ1 = new QLabel;
labelJ1 -> setText("0.0");
buttonJog2Plus = new QPushButton;
buttonJog2Plus -> setText("J3 Plus");
buttonJog2Minus = new QPushButton;
buttonJog2Minus -> setText("J3 Minus");
labelJ2 = new QLabel;
labelJ2 -> setText("0.0");
buttonJog3Plus = new QPushButton;
buttonJog3Plus -> setText("J4 Plus");
buttonJog3Minus = new QPushButton;
buttonJog3Minus -> setText("J4 Minus");
labelJ3 = new QLabel;
labelJ3 -> setText("0.0");
if(flagMover6){ // if mover6 is defined add two joint buttons
buttonJog4Plus = new QPushButton;
buttonJog4Plus -> setText("J5 Plus");
buttonJog4Minus = new QPushButton;
buttonJog4Minus -> setText("J5 Minus");
labelJ4 = new QLabel;
labelJ4 -> setText("0.0");
buttonJog5Plus = new QPushButton;
buttonJog5Plus -> setText("J6 Plus");
buttonJog5Minus = new QPushButton;
buttonJog5Minus -> setText("J6 Minus");
labelJ5 = new QLabel;
labelJ5 -> setText("0.0");
}
QVBoxLayout* layout = new QVBoxLayout; // the main container
QHBoxLayout * hbox1 = new QHBoxLayout; // Compile a simple layout
hbox1->addWidget(buttonConnect);
hbox1->addWidget(buttonReset);
hbox1->addWidget(buttonEnable);
QHBoxLayout * hboxGripper = new QHBoxLayout;
hboxGripper->addWidget(buttonGripperClose);
hboxGripper->addWidget(buttonGripperOpen);
QHBoxLayout * hboxOverride = new QHBoxLayout;
hboxOverride->addWidget(buttonOverrideMinus);
hboxOverride->addWidget(labelOverride);
hboxOverride->addWidget(buttonOverridePlus);
layout->addLayout(hboxStatus);
layout->addLayout(hbox1);
layout->addLayout(hboxGripper);
layout->addLayout(hboxOverride);
QHBoxLayout * hboxJ0 = new QHBoxLayout;
hboxJ0->addWidget(buttonJog0Minus);
hboxJ0->addWidget(labelJ0);
hboxJ0->addWidget(buttonJog0Plus);
layout->addLayout(hboxJ0);
QHBoxLayout * hboxJ1 = new QHBoxLayout;
hboxJ1->addWidget(buttonJog1Minus);
hboxJ1->addWidget(labelJ1);
hboxJ1->addWidget(buttonJog1Plus);
layout->addLayout(hboxJ1);
QHBoxLayout * hboxJ2 = new QHBoxLayout;
hboxJ2->addWidget(buttonJog2Minus);
hboxJ2->addWidget(labelJ2);
hboxJ2->addWidget(buttonJog2Plus);
layout->addLayout(hboxJ2);
QHBoxLayout * hboxJ3 = new QHBoxLayout;
hboxJ3->addWidget(buttonJog3Minus);
hboxJ3->addWidget(labelJ3);
hboxJ3->addWidget(buttonJog3Plus);
layout->addLayout(hboxJ3);
if(flagMover6){ // if mover6 is defined add two joint buttons
QHBoxLayout * hboxJ4 = new QHBoxLayout;
hboxJ4->addWidget(buttonJog4Minus);
hboxJ4->addWidget(labelJ4);
hboxJ4->addWidget(buttonJog4Plus);
layout->addLayout(hboxJ4);
QHBoxLayout * hboxJ5 = new QHBoxLayout;
hboxJ5->addWidget(buttonJog5Minus);
hboxJ5->addWidget(labelJ5);
hboxJ5->addWidget(buttonJog5Plus);
layout->addLayout(hboxJ5);
}
setLayout( layout );
// Create a timer for sending the output.
output_timer = new QTimer( this );
connect( buttonConnect, SIGNAL( clicked() ), this, SLOT( btPressedConnect() ));
connect( buttonReset, SIGNAL( clicked() ), this, SLOT( btPressedReset() ));
connect( buttonEnable, SIGNAL( clicked() ), this, SLOT( btPressedEnable() ));
connect( buttonGripperClose, SIGNAL( clicked() ), this, SLOT( btPressedGripperClose() ));
connect( buttonGripperOpen, SIGNAL( clicked() ), this, SLOT( btPressedGripperOpen() ));
connect( buttonOverrideMinus, SIGNAL( clicked() ), this, SLOT( btPressedOverrideMinus() ));
connect( buttonOverridePlus, SIGNAL( clicked() ), this, SLOT( btPressedOverridePlus() ));
connect( output_timer, SIGNAL( timeout() ), this, SLOT( sendVel() ));
}
} // end namespace
// Tell pluginlib about this class.
#include
PLUGINLIB_EXPORT_CLASS(cpr_rviz_plugin::TeleopPanel,rviz::Panel )
// END_TUTORIAL