p2os_ptz.cpp
Go to the documentation of this file.
1 /*
2  * P2OS for ROS
3  * Copyright (C) 2000 Tucker Hermans
4  * Copyright (C) 2018 Hunter L. Allen
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #include <p2os_driver/p2os_ptz.hpp>
23 #include <p2os_driver/p2os.hpp>
24 
25 //
26 // Constants
27 //
28 const int P2OSPtz::MAX_COMMAND_LENGTH = 19;
29 const int P2OSPtz::MAX_REQUEST_LENGTH = 17;
31 const int P2OSPtz::PACKET_TIMEOUT = 300;
32 const int P2OSPtz::SLEEP_TIME_USEC = 300000;
33 const int P2OSPtz::PAN_THRESH = 1;
34 const int P2OSPtz::TILT_THRESH = 1;
35 const int P2OSPtz::ZOOM_THRESH = 1;
36 
37 //
38 // Constructors
39 //
40 P2OSPtz::P2OSPtz(P2OSNode * p2os, bool bidirectional_com)
41 : p2os_(p2os), max_zoom_(MAX_ZOOM_OPTIC), pan_(0), tilt_(0), zoom_(0),
42  is_on_(false), error_code_(CAM_ERROR_NONE),
43  bidirectional_com_(bidirectional_com)
44 {
45  current_state_.pan = 0;
46  current_state_.zoom = 0;
47  current_state_.tilt = 0;
48  current_state_.relative = false;
49 }
50 
51 
52 //
53 // Core Functions
54 //
56 {
57  int err = 0;
58  int num_inits = 7;
59  is_on_ = true;
60  for (int i = 1; i < num_inits; i++) {
61  switch (i) {
62  // case 0:
63  // do
64  // {
65  // ROS_DEBUG("Waiting for camera to power off.");
66  // err = setPower(POWER_OFF);
67  // } while (error_code_ == CAM_ERROR_BUSY);
68  // break;
69  case 1:
70  do {
71  ROS_DEBUG("Waiting for camera to power on.");
72  err = setPower(POWER_ON);
73  } while (error_code_ == CAM_ERROR_BUSY);
74  break;
75  case 2:
76  do {
77  ROS_DEBUG("Waiting for camera mode to set");
78  err = setControlMode();
79  } while (error_code_ == CAM_ERROR_BUSY);
80  break;
81  case 3:
82  do {
83  ROS_DEBUG("Waiting for camera to initialize");
84  err = sendInit();
85  } while (error_code_ == CAM_ERROR_BUSY);
86  break;
87  case 4:
88  do {
89  for (int i = 0; i < 3; i++) {
90  ROS_DEBUG("Waiting for camera to set default tilt");
91  err = setDefaultTiltRange();
92  }
93  } while (error_code_ == CAM_ERROR_BUSY);
94  break;
95  case 5:
96  do {
97  ROS_DEBUG("Waiting for camera to set initial pan and tilt");
98  err = sendAbsPanTilt(0, 0);
99  } while (error_code_ == CAM_ERROR_BUSY);
100  break;
101  case 6:
102  do {
103  ROS_DEBUG("Waiting for camera to set initial zoom");
104  err = sendAbsZoom(0);
105  } while (error_code_ == CAM_ERROR_BUSY);
106  break;
107  default:
108  err = -7;
109  break;
110  }
111 
112  // Check for erros after each attempt
113  if (err) {
114  ROS_ERROR("Error initiliazing PTZ at stage %i", i);
115  switch (error_code_) {
116  case CAM_ERROR_BUSY:
117  ROS_ERROR("Error: CAM_ERROR_BUSY");
118  break;
119  case CAM_ERROR_PARAM:
120  ROS_ERROR("Error: CAM_ERROR_PARAM");
121  break;
122  case CAM_ERROR_MODE:
123  ROS_ERROR("Error: CAM_ERROR_MODE");
124  break;
125  default:
126  ROS_ERROR("Error: Unknown error response from camera.");
127  break;
128  }
129  return -1;
130  } else {
131  ROS_DEBUG("Passed stage %i of PTZ initialization.", i);
132  }
133  }
134  ROS_DEBUG("Finished initialization of the PTZ.");
135  return 0;
136 }
137 
139 {
140  sendAbsPanTilt(0, 0);
141  usleep(SLEEP_TIME_USEC);
142  sendAbsZoom(0);
143  usleep(SLEEP_TIME_USEC);
145  usleep(SLEEP_TIME_USEC);
146  ROS_INFO("PTZ camera has been shutdown");
147 }
148 
149 void P2OSPtz::callback(const p2os_msgs::PTZStateConstPtr & cmd)
150 {
151  p2os_msgs::PTZState to_send;
152  bool change_pan_tilt = false;
153  bool change_zoom = false;
154  to_send.pan = pan_;
155  to_send.tilt = tilt_;
156  to_send.zoom = zoom_;
157 
158  // Check if the command is relative to the current position
159  if (cmd->relative) {
160  if (abs(cmd->pan) > PAN_THRESH) {
161  to_send.pan = cmd->pan + pan_;
162  change_pan_tilt = true;
163  }
164  if (abs(cmd->tilt) > TILT_THRESH) {
165  to_send.tilt = cmd->tilt + tilt_;
166  change_pan_tilt = true;
167  }
168  if (abs(cmd->zoom) > ZOOM_THRESH) {
169  to_send.zoom = cmd->zoom + zoom_;
170  change_zoom = true;
171  }
172  } else {
173  if (abs(cmd->pan - pan_) > PAN_THRESH) {
174  to_send.pan = cmd->pan;
175  change_pan_tilt = true;
176  }
177  if (abs(cmd->tilt - tilt_) > TILT_THRESH) {
178  to_send.tilt = cmd->tilt;
179  change_pan_tilt = true;
180  }
181  if (abs(cmd->zoom - zoom_) > ZOOM_THRESH) {
182  to_send.zoom = cmd->zoom;
183  change_zoom = true;
184  }
185  }
186 
187  if (change_pan_tilt) {
188  sendAbsPanTilt(to_send.pan, to_send.tilt);
189  }
190  if (change_zoom) {
191  sendAbsZoom(to_send.zoom);
192  }
193 
194  current_state_.pan = pan_;
195  current_state_.zoom = zoom_;
196  current_state_.tilt = tilt_;
197 }
198 
199 //
200 // Communication Functions
201 //
202 int P2OSPtz::sendCommand(unsigned char * str, int len)
203 {
204  P2OSPacket ptz_packet;
205  P2OSPacket request_pkt;
206  unsigned char request[4];
207 
208  // Zero out the Receive Buffer
209  request[0] = GETAUX;
210  request[1] = ARGINT;
211  request[2] = 0;
212  request[3] = 0;
213  request_pkt.Build(request, 4);
214  p2os_->SendReceive(&request_pkt, false);
215 
216  if (len > MAX_COMMAND_LENGTH) {
217  ROS_ERROR("Command message is too large to send");
218  return -1;
219  }
220 
221  // Since I'm hardcoding this to AUX1, basically we gotta stick the AUX1DATA
222  // header on this and then give it to the p2os send command.
223  unsigned char mybuf[MAX_COMMAND_LENGTH + 3];
224  mybuf[0] = TTY2;
225  mybuf[1] = ARGSTR;
226  mybuf[2] = len;
227  // Copy the command
228  memcpy(&mybuf[3], str, len);
229  ptz_packet.Build(mybuf, len + 3);
230 
231  // Send the packet
232  p2os_->SendReceive(&ptz_packet, false);
233 
234  return 0;
235 }
236 
237 int P2OSPtz::sendRequest(unsigned char * str, int len, unsigned char * reply)
238 {
239  static_cast<void>(reply); // TODO(hallen): why isn't this used?
240  P2OSPacket ptz_packet;
241  P2OSPacket request_pkt;
242  unsigned char request[4];
243 
244  // Zero out the Receive Buffer
245  request[0] = GETAUX;
246  request[1] = ARGINT;
247  request[2] = 0;
248  request[3] = 0;
249  request_pkt.Build(request, 4);
250  p2os_->SendReceive(&request_pkt, false);
251 
252  if (len > MAX_REQUEST_LENGTH) {
253  ROS_ERROR("Request message is too large to send.");
254  return -1;
255  }
256 
257  // Since I'm hardcoding this to AUX1, basically we gotta stick the AUX1DATA
258  // header on this and then give it to the p2os send command.
259  unsigned char mybuf[MAX_REQUEST_LENGTH];
260  mybuf[0] = TTY2;
261  mybuf[1] = ARGSTR;
262  mybuf[2] = len;
263  // Copy the command
264  memcpy(&mybuf[3], str, len);
265  ptz_packet.Build(mybuf, len + 3);
266 
267  // Send the packet
268  p2os_->SendReceive(&ptz_packet, false);
269 
270 
271  return 0;
272 }
273 
275 {
276  int num;
277  unsigned char reply[MAX_REQUEST_LENGTH];
278  int len = 0;
279  unsigned char byte;
280  int t;
281  memset(reply, 0, COMMAND_RESPONSE_BYTES);
282 
283  getPtzPacket(asize);
284 
285  for (num = 0; num <= COMMAND_RESPONSE_BYTES + 1; num++) {
286  // if we don't get any bytes, or if we've just exceeded the limit
287  // then return null
288  t = cb_.getFromBuf();
289  if (t < 0) {
290  // Buf Error!
291  ROS_ERROR("circbuf error!");
292  return -1;
293  } else {
294  byte = (unsigned char)t;
295  }
296  if (byte == (unsigned char)RESPONSE) {
297  reply[0] = byte;
298  len++;
299  break;
300  }
301  }
302 
303  if (len == 0) {
304  ROS_ERROR("Length is 0 on received packet.");
305  return -1;
306  }
307 
308  // we got the header character so keep reading bytes for MAX_RESPONSE_BYTES more
309  for (num = 1; num <= MAX_REQUEST_LENGTH; num++) {
310  t = cb_.getFromBuf();
311  if (t < 0) {
312  // there are no more bytes, so check the last byte for the footer
313  if (reply[len - 1] != (unsigned char)FOOTER) {
314  ROS_ERROR("canonvcc4::receiveCommandAnswer: Discarding bad packet.");
315  return -1;
316  } else {
317  break;
318  }
319  } else {
320  // add the byte to the array
321  reply[len] = (unsigned char)t;
322  len++;
323  }
324  }
325 
326  // Check the response
327  if (len != COMMAND_RESPONSE_BYTES) {
328  ROS_ERROR("Answer does not equal command response bytes");
329  return -1;
330  }
331 
332  // check the header and footer
333  if (reply[0] != (unsigned char)RESPONSE || reply[5] != (unsigned char)FOOTER) {
334  ROS_ERROR("Header or Footer is wrong on received packet");
335  return -1;
336  }
337 
338  // so far so good. Set myError to the error byte
339  error_code_ = reply[3];
340  if (error_code_ == CAM_ERROR_NONE) {
341  return 0;
342  }
343 
344  switch (error_code_) {
345  case CAM_ERROR_BUSY:
346  ROS_ERROR("Error: CAM_ERROR_BUSY");
347  break;
348  case CAM_ERROR_PARAM:
349  ROS_ERROR("Error: CAM_ERROR_PARAM");
350  break;
351  case CAM_ERROR_MODE:
352  ROS_ERROR("Error: CAM_ERROR_MODE");
353  break;
354  default:
355  ROS_ERROR("Error: Unknown error response from camera.");
356  break;
357  }
358  return -1;
359 }
360 
361 /* These commands often have variable packet lengths, if there is an error,
362  * there is a smaller packet size. If we request the larger packet size first,
363  * then we will never get a response back. Because of this, we have to first
364  * request the smaller size, check if its a full packet, if it's not, request
365  * the rest of the packet. Also according to the source code for ARIA, we can
366  * not do more than 2 requests for a single packet, therefor, we can't just
367  * request 1 byte over and over again.
368  *
369  * So here, s1 is the size of the smaller packet.
370  * And s2 is the size of the larger packet.
371  */
372 int P2OSPtz::receiveRequestAnswer(unsigned char * data, int s1, int s2)
373 {
374  int num;
375  unsigned char reply[MAX_REQUEST_LENGTH];
376  int len = 0;
377  unsigned char byte;
378  int t;
379 
380  memset(reply, 0, MAX_REQUEST_LENGTH);
381  getPtzPacket(s1, s2);
382 
383  for (num = 0; num <= COMMAND_RESPONSE_BYTES + 1; num++) {
384  // if we don't get any bytes, or if we've just exceeded the limit
385  // then return null
386  t = cb_.getFromBuf();
387  if (t < 0) { // Buf Error!
388  ROS_ERROR("circbuf error!\n");
389  return -1;
390  } else {
391  byte = (unsigned char)t;
392  }
393  if (byte == (unsigned char)RESPONSE) {
394  reply[0] = byte;
395  len++;
396  break;
397  }
398  }
399  if (len == 0) {
400  ROS_ERROR("Received Request Answer has length 0");
401  return -1;
402  }
403  // we got the header character so keep reading bytes for MAX_RESPONSE_BYTES more
404  for (num = 1; num <= MAX_REQUEST_LENGTH; num++) {
405  t = cb_.getFromBuf();
406  if (t < 0) {
407  // there are no more bytes, so check the last byte for the footer
408  if (reply[len - 1] != (unsigned char)FOOTER) {
409  ROS_ERROR("Last Byte was not the footer!");
410  return -1;
411  } else {
412  break;
413  }
414  } else {
415  // add the byte to the array
416  reply[len] = (unsigned char)t;
417  len++;
418  }
419  }
420  // Check the response length: pt: 14; zoom: 10
421  if (len != COMMAND_RESPONSE_BYTES && len != 8 && len != 10 && len != 14) {
422  ROS_ERROR("Response Length was incorrect at %i.", len);
423  return -1;
424  }
425 
426  if (reply[0] != (unsigned char)RESPONSE ||
427  reply[len - 1] != (unsigned char)FOOTER)
428  {
429  ROS_ERROR("Header or Footer is wrong on received packet");
430  return -1;
431  }
432 
433  // so far so good. Set myError to the error byte
434  error_code_ = reply[3];
435 
436  if (error_code_ == CAM_ERROR_NONE) {
437  memcpy(data, reply, len);
438  return len;
439  }
440  switch (error_code_) {
441  case CAM_ERROR_BUSY:
442  ROS_ERROR("Error: CAM_ERROR_BUSY");
443  break;
444  case CAM_ERROR_PARAM:
445  ROS_ERROR("Error: CAM_ERROR_PARAM");
446  break;
447  case CAM_ERROR_MODE:
448  ROS_ERROR("Error: CAM_ERROR_MODE");
449  break;
450  default:
451  ROS_ERROR("Error: Unknown error response from camera.");
452  break;
453  }
454  return -1;
455 }
456 
457 void P2OSPtz::getPtzPacket(int s1, int s2)
458 {
459  int packetCount = 0;
460  unsigned char request[4];
461  P2OSPacket request_pkt;
462  bool secondSent = false;
463 
464  request[0] = GETAUX;
465  request[1] = ARGINT;
466  request[2] = s1;
467  request[3] = 0;
468 
469  // Reset our receiving buffer.
470  cb_.reset();
471 
472  // Request the request-size back
473  request_pkt.Build(request, 4);
474  p2os_->SendReceive(&request_pkt, false);
475 
476  while (!cb_.gotPacket() ) {
477  if (packetCount++ > PACKET_TIMEOUT) {
478  // Give Up We're not getting it.
479  ROS_ERROR("Waiting for packet timed out.");
480  return;
481  }
482  if (cb_.size() == s1 && !secondSent) {
483  if (s2 > s1) {
484  // We got the first packet size, but we don't have a full packet.
485  int newsize = s2 - s1;
486  ROS_ERROR("Requesting Second Packet of size %i.", newsize);
487  request[2] = newsize;
488  request_pkt.Build(request, 4);
489  secondSent = true;
490  p2os_->SendReceive(&request_pkt, false);
491  } else {
492  // We got the first packet but don't have a full packet, this is an error.
493  ROS_ERROR("Got reply from AUX1 But don't have a full packet.");
494  break;
495  }
496  }
497 
498  // Keep reading data until we get a response from the camera.
499  p2os_->SendReceive(NULL, false);
500  }
501 }
502 
503 //
504 // Device Commands
505 //
507 {
508  unsigned char command[MAX_COMMAND_LENGTH];
509 
510  command[0] = HEADER;
511  command[1] = DEVICEID;
512  command[2] = DEVICEID;
513  command[3] = DELIM;
514  command[4] = POWER;
515  if (on) {
516  command[5] = DEVICEID + 1;
517  } else {
518  command[5] = DEVICEID;
519  }
520  command[6] = FOOTER;
521 
522  if (sendCommand(command, 7)) {
523  return -1;
524  }
525  if (bidirectional_com_) {
527  } else {
528  usleep(SLEEP_TIME_USEC);
529  return 0;
530  }
531 }
532 
534 {
535  unsigned char command[MAX_COMMAND_LENGTH];
536 
537  command[0] = HEADER;
538  command[1] = DEVICEID;
539  command[2] = DEVICEID;
540  command[3] = DELIM;
541  command[4] = CONTROL;
542  command[5] = DEVICEID;
543  command[6] = FOOTER;
544 
545  if (sendCommand(command, 7)) {
546  return -1;
547  }
548  if (bidirectional_com_) {
550  } else {
551  usleep(SLEEP_TIME_USEC);
552  return 0;
553  }
554 }
555 
557 {
558  unsigned char command[MAX_COMMAND_LENGTH];
559 
560  command[0] = HEADER;
561  command[1] = DEVICEID;
562  command[2] = DEVICEID;
563  command[3] = DELIM;
564  command[4] = INIT;
565  command[5] = DEVICEID;
566  command[6] = FOOTER;
567 
568  if (sendCommand(command, 7)) {
569  return -1;
570  }
571  if (bidirectional_com_) {
573  } else {
574  usleep(SLEEP_TIME_USEC);
575  return 0;
576  }
577 }
578 
579 int P2OSPtz::getMaxZoom(int * maxzoom)
580 {
581  unsigned char command[MAX_COMMAND_LENGTH];
582  unsigned char reply[MAX_REQUEST_LENGTH];
583  int reply_len;
584  char byte;
585  unsigned char buf[4];
586  unsigned int u_zoom;
587  int i;
588 
589  command[0] = HEADER;
590  command[1] = DEVICEID;
591  command[2] = DEVICEID;
592  command[3] = DELIM;
593  command[4] = ZOOMREQ;
594  command[5] = DEVICEID;
595  command[6] = FOOTER;
596 
597  if (sendCommand(command, 7)) {
598  return -1;
599  }
600  // usleep(5000000);
601  if (bidirectional_com_) {
602  reply_len = receiveRequestAnswer(reply, 10, 0);
603  } else {
604  return 0;
605  }
606 
607  if (reply_len == COMMAND_RESPONSE_BYTES) {
608  return -1;
609  }
610 
611  // remove the ascii encoding, and put into 2 bytes
612  for (i = 0; i < 4; i++) {
613  byte = reply[i + 5];
614  if (byte < 0x40) {
615  byte = byte - 0x30;
616  } else {
617  byte = byte - 'A' + 10;
618  }
619  buf[i] = byte;
620  }
621 
622  // convert the 2 bytes into a number
623  u_zoom = 0;
624  for (i = 0; i < 4; i++) {
625  u_zoom += buf[i] * static_cast<unsigned int>(pow(16.0, static_cast<double>(3 - i)));
626  }
627  *maxzoom = u_zoom;
628 
629  return 0;
630 }
631 int P2OSPtz::getAbsZoom(int * zoom)
632 {
633  unsigned char command[MAX_COMMAND_LENGTH];
634  unsigned char reply[MAX_REQUEST_LENGTH];
635  int reply_len;
636  char byte;
637  unsigned char buf[4];
638  unsigned int u_zoom;
639  int i;
640 
641  command[0] = HEADER;
642  command[1] = DEVICEID;
643  command[2] = DEVICEID;
644  command[3] = DELIM;
645  command[4] = ZOOMREQ;
646  command[5] = DEVICEID;
647  command[6] = FOOTER;
648 
649  if (sendRequest(command, 6, reply)) {
650  return -1;
651  }
652  if (bidirectional_com_) {
653  reply_len = receiveRequestAnswer(reply, 10, 0);
654  } else {
655  return 0;
656  }
657 
658  if (reply_len == COMMAND_RESPONSE_BYTES) {
659  return -1;
660  }
661 
662  // remove the ascii encoding, and put into 2 bytes
663  for (i = 0; i < 4; i++) {
664  byte = reply[i + 5];
665  if (byte < 0x40) {
666  byte = byte - 0x30;
667  } else {
668  byte = byte - 'A' + 10;
669  }
670  buf[i] = byte;
671  }
672 
673  // convert the 2 bytes into a number
674  u_zoom = 0;
675  for (i = 0; i < 4; i++) {
676  u_zoom += buf[i] * static_cast<unsigned int>(pow(16.0, static_cast<double>(3 - i)));
677  }
678  *zoom = u_zoom;
679  return 0;
680 }
681 
682 int P2OSPtz::sendAbsZoom(int zoom)
683 {
684  unsigned char command[MAX_COMMAND_LENGTH];
685  unsigned char buf[5];
686  int i;
687 
688  if (zoom < 0) {
689  zoom = 0;
690  } else if (zoom > max_zoom_) {
691  zoom = max_zoom_;
692  }
693 
694  command[0] = HEADER;
695  command[1] = DEVICEID;
696  command[2] = DEVICEID;
697  command[3] = DELIM;
698  command[4] = ZOOM;
699 
700  snprintf(reinterpret_cast<char *>(buf), sizeof(buf), "%4X", zoom);
701 
702  for (i = 0; i < 3; i++) {
703  if (buf[i] == ' ') {
704  buf[i] = '0';
705  }
706  }
707 
708  // zoom position
709  command[5] = buf[0];
710  command[6] = buf[1];
711  command[7] = buf[2];
712  command[8] = buf[3];
713  command[9] = FOOTER;
714 
715  zoom_ = zoom;
716 
717  if (sendCommand(command, 10)) {
718  return -1;
719  }
720  if (bidirectional_com_) {
722  } else {
723  usleep(SLEEP_TIME_USEC);
724  return 0;
725  }
726  // return (receiveCommandAnswer(COMMAND_RESPONSE_BYTES));
727 }
728 
730 {
731  unsigned char command[MAX_COMMAND_LENGTH];
732  unsigned char buf[5]; // 4 values and string terminator
733  int maxtilt, mintilt;
734 
735  command[0] = HEADER;
736  command[1] = DEVICEID;
737  command[2] = DEVICEID;
738  command[3] = DELIM;
739  command[4] = SETRANGE;
740  command[5] = DEVICEID + 1;
741 
742  mintilt = static_cast<int>(floor(MIN_TILT / .1125) + 0x8000);
743  snprintf(reinterpret_cast<char *>(buf), sizeof(buf), "%X", mintilt);
744  command[6] = buf[0];
745  command[7] = buf[1];
746  command[8] = buf[2];
747  command[9] = buf[3];
748  maxtilt = static_cast<int>(floor(MAX_TILT / .1125) + 0x8000);
749  snprintf(reinterpret_cast<char *>(buf), sizeof(buf), "%X", maxtilt);
750 
751  command[10] = buf[0];
752  command[11] = buf[1];
753  command[12] = buf[2];
754  command[13] = buf[3];
755  command[14] = FOOTER;
756 
757  if (sendCommand(command, 15)) {
758  return -1;
759  }
760  if (bidirectional_com_) {
762  } else {
763  usleep(SLEEP_TIME_USEC);
764  return 0;
765  }
766 
767  // return(receiveCommandAnswer(COMMAND_RESPONSE_BYTES));
768 }
769 
770 int P2OSPtz::getAbsPanTilt(int * pan, int * tilt)
771 {
772  unsigned char command[MAX_COMMAND_LENGTH];
773  unsigned char reply[MAX_REQUEST_LENGTH];
774  int reply_len;
775  unsigned char buf[4];
776  char byte;
777  unsigned int u_val;
778  int val;
779  int i;
780 
781  command[0] = HEADER;
782  command[1] = DEVICEID;
783  command[2] = DEVICEID;
784  command[3] = DELIM;
785  command[4] = PANTILTREQ;
786  command[5] = FOOTER;
787 
788  if (sendRequest(command, 6, reply)) {
789  return -1;
790  }
791  if (bidirectional_com_) {
792  reply_len = receiveRequestAnswer(reply, 14, 0);
793  } else {
794  return 0;
795  }
796 
797  if (reply_len != 14) {
798  ROS_ERROR("Reply Len = %i; should equal 14", reply_len);
799  return -1;
800  }
801 
802  // remove the ascii encoding, and put into 4-byte array
803  for (i = 0; i < 4; i++) {
804  byte = reply[i + 5];
805  if (byte < 0x40) {
806  byte = byte - 0x30;
807  } else {
808  byte = byte - 'A' + 10;
809  }
810  buf[i] = byte;
811  }
812 
813  // convert the 4-bytes into a number
814  u_val = buf[0] * 0x1000 + buf[1] * 0x100 + buf[2] * 0x10 + buf[3];
815 
816  // convert the number to a value that's meaningful, based on camera specs
817  val = static_cast<int>((static_cast<int>(u_val) - 0x8000) * 0.1125);
818 
819  // now set myPan to the response received for where the camera thinks it is
820  *pan = val;
821 
822  // repeat the steps for the tilt value
823  for (i = 0; i < 4; i++) {
824  byte = reply[i + 9];
825  if (byte < 0x40) {
826  byte = byte - 0x30;
827  } else {
828  byte = byte - 'A' + 10;
829  }
830  buf[i] = byte;
831  }
832  u_val = buf[0] * 0x1000 + buf[1] * 0x100 + buf[2] * 0x10 + buf[3];
833  val = static_cast<int>((static_cast<int>(u_val) - 0x8000) * 0.1125);
834  *tilt = val;
835 
836  return 0;
837 }
838 
839 int P2OSPtz::sendAbsPanTilt(int pan, int tilt)
840 {
841  unsigned char command[MAX_COMMAND_LENGTH];
842  int convpan, convtilt;
843  unsigned char buf[5];
844  int ppan, ttilt;
845 
846  ppan = pan; ttilt = tilt;
847  if (pan < MIN_PAN) {
848  ppan = static_cast<int>(MIN_PAN);
849  } else if (pan > MAX_PAN) {
850  ppan = static_cast<int>(MAX_PAN);
851  }
852 
853  if (tilt > MAX_TILT) {
854  ttilt = static_cast<int>(MAX_TILT);
855  } else if (tilt < MIN_TILT) {
856  ttilt = static_cast<int>(MIN_TILT);
857  }
858  // puts("Camera pan angle thresholded");
859 
860  // puts("Camera tilt angle thresholded");
861 
862  convpan = static_cast<int>(floor(ppan / .1125)) + 0x8000;
863  convtilt = static_cast<int>(floor(ttilt / .1125)) + 0x8000;
864  // fprintf(stdout, "ppan: %d ttilt: %d conpan: %d contilt: %d\n",
865  // ppan,ttilt,convpan,convtilt);
866  command[0] = HEADER;
867  command[1] = DEVICEID;
868  command[2] = DEVICEID;
869  command[3] = DELIM;
870  command[4] = PANTILT;
871  // pan position
872 
873  snprintf(reinterpret_cast<char *>(buf), sizeof(buf), "%X", convpan);
874 
875  command[5] = buf[0];
876  command[6] = buf[1];
877  command[7] = buf[2];
878  command[8] = buf[3];
879  // tilt position
880  snprintf(reinterpret_cast<char *>(buf), sizeof(buf), "%X", convtilt);
881  command[9] = buf[0];
882  command[10] = buf[1];
883  command[11] = buf[2];
884  command[12] = buf[3];
885  command[13] = (unsigned char) FOOTER;
886  if (sendCommand(command, 14)) {
887  return -1;
888  }
889 
890  tilt_ = ttilt;
891  pan_ = ppan;
892 
893  if (bidirectional_com_) {
895  } else {
896  usleep(SLEEP_TIME_USEC);
897  return 0;
898  }
899 
900  // return(receiveCommandAnswer(COMMAND_RESPONSE_BYTES));
901 }
902 
903 //
904 // Circular Buffer To deal with getting data back from AUX
905 //
907 : start(0), end(0), mysize(size), gotPack(false)
908 {
909  this->buf = new unsigned char[size];
910 }
911 
913 {
914  int i = start;
915  printf("circbuf: ");
916  while (i != end) {
917  printf("0x%x ", buf[i]);
918  i = (i + 1) % mysize;
919  }
920  printf("\n");
921 }
922 
923 
924 void circbuf::putOnBuf(unsigned char c)
925 {
926  buf[end] = c;
927  end = (end + 1) % mysize;
928  if (end == start) {
929  // We're overwriting old data.
930  start = (start + 1) % mysize;
931  }
932 
933  // Check to see if we have the whole packet now. (ends with FOOTER)
934  if (c == P2OSPtz::FOOTER) {
935  gotPack = true;
936  }
937 }
938 
940 {
941  return !(this->start == this->end);
942 }
943 
945 {
946  if (start != end) {
947  unsigned char ret = buf[start];
948  start = (start + 1) % mysize;
949  return static_cast<int>(ret);
950  } else {
951  return -1;
952  }
953 }
954 
956 {
957  if (end > start) {
958  return end - start;
959  } else if (start > end) {
960  return mysize - start - end - 1;
961  } else {
962  return 0;
963  }
964 }
965 
967 {
968  return gotPack;
969 }
970 
972 {
973  memset(buf, 0, mysize);
974  gotPack = false;
975  start = end = 0;
976 }
int getFromBuf()
Definition: p2os_ptz.cpp:944
int end
Definition: p2os_ptz.hpp:51
int max_zoom_
Definition: p2os_ptz.hpp:179
int size()
Definition: p2os_ptz.cpp:955
static const int MAX_COMMAND_LENGTH
Definition: p2os_ptz.hpp:187
bool gotPack
Definition: p2os_ptz.hpp:53
int SendReceive(P2OSPacket *pkt, bool publish_data=true)
Definition: p2os.cpp:688
int setControlMode()
Definition: p2os_ptz.cpp:533
P2OSPtz(P2OSNode *p2os, bool bidirectional_com=false)
Definition: p2os_ptz.cpp:40
void shutdown()
Definition: p2os_ptz.cpp:138
int setDefaultTiltRange()
Definition: p2os_ptz.cpp:729
P2OSNode * p2os_
Definition: p2os_ptz.hpp:173
bool gotPacket()
Definition: p2os_ptz.cpp:966
int error_code_
Definition: p2os_ptz.hpp:182
int sendCommand(unsigned char *str, int len)
Definition: p2os_ptz.cpp:202
int getAbsPanTilt(int *pan, int *tilt)
Definition: p2os_ptz.cpp:770
static const int PACKET_TIMEOUT
Definition: p2os_ptz.hpp:190
int receiveCommandAnswer(int asize)
Definition: p2os_ptz.cpp:274
bool bidirectional_com_
Definition: p2os_ptz.hpp:183
int mysize
Definition: p2os_ptz.hpp:52
void putOnBuf(unsigned char c)
Definition: p2os_ptz.cpp:924
circbuf cb_
Definition: p2os_ptz.hpp:176
int sendAbsZoom(int zoom)
Definition: p2os_ptz.cpp:682
#define ARGSTR
ROSLIB_DECL std::string command(const std::string &cmd)
int Build(unsigned char *data, unsigned char datasize)
Definition: packet.cpp:128
int setPower(Power on)
Definition: p2os_ptz.cpp:506
static const int TILT_THRESH
Definition: p2os_ptz.hpp:193
int zoom_
Definition: p2os_ptz.hpp:180
#define ROS_INFO(...)
#define ARGINT
void getPtzPacket(int s1, int s2=0)
Definition: p2os_ptz.cpp:457
static const int SLEEP_TIME_USEC
Definition: p2os_ptz.hpp:191
void callback(const p2os_msgs::PTZStateConstPtr &msg)
Definition: p2os_ptz.cpp:149
static const int COMMAND_RESPONSE_BYTES
Definition: p2os_ptz.hpp:189
int tilt_
Definition: p2os_ptz.hpp:180
int sendInit()
Definition: p2os_ptz.cpp:556
int sendAbsPanTilt(int pan, int tilt)
Definition: p2os_ptz.cpp:839
static const int PAN_THRESH
Definition: p2os_ptz.hpp:192
int receiveRequestAnswer(unsigned char *data, int s1, int s2)
Definition: p2os_ptz.cpp:372
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
int start
Definition: p2os_ptz.hpp:50
bool is_on_
Definition: p2os_ptz.hpp:181
static const int MAX_REQUEST_LENGTH
Definition: p2os_ptz.hpp:188
unsigned char * buf
Definition: p2os_ptz.hpp:49
INLINE Rall1d< T, V, S > abs(const Rall1d< T, V, S > &x)
bool haveData()
Definition: p2os_ptz.cpp:939
static const int ZOOM_THRESH
Definition: p2os_ptz.hpp:194
int getAbsZoom(int *zoom)
Definition: p2os_ptz.cpp:631
int setup()
Definition: p2os_ptz.cpp:55
int sendRequest(unsigned char *str, int len, unsigned char *reply)
Definition: p2os_ptz.cpp:237
void printBuf()
Definition: p2os_ptz.cpp:912
#define ROS_ERROR(...)
void reset()
Definition: p2os_ptz.cpp:971
int pan_
Definition: p2os_ptz.hpp:180
int getMaxZoom(int *max_zoom)
Definition: p2os_ptz.cpp:579
p2os_msgs::PTZState current_state_
Definition: p2os_ptz.hpp:184
#define ROS_DEBUG(...)
circbuf(int size=512)
Definition: p2os_ptz.cpp:906


p2os_driver
Author(s): Hunter L. Allen , David Feil-Seifer , Aris Synodinos , Brian Gerkey, Kasper Stoy, Richard Vaughan, Andrew Howard, Tucker Hermans, ActivMedia Robotics LLC, MobileRobots Inc.
autogenerated on Sat Jun 20 2020 03:29:42