ArmWidget.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
00004 ** All rights reserved.
00005 ** Contact: Nokia Corporation (qt-info@nokia.com)
00006 **
00007 ** This file is part of the examples of the Qt Toolkit.
00008 **
00009 ** $QT_BEGIN_LICENSE:BSD$
00010 ** You may use this file under the terms of the BSD license as follows:
00011 **
00012 ** "Redistribution and use in source and binary forms, with or without
00013 ** modification, are permitted provided that the following conditions are
00014 ** met:
00015 **   * Redistributions of source code must retain the above copyright
00016 **     notice, this list of conditions and the following disclaimer.
00017 **   * Redistributions in binary form must reproduce the above copyright
00018 **     notice, this list of conditions and the following disclaimer in
00019 **     the documentation and/or other materials provided with the
00020 **     distribution.
00021 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
00022 **     the names of its contributors may be used to endorse or promote
00023 **     products derived from this software without specific prior written
00024 **     permission.
00025 **
00026 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00030 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
00037 ** $QT_END_LICENSE$
00038 **
00039 ****************************************************************************/
00040 
00041 #include "ArmWidget.h"
00042 
00043 #include <math.h>
00044 #include <QtGui>
00045 #include "corobot.h"
00046 
00047 double inchesToMeters(const double inches)
00048 //convert from inches to meters
00049 {
00050     return inches * 2.54 / 100.0;
00051 }
00052 
00053 double PixeltoMeter(const double pixel)
00054 //convert from pixel to meter
00055 {
00056     return (pixel / PIXELS_PER_METER);
00057 }
00058 
00059 double MetersToPixels(const double meters)
00060 //convert from meters to pixels
00061 {
00062     return (meters * PIXELS_PER_METER);
00063 }
00064 
00065 //Shoulder and Elbow width constant for different arms.
00066 //Old corobot Arm
00067 const double COROBOT_ARM_SHOULDER_SEGMENT_METERS = inchesToMeters(6.25);
00068 const double COROBOT_ARM_ELBOW_SEGMENT_METERS = inchesToMeters(8);
00069 
00070 //PhantomX Pincher
00071 const double PINCHER_ARM_SHOULDER_SEGMENT_METERS = inchesToMeters(6.25);
00072 const double PINCHER_ARM_ELBOW_SEGMENT_METERS = inchesToMeters(8);
00073 
00074 //PhantomX Reactor
00075 const double REACTOR_ARM_SHOULDER_SEGMENT_METERS = inchesToMeters(6.25);
00076 const double REACTOR_ARM_ELBOW_SEGMENT_METERS = inchesToMeters(8);
00077 
00078 //Lynxmotion al5a
00079 const double AL5A_ARM_SHOULDER_SEGMENT_METERS = inchesToMeters(3.75);
00080 const double AL5A_ARM_ELBOW_SEGMENT_METERS = inchesToMeters(7.62);
00081 
00082 
00083 double armShoulderSegmentMeters=COROBOT_ARM_SHOULDER_SEGMENT_METERS;
00084 double armElbowSegmentMeters=COROBOT_ARM_ELBOW_SEGMENT_METERS;
00085 
00086 //Constant related to the drawings
00087 const int ARM_X = 120;
00088 const int ARM_Y = 120;
00089 const int ARM_CENTER_X = ARM_X / 2;
00090 const int ARM_BODY_TOP = ARM_X * 7 / 10;
00091 const int ARM_SHOULDER_X = ARM_CENTER_X - ARM_X / 7;
00092 
00093 ArmWidget::ArmWidget(QWidget *parent)
00094     : QGraphicsView(parent), timerId(0)
00095 {
00096 
00097     QGraphicsScene *scene = new QGraphicsScene(this);
00098     scene->setItemIndexMethod(QGraphicsScene::NoIndex);
00099     scene->setSceneRect(0, 00, 210, 110);
00100 
00101         shoulder = true;
00102         elbow = true;
00103     setScene(scene);
00104     setCacheMode(CacheBackground);
00105     setViewportUpdateMode(BoundingRectViewportUpdate);
00106     setRenderHint(QPainter::Antialiasing);
00107     setTransformationAnchor(AnchorUnderMouse);
00108     scale(qreal(1), qreal(1));
00109     setMinimumSize(210, 110);
00110     setWindowTitle(tr("Elastic Nodes"));
00111 
00112     joint *joint1 = new joint(this);
00113     joint *joint2 = new joint(this);
00114     joint *joint3 = new joint(this);
00115 
00116 
00117     scene->addItem(joint1);
00118     scene->addItem(joint2);
00119     scene->addItem(joint3);
00120 
00121     joint3->setFlag(joint3->ItemIsMovable);
00122 
00123     double x = armShoulderSegmentMeters;
00124     double y = armElbowSegmentMeters;
00125 
00126     joint1->setPos(this->sceneRect().left()+ARM_SHOULDER_X+5, this->sceneRect().bottom()-ARM_Y+ARM_BODY_TOP+5);
00127     joint2->setPos(this->sceneRect().left()+ARM_SHOULDER_X+5, -MetersToPixels(y)-ARM_Y+ARM_BODY_TOP+5+this->sceneRect().bottom());
00128 
00129 
00130     joint3->setPos(MetersToPixels(x)+this->sceneRect().left()+ARM_SHOULDER_X+5,
00131                    -MetersToPixels(y)-ARM_Y+ARM_BODY_TOP+5+this->sceneRect().bottom());
00132     end_effector = QPointF(0,0);
00133 
00134     QGraphicsLineItem *line = new QGraphicsLineItem(joint1->pos().x()-5,joint1->pos().y()-5,joint2->pos().x()-5,joint2->pos().y()-5);
00135     scene->addItem(line);
00136     QGraphicsLineItem *line2 = new QGraphicsLineItem(joint2->pos().x()-5,joint2->pos().y()-5,joint3->pos().x()-5,joint3->pos().y()-5);
00137     scene->addItem(line2);
00138 
00139  }
00147 bool doArmIK(const double x, const double y, double& theta1, double& theta2)
00148 //compute the inverse kinematics for the arm
00149 {
00150     const double LOWER_LINK_LEN = armShoulderSegmentMeters;
00151     const double UPPER_LINK_LEN = armElbowSegmentMeters;
00152     const double LOWER_SQUARED = armShoulderSegmentMeters * armShoulderSegmentMeters;
00153     const double UPPER_SQUARED = armElbowSegmentMeters * armElbowSegmentMeters;
00154 
00155     double c2;                  // cosine of theta2
00156 
00157         c2 = ((x * x) + (y * y) - LOWER_SQUARED - UPPER_SQUARED) /
00158             (2 * LOWER_LINK_LEN * UPPER_LINK_LEN);
00159         if ((c2 < -1.0) || (c2 > 1.0))
00160         {
00161             return false;
00162         }
00163 
00164         double magS2;               // magnitude of sine of theta2 (could be + or - this).
00165 
00166         magS2 = sqrt(1 - c2 * c2);
00167         double posS2 = magS2;
00168         double negS2 = -magS2;
00169         double posTheta2,
00170             negTheta2;
00171 
00172         posTheta2 = atan2(posS2, c2);
00173         negTheta2 = atan2(negS2, c2);
00174 
00175         double posS1;               // sine of theta1
00176 
00177         posS1 =
00178             ((LOWER_LINK_LEN + UPPER_LINK_LEN * c2) * y -
00179              (UPPER_LINK_LEN * posS2 * x)) / (x * x + y * y);
00180         double posC1;
00181 
00182         posC1 =
00183             ((LOWER_LINK_LEN + UPPER_LINK_LEN * c2) * x +
00184              (UPPER_LINK_LEN * posS2 * y)) / (x * x + y * y);
00185         double posTheta1;
00186 
00187         posTheta1 = atan2(posS1, posC1);
00188 
00189         double negS1;               // sine of theta1
00190 
00191         negS1 =
00192             ((LOWER_LINK_LEN + UPPER_LINK_LEN * c2) * y -
00193              (UPPER_LINK_LEN * negS2 * x)) / (x * x + y * y);
00194         double negC1;
00195 
00196         negC1 =
00197             ((LOWER_LINK_LEN + UPPER_LINK_LEN * c2) * x +
00198              (UPPER_LINK_LEN * negS2 * y)) / (x * x + y * y);
00199         double negTheta1;
00200 
00201         negTheta1 = atan2(negS1, negC1);
00202 
00203         // bounds checking - make sure the joints are within ranges.
00204         if ((posTheta1 <= M_PI * 0.75) && (posTheta1 >= 0.0) && (posTheta2 <= 0.0))
00205         {
00206             theta1 = posTheta1;
00207             theta2 = posTheta2;
00208             return true;
00209         }
00210 
00211         // bounds checking - make sure the joints are within ranges.
00212         if ((negTheta1 <= M_PI * 0.75) && (negTheta1 >= 0.0) && (negTheta2 <= 0.0))
00213         {
00214             theta1 = negTheta1;
00215             theta2 = negTheta2;
00216             return true;
00217         }
00218         return false;
00219 }
00220 
00221 void ArmWidget::Corobot(bool value)
00222 // value is true of a Corobot, false if is an Explorer, Explorer doesn't have an arm therefore the Widget is white
00223 {
00224         foreach (QGraphicsItem *item, scene()->items()) {
00225             if(value == true){
00226                 item->show();
00227             }
00228             else{
00229                 item->hide();
00230             }
00231         }
00232 }
00233 
00234 void ArmWidget::setModel(bool arm_al5a,bool arm_pincher,bool arm_reactor,bool arm_old_corobot)
00235 // set the number of Degree of Freedom of the arm and therefore the dimensions and if the rotation of the arm should be controled or not
00236 {
00237     if (arm_old_corobot)
00238     {
00239         armShoulderSegmentMeters= COROBOT_ARM_SHOULDER_SEGMENT_METERS;
00240         armElbowSegmentMeters= COROBOT_ARM_ELBOW_SEGMENT_METERS;
00241         arm_type = OldCorobot;
00242     }
00243     else if (arm_pincher)
00244     {
00245         armShoulderSegmentMeters= PINCHER_ARM_SHOULDER_SEGMENT_METERS;
00246         armElbowSegmentMeters= PINCHER_ARM_ELBOW_SEGMENT_METERS;
00247         arm_type = Pincher;
00248     }
00249     else if (arm_reactor)
00250     {
00251         armShoulderSegmentMeters= REACTOR_ARM_SHOULDER_SEGMENT_METERS;
00252         armElbowSegmentMeters= REACTOR_ARM_ELBOW_SEGMENT_METERS;
00253         arm_type = Reactor;
00254     }
00255     else if (arm_al5a)
00256     {
00257         armShoulderSegmentMeters= AL5A_ARM_SHOULDER_SEGMENT_METERS;
00258         armElbowSegmentMeters= AL5A_ARM_ELBOW_SEGMENT_METERS;
00259         arm_type = Al5a;
00260     }
00261 
00262     printf("ARM_LENGTH %d, %d", armShoulderSegmentMeters, armShoulderSegmentMeters);
00263 
00264     QGraphicsScene *scene = this->scene();
00265 
00266     joint* joint1 = (joint*)scene->items().at(0);
00267     joint* joint2 = (joint*)scene->items().at(1);
00268     joint* joint3 = (joint*)scene->items().at(2);
00269 
00270     double x = armShoulderSegmentMeters;
00271     double y = armElbowSegmentMeters;
00272 
00273     joint3->setPos(MetersToPixels(x)+this->sceneRect().left()+ARM_SHOULDER_X+5,-MetersToPixels(y)-ARM_Y+ARM_BODY_TOP+5+this->sceneRect().bottom());
00274     joint2->setPos(this->sceneRect().left()+ARM_SHOULDER_X+5, -MetersToPixels(y)-ARM_Y+ARM_BODY_TOP+5+this->sceneRect().bottom());
00275 
00276     ((QGraphicsLineItem*)(scene->items().at(3)))->setLine(joint1->pos().x()-5,joint1->pos().y()-5,joint2->pos().x()-5,joint2->pos().y()-5);
00277     ((QGraphicsLineItem*)(scene->items().at(4)))->setLine(joint2->pos().x()-5,joint2->pos().y()-5,joint3->pos().x()-5,joint3->pos().y()-5);
00278 
00279 
00280 }
00281 
00282 
00283 void ArmWidget::itemMoved()
00284 //timer starts if a movement is detected
00285 {
00286     if (!timerId)
00287         timerId = startTimer(1000 / 25);
00288 }
00289 
00290 void ArmWidget::shoulder_degree(bool value)
00291 //if value is true, the signal theta1 will be emited in degrees
00292 {
00293     shoulder = value;
00294 
00295 }
00296 
00297 void ArmWidget::elbow_degree(bool value)
00298 //if value is true, the signal theta2 will be emited in degrees
00299 {
00300     elbow = value;
00301 
00302 }
00303 
00304 void ArmWidget::moveArmUp()
00305 //moves the arm up
00306 {
00307     this->scene()->items().at(2)->setPos(end_effector + QPointF(0,-5));
00308 }
00309 
00310 void ArmWidget::moveArmDown()
00311 //moves the arm down
00312 {
00313     this->scene()->items().at(2)->setPos(end_effector + QPointF(0,5));
00314 }
00315 
00316 void ArmWidget::moveArmLeft()
00317 //moves the arm toward the robot
00318 {
00319     this->scene()->items().at(2)->setPos(end_effector + QPointF(-5,0));
00320 }
00321 
00322 void ArmWidget::moveArmRight()
00323 //moves the arm far from the robot
00324 {
00325     this->scene()->items().at(2)->setPos(end_effector + QPointF(5,0));
00326 }
00327 
00328 void ArmWidget::received_pos(double x, double y)
00329 //set the position ofthe arm. x,y if he position in meters
00330 {
00331 
00332     QList<joint *> joints;
00333         foreach (QGraphicsItem *item, scene()->items()) {
00334             if (joint *j = qgraphicsitem_cast<joint *>(item))
00335                 joints << j;
00336         }
00337 
00338     joints.at(2)->setPos(MetersToPixels(x)+this->sceneRect().left()+ARM_SHOULDER_X+5,
00339                 -MetersToPixels(y)-ARM_Y+ARM_BODY_TOP+5+this->sceneRect().bottom());
00340 
00341 
00342 }
00343 
00344 
00345 void ArmWidget::timerEvent(QTimerEvent *event)
00346 //execute this function when the timer is up.
00347  {
00348      Q_UNUSED(event);
00349 
00350      QList<joint *> joints;
00351          foreach (QGraphicsItem *item, scene()->items()) {
00352              if (joint *j = qgraphicsitem_cast<joint *>(item))
00353                  joints << j;
00354          }
00355 
00356        //  foreach (joint *j, joints)
00357          //   j->calculateForces();
00358 /*
00359          bool itemsMoved = false;
00360          foreach (joint *j, joints) {
00361              if (j->advance())
00362                  itemsMoved = true;
00363          }
00364 
00365          if (!itemsMoved) {
00366              killTimer(timerId);
00367        //      timerId = 0;
00368          }
00369        else{*/
00370 
00371          const double LINK_1_LENGTH = MetersToPixels(armShoulderSegmentMeters);
00372          const double LINK_2_LENGTH = MetersToPixels(armElbowSegmentMeters);
00373 
00374          float x,y;
00375 
00376              x = PixeltoMeter(joints.at(2)->pos().x()-5-(this->sceneRect().left()+ARM_SHOULDER_X));
00377              y = PixeltoMeter(this->sceneRect().bottom()-ARM_Y+ARM_BODY_TOP-joints.at(2)->pos().y()+5);
00378 
00379          if(joints.at(2)->x()!=end_effector.x() || joints.at(2)->y()!=end_effector.y()){
00380              double t1,t2;
00381              if(doArmIK(x,y, t1, t2)){
00382 
00383             //emit posarm(x,y);
00384 
00385             double x = LINK_1_LENGTH * cos(t1);
00386             double y = LINK_1_LENGTH * sin(t1);
00387 
00388             int elbowX = ARM_SHOULDER_X + (int)x;
00389             int elbowY = -ARM_Y+ARM_BODY_TOP - (int)y;
00390 
00391             joints.at(1)->setPos(this->sceneRect().left()+elbowX+5, this->sceneRect().bottom()+elbowY+5);
00392 
00393 
00394             if(shoulder)
00395                 emit theta1(t1/M_PI*180);
00396             else
00397                 emit theta1(t1);
00398             if(elbow)
00399                 emit theta2(t2/M_PI*180+180);
00400             else
00401                 emit theta2(t2 + M_PI);
00402 
00403             if (arm_type == Al5a)
00404             {
00405                 emit shoulderAngle_rad(180 - t1);
00406                 emit elbowAngle_rad(180 + t2);
00407             }
00408             else
00409             {
00410                 emit shoulderAngle_rad(t1);
00411                 emit elbowAngle_rad(-t2);
00412             }
00413                  QList<QGraphicsLineItem *> lines;
00414                      foreach (QGraphicsItem *item, scene()->items()) {
00415                          if (QGraphicsLineItem *l = qgraphicsitem_cast<QGraphicsLineItem *>(item))
00416                              lines << l;
00417                      }
00418 
00419                          lines.at(0)->setLine(joints.at(0)->pos().x()-5,joints.at(0)->pos().y()-5,joints.at(1)->pos().x()-5,joints.at(1)->pos().y()-5);
00420                          lines.at(1)->setLine(joints.at(1)->pos().x()-5,joints.at(1)->pos().y()-5,joints.at(2)->pos().x()-5,joints.at(2)->pos().y()-5);
00421 
00422                  end_effector = joints.at(2)->pos();
00423                  }
00424              else{
00425                 joints.at(2)->setPos(end_effector);
00426              }
00427          }
00428 
00429 
00430 
00431  }
00432 
00433 
00434 
00435 
00436  void ArmWidget::drawBackground(QPainter *painter, const QRectF &rect)
00437  // draw the widget background
00438  {
00439      Q_UNUSED(rect);
00440 
00441      // Shadow
00442      QRectF sceneRect = this->sceneRect();
00443      QRectF rightShadow(sceneRect.right(), sceneRect.top() + 5, 5, sceneRect.height());
00444      QRectF bottomShadow(sceneRect.left() + 5, sceneRect.bottom(), sceneRect.width(), 5);
00445      if (rightShadow.intersects(rect) || rightShadow.contains(rect))
00446          painter->fillRect(rightShadow, Qt::darkGray);
00447      if (bottomShadow.intersects(rect) || bottomShadow.contains(rect))
00448          painter->fillRect(bottomShadow, Qt::darkGray);
00449 
00450 
00451      // Fill
00452      QLinearGradient gradient(sceneRect.topLeft(), sceneRect.bottomRight());
00453      gradient.setColorAt(0, Qt::white);
00454      gradient.setColorAt(1, Qt::lightGray);
00455      painter->fillRect(rect.intersect(sceneRect), gradient);
00456      painter->setBrush(Qt::NoBrush);
00457      painter->drawRect(sceneRect);
00458 
00459      //Robot
00460       QRectF robot(sceneRect.left(), sceneRect.bottom()-ARM_Y+ARM_BODY_TOP, ARM_X / 2, ARM_Y - ARM_BODY_TOP);
00461       painter->fillRect(robot, Qt::gray);
00462       painter->setBrush(Qt::NoBrush);
00463       painter->drawRect(robot);
00464 
00465 
00466      // Text
00467      QRectF textRect(sceneRect.left() + 4, sceneRect.top() + 4,
00468                      sceneRect.width() - 4, sceneRect.height() - 4);
00469 
00470      QFont font = painter->font();
00471      font.setBold(true);
00472      font.setPointSize(14);
00473      painter->setFont(font);
00474      painter->setPen(Qt::lightGray);
00475      painter->setPen(Qt::black);
00476  }
00477 
00478  void ArmWidget::scaleView(qreal scaleFactor)
00479  //scale the view
00480  {
00481      qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
00482      if (factor < 0.07 || factor > 100)
00483          return;
00484 
00485      scale(scaleFactor, scaleFactor);
00486  }
00487 
00488 //bool arm_reset()
00489 //{
00490 //}


corobot_teleop
Author(s): Morgan Cormier/Gang Li/mcormier@coroware.com
autogenerated on Tue Jan 7 2014 11:39:41