ViSP  2.9.0
vpServolens.cpp
1 /****************************************************************************
2  *
3  * $Id: vpServolens.cpp 4649 2014-02-07 14:57:11Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Interface for the Servolens lens attached to the camera fixed on the
36  * Afma4 robot.
37  *
38  * Authors:
39  * Fabien Spindler
40  *
41  *****************************************************************************/
42 
52 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
53 
54 #include <unistd.h>
55 #include <termios.h>
56 #include <stdio.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <fcntl.h>
60 #include <stdlib.h>
61 #include <string.h>
62 
63 #include <visp/vpServolens.h>
64 #include <visp/vpRobotException.h>
65 #include <visp/vpDebug.h>
66 #include <visp/vpTime.h>
67 
74 vpServolens::vpServolens() : remfd(0), isinit(false)
75 {
76 }
77 
86 vpServolens::vpServolens(const char *port) : remfd(0), isinit(false)
87 {
88  this->open(port);
89 }
90 
98 vpServolens::~vpServolens()
99 {
100  this->close();
101 }
102 
117 void
118 vpServolens::open(const char *port)
119 {
120  if (! isinit) {
121  struct termios info;
122 
123  printf("\nOpen the Servolens serial port \"%s\"\n", port);
124 
125  if ((this->remfd=::open(port, O_RDWR|O_NONBLOCK)) < 0) {
126  vpERROR_TRACE ("Cannot open Servolens serial port.");
128  "Cannot open Servolens serial port.");
129  }
130 
131  // Lecture des parametres courants de la liaison serie.
132  if (tcgetattr(this->remfd, &info) < 0) {
133  ::close(this->remfd);
134  vpERROR_TRACE ("Error using TCGETS in ioctl.");
136  "Error using TCGETS in ioctl");
137  }
138 
139  //
140  // Configuration de la liaison serie:
141  // 9600 bauds, 1 bit de stop, parite paire, 7 bits de donnee
142  //
143 
144  // Traitement sur les caracteres recus
145  info.c_iflag = 0;
146  info.c_iflag |= INLCR;
147 
148  // Traitement sur les caracteres envoyes sur la RS232.
149  info.c_oflag = 0; // idem
150 
151  // Traitement des lignes
152  info.c_lflag = 0;
153 
154  // Controle materiel de la liaison
155  info.c_cflag = 0;
156  info.c_cflag |= CREAD; // Validation reception
157  info.c_cflag |= B9600 | CS7 | PARENB; // 9600 baus, 7 data, parite paire
158 
159  // Caracteres immediatement disponibles.
160  // info.c_cc[VMIN] = 1;
161  // info.c_cc[VTIME] = 0;
162 
163  if (tcsetattr(this->remfd, TCSANOW, &info) < 0) {
164  ::close(this->remfd);
165  vpERROR_TRACE ("Error using TCGETS in ioctl.");
167  "Error using TCGETS in ioctl");
168  }
169 
170  // Supprime tous les caracteres recus mais non encore lus par read()
171  tcflush(this->remfd, TCIFLUSH);
172 
173  isinit = true;
174 
175  this->init();
176 
177  // Try to get the position of the zoom to check if the lens is really connected
178  unsigned int izoom;
179  if (this->getPosition(vpServolens::ZOOM, izoom) == false) {
180  vpERROR_TRACE ("Cannot dial with the servolens. Check if the serial link is connected.");
182  "Cannot dial with the servolens. Check if the serial link is connected.");
183 
184  }
185 
186  }
187 }
188 
193 void
194 vpServolens::close()
195 {
196  if (isinit) {
197  printf("\nClose the serial connexion with Servolens\n");
198  ::close(this->remfd);
199  isinit = false;
200  }
201 }
202 
209 void
210 vpServolens::reset() const
211 {
212  if (!isinit) {
213  vpERROR_TRACE ("Cannot dial with Servolens.");
215  "Cannot dial with Servolens.");
216  }
217  char commande[10];
218 
219  /* suppression de l'echo */
220  sprintf(commande, "SE1");
221  this->write(commande);
222 
223  /* initialisation de l'objectif, idem qu'a la mise sous tension */
224  sprintf(commande, "SR0");
225  this->write(commande);
226 
227  vpTime::wait(25000);
228 
229  this->wait();
230 
231  /* suppression de l'echo */
232  sprintf(commande, "SE0");
233  this->write(commande);
234 
235  /* devalide l'incrustation de la fenetre sur l'ecran du moniteur */
236  sprintf(commande, "VW0");
237  this->write(commande);
238 }
247 void
248 vpServolens::init() const
249 {
250  if (!isinit) {
251  vpERROR_TRACE ("Cannot dial with Servolens.");
253  "Cannot dial with Servolens.");
254  }
255 
256  char commande[10];
257 
258  /* suppression de l'echo */
259  sprintf(commande, "SE0");
260  this->write(commande);
261 
262  /* devalide l'incrustation de la fenetre sur l'ecran du moniteur */
263  sprintf(commande, "VW0");
264  this->write(commande);
265 
266  /* L'experience montre qu'une petite tempo est utile. */
267  vpTime::wait(500);
268 }
269 
282 void
283 vpServolens::enableCmdComplete(vpServoType servo, bool active) const
284 {
285  if (!isinit) {
286  vpERROR_TRACE ("Cannot dial with Servolens.");
288  "Cannot dial with Servolens.");
289  }
290  char commande[10];
291 
292  /* Envoie une commande pour qu'en fin de mouvement servolens renvoie
293  * une information de fin de mouvement (ex: ZF, FF, DF).
294  */
295  switch(servo) {
296  case ZOOM:
297  if (active)
298  sprintf(commande, "ZF1");
299  else
300  sprintf(commande, "ZF0");
301  break;
302  case FOCUS:
303  if (active)
304  sprintf(commande, "FF1");
305  else
306  sprintf(commande, "FF0");
307  break;
308  case IRIS:
309  if (active)
310  sprintf(commande, "DF1");
311  else
312  sprintf(commande, "DF0");
313  break;
314  }
315 
316  /* envoie de la commande */
317  this->write(commande); /* a la fin du mouvement envoie de ZF, FF, DF */
318 }
319 
330 void
331 vpServolens::enablePrompt(bool active) const
332 {
333  if (!isinit) {
334  vpERROR_TRACE ("Cannot dial with Servolens.");
336  "Cannot dial with Servolens.");
337  }
338  char commande[10];
339 
340  /* suppression de l'echo */
341  if (active == true)
342  sprintf(commande, "SE1");
343  else
344  sprintf(commande, "SE0");
345 
346  this->write(commande);
347 }
348 
357 void
358 vpServolens::setController(vpControllerType controller) const
359 {
360  if (!isinit) {
361  vpERROR_TRACE ("Cannot dial with Servolens.");
363  "Cannot dial with Servolens.");
364  }
365  char commande[10];
366 
367  switch(controller) {
368  case AUTO:
369  /* Valide l'incrustation de la fenetre sur l'ecran du moniteur */
370  sprintf(commande, "VW1");
371  this->write(commande);
372  break;
373  case CONTROLLED:
374  /* nettoyage : mot d'etat vide 0000 */
375  sprintf(commande,"SX0842");
376  this->write(commande);
377  /* devalide l'incrustation de la fenetre sur l'ecran du moniteur */
378  sprintf(commande, "VW0");
379  this->write(commande);
380  break;
381  case RELEASED:
382  sprintf(commande,"SX1084");
383  this->write(commande);
384  /* devalide l'incrustation de la fenetre sur l'ecran du moniteur */
385  sprintf(commande, "VW0");
386  this->write(commande);
387  break;
388  }
389 
390 }
391 
398 void
399 vpServolens::setAutoIris(bool enable) const
400 {
401  if (!isinit) {
402  vpERROR_TRACE ("Cannot dial with Servolens.");
404  "Cannot dial with Servolens.");
405  }
406  char commande[10];
407 
408  if (enable)
409  sprintf(commande, "DA1");
410  else
411  sprintf(commande, "DA0");
412 
413  this->write(commande);
414 }
415 
426 void
427 vpServolens::setPosition(vpServoType servo, unsigned int position) const
428 {
429  if (!isinit) {
430  vpERROR_TRACE ("Cannot dial with Servolens.");
432  "Cannot dial with Servolens.");
433  }
434  char commande[10];
435 
436  /* attente du prompt pour envoyer une commande */
437  /*
438  printf("attente prompt\n");
439  this->wait();
440  */
441 
442 #ifdef FINSERVO
443  /* envoie des commandes pour qu'en fin de mouvement servolens renvoie */
444  /* une commande de fin de mouvement (ex: ZF, FF, DF). */
445  this->enableCommandComplete();
446 #endif /* FINSERVO */
447 
448  // 08/08/00 Fabien S. - Correction de la consigne demandee
449  // pour prendre en compte l'erreur entre la consigne demandee
450  // et la consigne mesuree.
451  // A la consigne du zoom on retranche 1.
452  // A la consigne du focus on ajoute 1.
453  // A la consigne du iris on ajoute 1.
454  switch (servo) {
455  case ZOOM:
456  //printf("zoom demande: %d ", position);
457  position --;
458  if (position < ZOOM_MIN) position = ZOOM_MIN;
459  //printf("zoom corrige: %d \n", position);
460  break;
461  case FOCUS:
462  //printf("focus demande: %d ", position);
463  position ++;
464  if (position > FOCUS_MAX) position = FOCUS_MAX;
465  //printf("focus corrige: %d \n", position);
466  break;
467  case IRIS:
468  // printf("iris demande: %d ", position);
469  position ++;
470  if (position > IRIS_MAX) position = IRIS_MAX;
471  //printf("iris corrige: %s \n", position);
472  break;
473  }
474 
475  /* commande a envoyer aux servomoteurs */
476  switch(servo) {
477  case ZOOM:
478  sprintf(commande, "ZD%d", position);
479  break;
480  case FOCUS:
481  sprintf(commande, "FD%d", position);
482  break;
483  case IRIS:
484  sprintf(commande, "DD%d", position);
485  break;
486  }
487  /* envoie de la commande */
488 #ifdef PRINT
489  printf("\ncommande: %s", commande);
490 #endif
491 
492  this->write(commande);
493 
494 #ifdef FINSERVO
495  /* on attend la fin du mouvement des objectifs */
496  this->wait(servo); /* on attend les codes ZF, FF, DF */
497 #endif
498 }
499 
510 bool
511 vpServolens::getPosition(vpServoType servo, unsigned int &position) const
512 {
513  if (!isinit) {
514  vpERROR_TRACE ("Cannot dial with Servolens.");
516  "Cannot dial with Servolens.");
517  }
518  char commande[10];
519  char posit[10], *pt_posit;
520  char c;
521  short fin_lect_posit; /* indique si on a lu la position du servo-moteur */
522  short posit_car; /* donne la position du caractere lu */
523  short lecture_posit_en_cours; /* indique si on lit la position courante */
524 
525  /* attente du prompt pour envoyer une commande */
526  /*
527  this->wait();
528  */
529  pt_posit = posit;
530 
531  /* envoie des commandes pour obtenir la position des servo-moteurs. */
532  switch (servo) {
533  case ZOOM:
534  sprintf(commande, "ZD?");
535  break;
536  case FOCUS:
537  sprintf(commande, "FD?");
538  break;
539  case IRIS:
540  sprintf(commande, "DD?");
541  break;
542  default:
543  break;
544  }
545  /* envoie de la commande */
546  // printf("\ncommande: %s", commande);
547 
548  this->write(commande);
549 
550  /* on cherche a lire la position du servo-moteur */
551  /* Servolens renvoie une chaine de caractere du type ZD00400 ou FD00234 */
552  fin_lect_posit = 0;
553  posit_car = 0;
554  lecture_posit_en_cours = 0;
555  do {
556  if (this->read(&c, 1) == true) {
557 
558  // printf("caractere lu: %c\n", c);
559  switch (posit_car){
560  /* on lit le 1er caractere; (soit Z, soit F, soit D) */
561  case 0:
562  /* sauvegarde du pointeur */
563  pt_posit = posit;
564 
565  switch (servo) {
566  case ZOOM:
567  if( c == 'Z') posit_car = 1;
568  break;
569  case FOCUS:
570  if( c == 'F') posit_car = 1;
571  break;
572  case IRIS:
573  if( c == 'D') posit_car = 1;
574  break;
575  }
576  break;
577 
578  /* si le 1er caractere est correct, on lit le 2eme caractere */
579  /* (toujours D) */
580  case 1:
581  if( c == 'D') posit_car = 2;
582  else posit_car = 0; /* le 2eme caractere n'est pas correct */
583  break;
584 
585  /* si on a lu les 2 premiers caracteres, on peut lire la */
586  /* position du servo-moteur */
587  case 2:
588  if (c >= '0' && c <= '9')
589  {
590  *pt_posit++ = c; /* sauvegarde de la position */
591  lecture_posit_en_cours = 1;
592  }
593  else if (lecture_posit_en_cours)
594  {
595  fin_lect_posit = 1;
596  *pt_posit = '\0';
597  }
598  else posit_car = 0;
599  break;
600  }
601 
602  }
603  else {
604  // Timout sur la lecture, on retoure FALSE
605  return false;
606  }
607  }
608  while ( !fin_lect_posit );
609 
610  // printf("\nChaine lue: posit: %s", posit);
611 
612  /* toilettage de la position courantes lue */
613  this->clean(posit, posit);
614 
615  // printf("\nChaine toilettee: posit: %s", posit);
616  position = (unsigned int)atoi(posit);
617 
618  return(true);
619 }
620 
649 vpServolens::getCameraParameters(vpImage<unsigned char> &I) const
650 {
651  if (!isinit) {
652  vpERROR_TRACE ("Cannot dial with Servolens.");
654  "Cannot dial with Servolens.");
655  }
656  vpCameraParameters cam;
657  double pix_size = 7.4e-6; // Specific to the Dragonfly2 camera
658  double px=1000, py=1000, u0=320, v0=240;
659  // Determine if the image is subsampled.
660  // Dragonfly2 native images are 640 by 480
661  double subsample_factor = 1.;
662  double width = I.getWidth();
663  double height= I.getHeight();
664 
665 
666  if (width > 300 && width < 340 && height > 220 && height < 260)
667  subsample_factor = 2;
668  else if (width > 140 && width < 1800 && height > 100 && height < 140)
669  subsample_factor = 4;
670 
671  unsigned zoom;
672  getPosition(vpServolens::ZOOM, zoom);
673  //std::cout << "Actual zoom value: " << zoom << std::endl;
674 
675  // XSIZE_PIX_CAM_AFMA4 / focale et YSIZE_PIX_CAM_AFMA4 / focale correspondent
676  // aux parametres de calibration de la camera (donnees constructeur) pour des
677  // tailles d'images CCIR (768x576), donc avec scale = 1.
678  double focale = zoom * 1.0e-5; // Transformation en metres
679  px = focale / (double)(subsample_factor * pix_size); // Taille des pixels en metres.
680  py = focale / (double)(subsample_factor * pix_size); // Taille des pixels en metres.
681  u0 = I.getWidth() / 2.;
682  v0 = I.getHeight() / 2.;
683  cam.initPersProjWithoutDistortion(px, py, u0, v0);
684 
685  return cam;
686 }
687 
696 char
697 vpServolens::wait() const
698 {
699  if (!isinit) {
700  vpERROR_TRACE ("Cannot dial with Servolens.");
702  "Cannot dial with Servolens.");
703  }
704 
705  ssize_t r;
706  r = ::write(this->remfd, "\r\n", strlen("\r\n"));
707  if (r != (ssize_t)(strlen("\r\n"))) {
709  "Cannot write on Servolens.");
710  }
711  char c;
712  do {
713  r = ::read(this->remfd, &c, 1);
714  c &= 0x7f;
715  }
716  while (c != '>');
717  return c;
718 
719 }
720 
731 void
732 vpServolens::wait(vpServoType servo) const
733 {
734  if (!isinit) {
735  vpERROR_TRACE ("Cannot dial with Servolens.");
737  "Cannot dial with Servolens.");
738  }
739 
740  char c;
741  char fin_mvt[3];
742  bool sortie = false;
743 
744  switch (servo) {
745  case ZOOM:
746  sprintf(fin_mvt, "ZF");
747  break;
748  case FOCUS:
749  sprintf(fin_mvt, "FF");
750  break;
751  case IRIS:
752  default:
753  sprintf(fin_mvt, "DF");
754  break;
755 
756  }
757 
758  /* lecture des caracteres recus */
759  do {
760  /* lecture des caracteres */
761  if (::read(this->remfd,&c,1) != 1) {
763  "Cannot read on Servolens.");
764  }
765  c &= 0x7f;
766 
767  /* tests si fin de mouvement */
768  if (c == fin_mvt[0]) {
769  /* lecture du caractere suivant */
770  if (::read(this->remfd,&c,1) != 1) {
772  "Cannot read on Servolens.");
773  }
774 
775  c &= 0x7f;
776  if (c == fin_mvt[1]) {
777  sortie = true;
778  }
779  }
780  }
781  while ( !sortie);
782 
783  /* printf("\nmouvement fini: chaine lue = %s", chaine); */
784 }
785 
797 bool
798 vpServolens::read(char *c, long timeout_s) const
799 {
800  if (!isinit) {
801  vpERROR_TRACE ("Cannot dial with Servolens.");
803  "Cannot dial with Servolens.");
804  }
805 
806  int n;
807  fd_set readfds; /* list of fds for select to listen to */
808  struct timeval timeout = {timeout_s, 0}; // seconde, micro-sec
809 
810  FD_ZERO(&readfds);
811  FD_SET(static_cast<unsigned int>(this->remfd), &readfds);
812 
813  if (select(FD_SETSIZE, &readfds, (fd_set *)NULL,
814  (fd_set *)NULL, &timeout) > 0) {
815  n = ::read(this->remfd, c, 1); /* read one character at a time */
816  if (n != 1)
817  return false;
818  *c &= 0x7f;
819  //printf("lecture 1 car: %c\n", *c);
820  return(true);
821  }
822 
823  return (false);
824 }
825 
834 void
835 vpServolens::write(const char *s) const
836 {
837  if (!isinit) {
838  vpERROR_TRACE ("Cannot dial with Servolens.");
840  "Cannot dial with Servolens.");
841  }
842  ssize_t r = 0;
843  r = ::write(this->remfd,"\r", strlen("\r"));
844  r += ::write(this->remfd, s, strlen(s));
845  r += ::write(this->remfd,"\r", strlen("\r"));
846  if (r != (ssize_t)(2*strlen("\r") + strlen(s))) {
848  "Cannot write on Servolens.");
849  }
850 
851 
852  /*
853  * Une petite tempo pour laisser le temps a la liaison serie de
854  * digerer la commande envoyee. En fait, la liaison serie fonctionne
855  * a 9600 bauds soit une transmission d'environ 9600 bits pas seconde.
856  * Les plus longues commandes envoyees sur la liaison serie sont du type:
857  * SX0842 soit 6 caracteres codes sur 8 bits chacuns = 48 bits pour
858  * envoyer la commande SX0842.
859  * Ainsi, le temps necessaire pour envoyer SX0842 est d'environ
860  * 48 / 9600 = 0,0050 secondes = 5 milli secondes.
861  * Ici on rajoute une marge pour amener la tempo a 20 ms.
862  */
863  vpTime::wait(20);
864 }
865 
873 bool
874 vpServolens::clean(const char *in, char *out) const
875 {
876  short nb_car, i=0;
877  bool error = false;
878 
879  nb_car = strlen(in);
880 
881  /* on se positionne sur le 1er caractere different de zero */
882  while( *(in) == '0' && i++ < nb_car ) {
883  in++;
884  if (i == nb_car)
885  {
886  error = true; /* la chaine ne contient pas une position */
887  *(out++) = '0'; /* mise a zero de la position */
888  }
889  }
890 
891  /* copie de la position epuree des zeros de gauche */
892  while( i++ <= nb_car ) { /* on a mis le = pour copier le caractere de fin */
893  /* de chaine \0 */
894  *(out++) = *(in++);
895  }
896  return (error);
897 }
898 
899 #endif
Error that can be emited by the vpRobot class and its derivates.
unsigned int getWidth() const
Definition: vpImage.h:159
#define vpERROR_TRACE
Definition: vpDebug.h:395
static int wait(double t0, double t)
Definition: vpTime.cpp:149
void initPersProjWithoutDistortion(const double px, const double py, const double u0, const double v0)
Generic class defining intrinsic camera parameters.
unsigned int getHeight() const
Definition: vpImage.h:150