00001 #include <Ice/Ice.h> 00002 #include "Ice/Scorbot.ice.H" 00003 #include "Image/Point2D.H" 00004 #include "Image/DrawOps.H" 00005 #include "Image/MathOps.H" 00006 #include "Image/ColorOps.H" 00007 #include <signal.h> 00008 #include "Component/ModelManager.H" 00009 #include "Raster/Raster.H" 00010 #include "Util/MathFunctions.H" 00011 #include "Util/Types.H" 00012 #include "Util/log.H" 00013 #include "Media/FrameSeries.H" 00014 #include "Transport/FrameInfo.H" 00015 #include "Raster/GenericFrame.H" 00016 #include "GUI/XWinManaged.H" 00017 #include "GUI/ImageDisplayStream.H" 00018 #include "GUI/PrefsWindow.H" 00019 #include "GUI/DebugWin.H" 00020 00021 00022 Robots::ScorbotIcePrx scorbot; 00023 00024 // ###################################################################### 00025 void cleanupAndExit() 00026 { 00027 std::cerr << 00028 std::endl << "*** EXITING - STOPPING SCORBOT ***" << std::endl; 00029 scorbot->stopAllMotors(); 00030 sleep(1); 00031 exit(0); 00032 } 00033 00034 // ###################################################################### 00035 void terminate(int s) 00036 { 00037 cleanupAndExit(); 00038 } 00039 00040 int getKey(nub::ref<OutputFrameSeries> &ofs) 00041 { 00042 const nub::soft_ref<ImageDisplayStream> ids = 00043 ofs->findFrameDestType<ImageDisplayStream>(); 00044 00045 const rutz::shared_ptr<XWinManaged> uiwin = 00046 ids.is_valid() 00047 ? ids->getWindow("Output") 00048 : rutz::shared_ptr<XWinManaged>(); 00049 return uiwin->getLastKeyPress(); 00050 } 00051 00052 00053 00054 Point2D<double> getTargetPos() 00055 { 00056 double x, y; 00057 00058 std::cout << "----------------------------------------" << std::endl; 00059 std::cout << "Enter a target point in mm: (x y): "; 00060 std::cin >> x >> y; 00061 return Point2D<double>(x,y); 00062 } 00063 00064 // ###################################################################### 00065 // Point the camera at a 2D position on the board at a given angle (camera to board angle, in radians), with the camera 00066 // 'camDist' mm away from the target, and the linear slide set xOffset mm to the side of the target. 00067 Robots::ArmPos calcArmPos(Point2D<double> targetPos, double xOffset, double angle, double camDist) 00068 { 00069 //////////////////////////////////////////////////////////////////////// 00070 // CONSTANTS 00071 double armSlideXoffset = 0.0; // The x-offset from origin to the arm's home slide position 00072 double armSlideYoffset = 0.0; // The y-offset from the origin to the arm's slide traversal axis (this should be a neg. number) 00073 double armZoffset = 0.0; // The distance from the arm's origin to the table surface 00074 00075 //These offsets assume that when the wrist is pointed straight out, the x-axis points through the tip of the gripper, 00076 //and the y-axis points towards the ceiling. 00077 double camToWristX = 0.0; // The distance from the cam center to the wrist along the x-axis if the wrist is straight out 00078 double camToWristY = 0.0; // The distance from the cam center to the wrist along the y-axis if the wrist is straight out 00079 // 00080 //////////////////////////////////////////////////////////////////////// 00081 00082 double targetX = targetPos.i; 00083 double targetY = targetPos.j; 00084 00085 // Distance from the arm center to the target in the x-y (tabletop) plane 00086 double d_t = sqrt(pow(xOffset,2) + pow(targetY+armSlideYoffset,2)); 00087 00088 // Relative position of the camera center from the target 00089 double x_hat_cam = cos(angle)*camDist; 00090 double y_hat_cam = sin(angle)*camDist; 00091 00092 // Position of the camera relative to the robot origin. 00093 // This position is in an artificial coord. system created by assuming the 00094 // arm is already at it's proper slide offset, and the base has been rotated 00095 // to the target 00096 double x_cam = d_t - x_hat_cam; 00097 double y_cam = y_hat_cam - armZoffset; 00098 00099 // Rotate the camera-to-wrist offsets according to the desired angle 00100 double cam_x_off = camToWristX * cos(-angle) - camToWristY*sin(-angle); 00101 double cam_y_off = camToWristX * sin(-angle) + camToWristY*cos(-angle); 00102 00103 // Absolute wrist position (in our artificial coord. system) 00104 double wrist_x = x_cam + cam_x_off; 00105 double wrist_y = y_cam + cam_y_off; 00106 00107 // Absolute global slider position 00108 double sliderPos = targetX + xOffset - armSlideXoffset; 00109 00110 // Base angle 00111 double baseAngle = atan2(xOffset, targetY+armSlideYoffset); 00112 00113 // Get the inverse kinematics from the scorbot 00114 Robots::ArmPos ik = scorbot->getIK(0, wrist_x, wrist_y); 00115 00116 // Force the slide position and base angle 00117 ik.ex1 = scorbot->mm2enc(sliderPos); 00118 ik.base = scorbot->ang2enc(baseAngle); 00119 00120 std::cout << "---IK---" << std::endl; 00121 std::cout << "base: " << ik.base << std::endl; 00122 std::cout << "shoulder: " << ik.shoulder << std::endl; 00123 std::cout << "elbow: " << ik.elbow << std::endl; 00124 std::cout << "wrist1: " << ik.wrist1 << std::endl; 00125 std::cout << "wrist2: " << ik.wrist2 << std::endl; 00126 std::cout << "ex1: " << ik.ex1 << std::endl; 00127 std::cout << "--------" << std::endl; 00128 00129 return ik; 00130 } 00131 00132 00133 00134 std::vector<Robots::ArmPos> getArmPositions() 00135 { 00136 00137 std::vector<Robots::ArmPos> positions; 00138 Robots::ArmPos armpos; 00139 armpos.base = 0; 00140 armpos.shoulder = 0; 00141 armpos.elbow = 0; 00142 armpos.wrist1 = 0; 00143 armpos.wrist2 = 0; 00144 armpos.ex1 = 0; 00145 armpos.ex2 = 0; 00146 armpos.duration = 500; 00147 00148 armpos.base=-823; armpos.shoulder=1594; armpos.elbow=-26751; armpos.wrist1=224; armpos.wrist2=-125; armpos.gripper=0; armpos.ex1=49; 00149 positions.push_back(armpos); 00150 armpos.base=-707; armpos.shoulder=1292; armpos.elbow=-27673; armpos.wrist1=1143; armpos.wrist2=-918; armpos.gripper=0; armpos.ex1=49; 00151 positions.push_back(armpos); 00152 00153 00154 00155 /* 00156 //armpos.base=-4253; armpos.shoulder=-1204; armpos.elbow=413; armpos.wrist1=618; armpos.wrist2=-937; armpos.gripper=0; armpos.ex1=4915; 00157 armpos.ex1=4915; 00158 positions.push_back(armpos); 00159 //armpos.base=590; armpos.shoulder=-1205; armpos.elbow=857; armpos.wrist1=615; armpos.wrist2=-795; armpos.gripper=0; armpos.ex1=95684; 00160 armpos.ex1=95684; 00161 positions.push_back(armpos); 00162 //armpos.base=3140; armpos.shoulder=-1204; armpos.elbow=856; armpos.wrist1=615; armpos.wrist2=-795; armpos.gripper=0; armpos.ex1=141287; 00163 armpos.ex1=141287; 00164 positions.push_back(armpos); 00165 //armpos.base=3322; armpos.shoulder=-9856; armpos.elbow=1556; armpos.wrist1=348; armpos.wrist2=-332; armpos.gripper=0; armpos.ex1=141271; 00166 armpos.ex1=141271; 00167 positions.push_back(armpos); 00168 //armpos.base=-1418; armpos.shoulder=-8198; armpos.elbow=6136; armpos.wrist1=1152; armpos.wrist2=-1106; armpos.gripper=0; armpos.ex1=58362; 00169 armpos.ex1=58362; 00170 positions.push_back(armpos); 00171 //armpos.base=-4147; armpos.shoulder=-11764; armpos.elbow=101; armpos.wrist1=489; armpos.wrist2=-584; armpos.gripper=0; armpos.ex1=4931; 00172 armpos.ex1=4931; 00173 positions.push_back(armpos); 00174 */ 00175 00176 return positions; 00177 00178 } 00179 00180 void setWrist(Robots::ArmPos &armPos, float ang) 00181 { 00182 armPos.wrist1 = (ang*(2568.0*2.0)/M_PI); 00183 armPos.wrist2 = -1*ang*(2568.0*2.0)/M_PI; 00184 } 00185 00186 // ###################################################################### 00187 int main(int argc, char* argv[]) 00188 { 00189 signal(SIGHUP, terminate); signal(SIGINT, terminate); 00190 signal(SIGQUIT, terminate); signal(SIGTERM, terminate); 00191 signal(SIGALRM, terminate); 00192 00193 00194 ModelManager manager("Test Model for Scorbot robot arm controller"); 00195 00196 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager)); 00197 manager.addSubComponent(ofs); 00198 00199 nub::ref<InputFrameSeries> ifs(new InputFrameSeries(manager)); 00200 manager.addSubComponent(ifs); 00201 00202 00203 // Parse command-line: 00204 if (manager.parseCommandLine(argc, argv, "FileName", 0, 1) == false) return(1); 00205 00206 std::string fileName = manager.getExtraArg(0); 00207 00208 // let's get all our ModelComponent instances started: 00209 manager.start(); 00210 00211 ifs->startStream(); 00212 while(1) 00213 { 00214 GenericFrame input = ifs->readFrame(); 00215 if (!input.initialized()) 00216 break; 00217 00218 00219 Image<PixRGB<byte> > inImage = input.asRgb(); 00220 Point2D<int> center(inImage.getWidth()/2, inImage.getHeight()/2); 00221 Dims winSize(512,512); 00222 00223 Image<PixRGB<byte> > objImg = crop(inImage, Rectangle::centerDims(center, winSize)); 00224 drawCircle(objImg, Point2D<int>(256,256), 3, PixRGB<byte>(255,0,0), 3); 00225 00226 drawCircle(inImage, Point2D<int>(inImage.getWidth()/2,inImage.getHeight()/2), 3, PixRGB<byte>(255,0,0), 3); 00227 00228 ofs->writeRGB(inImage, "Output", FrameInfo("output", SRC_POS)); 00229 00230 } 00231 00232 /* 00233 try { 00234 ic = Ice::initialize(argc, argv); 00235 Ice::ObjectPrx base = ic->stringToProxy( 00236 "ScorbotServer:default -p 10000 -h ihead"); 00237 scorbot = Robots::ScorbotIcePrx::checkedCast(base); 00238 if(!scorbot) 00239 throw "Invalid Proxy!"; 00240 00241 00242 std::vector<Robots::ArmPos> armPos = getArmPositions(); 00243 Robots::ArmPos homePos = armPos[0]; 00244 //homePos.base = 0; homePos.shoulder = 0; homePos.elbow = 0; homePos.wrist1 = 0; homePos.wrist2 = 0; homePos.ex1 = 0; homePos.ex2 = 0; 00245 //homePos.duration = 1000; 00246 00247 00248 00249 LINFO("Move robot %i %i", homePos.wrist1, homePos.wrist2); 00250 //scorbot->setArmPos(homePos); 00251 //getchar(); 00252 00253 scorbot->setArmPos(armPos[0]); 00254 sleep(2); 00255 LINFO("Done"); 00256 00257 uint currentArmPos = 0; 00258 bool motorsOn = false; 00259 bool clearToShoot = false; 00260 bool startSequance = false; 00261 00262 Image<PixRGB<byte> > lastInput; 00263 00264 while(1) 00265 { 00266 const FrameState is = ifs->updateNext(); 00267 if (is == FRAME_COMPLETE) 00268 break; 00269 00270 GenericFrame input = ifs->readFrame(); 00271 if (!input.initialized()) 00272 break; 00273 00274 00275 Image<PixRGB<byte> > inImage = input.asRgb(); 00276 Point2D<int> center(inImage.getWidth()/2, inImage.getHeight()/2); 00277 Dims winSize(512,512); 00278 00279 Image<PixRGB<byte> > objImg = crop(inImage, Rectangle::centerDims(center, winSize)); 00280 00281 00282 double imgSum = 1e10; 00283 if (lastInput.initialized()) 00284 { 00285 Image<float> lum1 = luminance(objImg); 00286 Image<float> lum2 = luminance(lastInput); 00287 Image<float> diffImg = lum1 - lum2; 00288 imgSum = sum(diffImg); 00289 } 00290 if (!(ifs->frame()%10)) 00291 { 00292 lastInput = objImg; 00293 double diff = fabs(imgSum)/(512*512); 00294 00295 int time = scorbot->getMovementTime(); 00296 //LINFO("Going to pos %i at %i/%i", currentArmPos, time, armPos[currentArmPos].duration); 00297 00298 if (diff < 0.5 && time >= armPos[currentArmPos].duration) 00299 clearToShoot = true; 00300 } 00301 00302 00303 00304 drawRect(inImage, Rectangle::centerDims(center, winSize), PixRGB<byte>(0,255,0)); 00305 drawCircle(inImage, center, 3, PixRGB<byte>(254,0,0), 3); 00306 00307 00308 00309 00310 if (startSequance) 00311 { 00312 if (clearToShoot) 00313 { 00314 char file[255]; 00315 sprintf(file, "%s/pos%i.ppm", fileName.c_str(), currentArmPos); //This is the previus position 00316 //LINFO("Capture image to %s", file); 00317 sleep(2); 00318 //Raster::WriteRGB(objImg, file); 00319 //SHOWIMG(objImg); 00320 00321 clearToShoot = false; 00322 00323 Robots::ArmPos curArmPos = scorbot->getArmPos(); 00324 Robots::ArmPos desArmPos = armPos[currentArmPos]; 00325 LINFO ("armpos.base=%i/%i; armpos.shoulder=%i/%i; armpos.elbow=%i/%i; armpos.wrist1=%i/%i; armpos.wrist2=%i/%i;", 00326 curArmPos.base, desArmPos.base, 00327 curArmPos.shoulder, desArmPos.shoulder, 00328 curArmPos.elbow, desArmPos.elbow, 00329 curArmPos.wrist1, desArmPos.wrist1, 00330 curArmPos.wrist2, desArmPos.wrist2); 00331 00332 scorbot->setArmPos(armPos[currentArmPos]); 00333 currentArmPos++; 00334 if (currentArmPos > armPos.size()) 00335 { 00336 currentArmPos = 0; 00337 startSequance = true; 00338 scorbot->setArmPos(armPos[currentArmPos]); 00339 } 00340 } 00341 00342 } 00343 00344 00345 drawCircle(objImg, Point2D<int>(256,256), 3, PixRGB<byte>(255,0,0), 3); 00346 ofs->writeRGB(objImg, "Output", FrameInfo("output", SRC_POS)); 00347 00348 00349 int key = getKey(ofs); 00350 00351 if (key != -1) 00352 { 00353 LINFO("Key %i", key); 00354 switch(key) 00355 { 00356 case 36: //enter 00357 startSequance = true; 00358 break; 00359 case 43: //h home 00360 LINFO("Going home\n"); 00361 scorbot->setArmPos(homePos); 00362 break; 00363 case 33: //p getPositions 00364 { 00365 Robots::ArmPos armpos = scorbot->getArmPos(); 00366 LINFO ("armpos.base=%i; armpos.shoulder=%i; armpos.elbow=%i; armpos.wrist1=%i; armpos.wrist2=%i; armpos.gripper=%i; armpos.ex1=%i; armpos.ex2=%i;", 00367 armpos.base, armpos.shoulder, armpos.elbow , armpos.wrist1, armpos.wrist2, armpos.gripper, armpos.ex1, armpos.ex2); 00368 } 00369 break; 00370 case 58: //m 00371 motorsOn = !motorsOn; 00372 if (motorsOn) 00373 scorbot->motorsOn(); 00374 else 00375 scorbot->motorsOff(); 00376 break; 00377 } 00378 } 00379 00380 } 00381 //mainLoop(); 00382 00383 } catch(const Ice::Exception& ex) { 00384 std::cerr << ex << std::endl; 00385 status = 1; 00386 } catch(const char* msg) { 00387 std::cerr << msg << std::endl; 00388 status = 1; 00389 } 00390 00391 if(ic) 00392 ic->destroy(); 00393 00394 cleanupAndExit(); 00395 return status; 00396 */ 00397 return 0; 00398 }