def __init__(self, hostname, username, password, flip, speed_control, frame_id="axis_camera", use_encrypted_password=False, state_publishing_frequency=50, camera_id=1): """Initialize the PTZ driver and start publishing positional data. :param hostname: Hostname of the camera (without http://, can be an IP address). :type hostname: basestring :param username: If login is needed, provide a username here. :type username: basestring|None :param password: If login is needed, provide a password here. :type password: basestring|None :param flip: Whether to flip the controls (for ceiling-mounted cameras). Deprecated. :type flip: bool :param speed_control: Use speed control instead of positional. Deprecated. :type speed_control: bool :param frame_id: Id of the frame in which positinal data should be published. :type frame_id: basestring :param use_encrypted_password: Whether to use Plain HTTP Auth (False) or Digest HTTP Auth (True). :type use_encrypted_password: bool :param state_publishing_frequency: The frequency at which joint states should be published. :type state_publishing_frequency: int :param camera_id: ID (number) of the camera. Can be 1 to 4. :type camera_id: int """ self._hostname = hostname self._camera_id = camera_id self._frame_id = frame_id self._state_publishing_frequency = state_publishing_frequency self._executing_reconfigure = False self._reconfigure_mutex = threading.Lock() self._api = None # autodetect the VAPIX API and connect to it; try it forever while self._api is None and not rospy.is_shutdown(): try: self._api = VAPIX.get_api_for_camera(hostname, username, password, camera_id, use_encrypted_password) except (IOError, ValueError): rospy.loginfo( "Retrying connection to VAPIX on host %s, camera %d in 2 seconds." % (hostname, camera_id)) rospy.sleep(2) if rospy.is_shutdown(): return if not self._api.has_ptz(): raise RuntimeError("Camera %d on host %s doesn't have a Pan-Tilt-Zoom unit." % (self._camera_id, self._hostname)) # Create a controller of the camera self._camera_controller = AxisCameraController(self._api, self, flip_vertically=flip, flip_horizontally=flip) # BACKWARDS COMPATIBILITY LAYER self.username = username # deprecated self.password = password # deprecated self.flip = flip # deprecated self.speedControl = speed_control # deprecated self.mirror = False # deprecated self.msg = None # deprecated self.cmdString = "" # deprecated self.pub = rospy.Publisher("state", Axis, queue_size=100) # deprecated self.command_subscriber = rospy.Subscriber("cmd", Axis, self.cmd, queue_size=100) # deprecated self.mirror_subscriber = rospy.Subscriber("mirror", Bool, self.mirrorCallback, queue_size=100) # deprecated self.srv = Server(PTZConfig, self.callback) # deprecated # Needs to be after the backwards compatibility setup # start the publisher thread self._publisher_thread = PositionStreamingThread(self, self._api) self.st = self._publisher_thread # deprecated self._publisher_thread.start()
class AxisPTZ: """This class is a node to manage the PTZ functions of an Axis PTZ camera. The most of its work is done by :py:class:`AxisCameraController <axis_camera.camera_control.AxisCameraController>` and this is just a ROS node envelope. """ def __init__(self, hostname, username, password, flip, speed_control, frame_id="axis_camera", use_encrypted_password=False, state_publishing_frequency=50, camera_id=1): """Initialize the PTZ driver and start publishing positional data. :param hostname: Hostname of the camera (without http://, can be an IP address). :type hostname: basestring :param username: If login is needed, provide a username here. :type username: basestring|None :param password: If login is needed, provide a password here. :type password: basestring|None :param flip: Whether to flip the controls (for ceiling-mounted cameras). Deprecated. :type flip: bool :param speed_control: Use speed control instead of positional. Deprecated. :type speed_control: bool :param frame_id: Id of the frame in which positinal data should be published. :type frame_id: basestring :param use_encrypted_password: Whether to use Plain HTTP Auth (False) or Digest HTTP Auth (True). :type use_encrypted_password: bool :param state_publishing_frequency: The frequency at which joint states should be published. :type state_publishing_frequency: int :param camera_id: ID (number) of the camera. Can be 1 to 4. :type camera_id: int """ self._hostname = hostname self._camera_id = camera_id self._frame_id = frame_id self._state_publishing_frequency = state_publishing_frequency self._executing_reconfigure = False self._reconfigure_mutex = threading.Lock() self._api = None # autodetect the VAPIX API and connect to it; try it forever while self._api is None and not rospy.is_shutdown(): try: self._api = VAPIX.get_api_for_camera(hostname, username, password, camera_id, use_encrypted_password) except (IOError, ValueError): rospy.loginfo( "Retrying connection to VAPIX on host %s, camera %d in 2 seconds." % (hostname, camera_id)) rospy.sleep(2) if rospy.is_shutdown(): return if not self._api.has_ptz(): raise RuntimeError("Camera %d on host %s doesn't have a Pan-Tilt-Zoom unit." % (self._camera_id, self._hostname)) # Create a controller of the camera self._camera_controller = AxisCameraController(self._api, self, flip_vertically=flip, flip_horizontally=flip) # BACKWARDS COMPATIBILITY LAYER self.username = username # deprecated self.password = password # deprecated self.flip = flip # deprecated self.speedControl = speed_control # deprecated self.mirror = False # deprecated self.msg = None # deprecated self.cmdString = "" # deprecated self.pub = rospy.Publisher("state", Axis, queue_size=100) # deprecated self.command_subscriber = rospy.Subscriber("cmd", Axis, self.cmd, queue_size=100) # deprecated self.mirror_subscriber = rospy.Subscriber("mirror", Bool, self.mirrorCallback, queue_size=100) # deprecated self.srv = Server(PTZConfig, self.callback) # deprecated # Needs to be after the backwards compatibility setup # start the publisher thread self._publisher_thread = PositionStreamingThread(self, self._api) self.st = self._publisher_thread # deprecated self._publisher_thread.start() # BACKWARDS COMPATIBILITY LAYER def cmd(self, message): """Deprecated.""" self.msg = message self.sanitisePTZCommands() if self._api.has_capabilities('AbsolutePan', 'AbsoluteTilt', 'AbsoluteZoom'): self._camera_controller.set_ptz(message.pan, message.tilt, message.zoom) else: rospy.loginfo("Camera on host %s doesn't support PTZ control." % self._hostname) if self._api.has_capability('AbsoluteFocus'): self._camera_controller.set_focus(message.focus, set_also_autofocus=False) else: rospy.loginfo("Camera on host %s doesn't support absolute focus control." % self._hostname) if self._api.has_capability('AutoFocus'): if message.focus != self._camera_controller._focus: self._camera_controller.set_autofocus(False) else: self._camera_controller.set_autofocus(message.autofocus) else: rospy.loginfo("Camera on host %s doesn't support autofocus." % self._hostname) if self._api.has_capability('AutoIris'): self._camera_controller.set_autoiris(True) else: rospy.loginfo("Camera on host %s doesn't support autoiris." % self._hostname) # there is no capability for brightness self._camera_controller.set_brightness(message.brightness) def adjustForFlippedOrientation(self): """Deprecated.""" self.msg.tilt = -self.msg.tilt if self.speedControl: self.msg.pan = -self.msg.pan else: self.msg.pan = 180.0 - self.msg.pan def sanitisePTZCommands(self): """Deprecated.""" if not self.speedControl: self.msg.pan = self._api.ptz_limits['Pan'].absolute.crop_value(self.msg.pan) self.msg.tilt = self._api.ptz_limits['Tilt'].absolute.crop_value(self.msg.tilt) self.msg.zoom = self._api.ptz_limits['Zoom'].absolute.crop_value(self.msg.zoom) self.msg.focus = self._api.ptz_limits['Focus'].absolute.crop_value(self.msg.focus) self.msg.brightness = self._api.ptz_limits['Brightness'].absolute.crop_value(self.msg.brightness) self.msg.iris = self._api.ptz_limits['Iris'].absolute.crop_value(self.msg.iris) else: self.msg.pan = self._api.ptz_limits['Pan'].velocity.crop_value(self.msg.pan) self.msg.tilt = self._api.ptz_limits['Tilt'].velocity.crop_value(self.msg.tilt) self.msg.zoom = self._api.ptz_limits['Zoom'].velocity.crop_value(self.msg.zoom) self.msg.focus = self._api.ptz_limits['Focus'].velocity.crop_value(self.msg.focus) self.msg.brightness = self._api.ptz_limits['Brightness'].velocity.crop_value(self.msg.brightness) self.msg.iris = self._api.ptz_limits['Iris'].velocity.crop_value(self.msg.iris) def sanitisePan(self): """Deprecated.""" if self.speedControl: self.msg.pan = self._api.ptz_limits['Pan'].velocity.crop_value(self.msg.pan) else: self.msg.pan = self._api.ptz_limits['Pan'].absolute.crop_value(self.msg.pan) def sanitiseTilt(self): """Deprecated.""" if self.speedControl: self.msg.tilt = self._api.ptz_limits['Tilt'].velocity.crop_value(self.msg.tilt) else: self.msg.tilt = self._api.ptz_limits['Tilt'].absolute.crop_value(self.msg.tilt) def sanitiseZoom(self): """Deprecated.""" if self.speedControl: self.msg.zoom = self._api.ptz_limits['Zoom'].velocity.crop_value(self.msg.zoom) else: self.msg.zoom = self._api.ptz_limits['Zoom'].absolute.crop_value(self.msg.zoom) def sanitiseFocus(self): """Deprecated.""" if self.speedControl: self.msg.focus = self._api.ptz_limits['Focus'].velocity.crop_value(self.msg.focus) else: self.msg.focus = self._api.ptz_limits['Focus'].absolute.crop_value(self.msg.focus) def sanitiseBrightness(self): """Deprecated.""" if self.speedControl: self.msg.brightness = self._api.ptz_limits['Brightness'].velocity.crop_value(self.msg.brightness) else: self.msg.brightness = self._api.ptz_limits['Brightness'].absolute.crop_value(self.msg.brightness) def sanitiseIris(self): """Deprecated.""" if self.msg.iris > 0.000001: rospy.logwarn("Iris value is read-only.") def applySetpoints(self): """Deprecated.""" """Apply the command to the camera using the HTTP API""" self._camera_controller.set_ptz(self.msg.pan, self.msg.tilt, self.msg.zoom) self._camera_controller.set_autofocus(self.msg.autofocus) if not self.msg.autofocus: self._camera_controller.set_focus(self.msg.focus) self._camera_controller.set_autoiris(True) self._camera_controller.set_brightness(self.msg.brightness) def createCmdString(self): """Deprecated.""" """Created tje HTTP API string to command PTZ camera""" self.cmdString = '/axis-cgi/com/ptz.cgi?' if self.speedControl: self.cmdString += 'continuouspantiltmove=%d,%d&' % (int(self.msg.pan), int(self.msg.tilt)) self.cmdString += 'continuouszoommove=%d&' % self.msg.zoom self.cmdString += 'continuousbrightnessmove=%d&' % self.msg.brightness # Note that brightness adjustment has no effect for Axis 214PTZ. if self.msg.autofocus: self.cmdString += 'autofocus=on&' else: self.cmdString += 'autofocus=off&continuousfocusmove=%d&' % self.msg.focus self.cmdString += 'autoiris=on' else: # position control: self.cmdString += 'pan=%f&tilt=%f&' % (self.msg.pan, self.msg.tilt) self.cmdString += 'zoom=%d&' % self.msg.zoom self.cmdString += 'brightness=%d&' % self.msg.brightness if self.msg.autofocus: self.cmdString += 'autofocus=on&' else: self.cmdString += 'autofocus=off&focus=%d&' % self.msg.focus self.cmdString += 'autoiris=on' def mirrorCallback(self, msg): """Deprecated.""" '''Command the camera with speed control or position control commands''' self.mirror = msg.data self._camera_controller.mirror_horizontally = self.mirror def callback(self, config, level): """Deprecated.""" #self.speedControl = config.speed_control if self._executing_reconfigure or (hasattr(self, '_camera_controller') and (self._camera_controller._executing_parameter_update or self._camera_controller._executing_reconfigure)): return config with self._reconfigure_mutex: self._executing_reconfigure = True # create temporary message and fill with data from dynamic reconfigure command = Axis() command.pan = config.pan command.tilt = config.tilt command.zoom = config.zoom command.focus = config.focus command.brightness = config.brightness command.autofocus = config.autofocus # check sanity and apply values self.cmd(command) # read sanitized values and update GUI config.pan = command.pan config.tilt = command.tilt config.zoom = command.zoom config.focus = self._camera_controller._focus config.brightness = self._camera_controller._brightness config.autofocus = self._camera_controller._autofocus self._executing_reconfigure = False # update GUI with sanitized values return config