Reputation: 51
I am developing an application in Python to control ONVIF-compatible cameras.
Software: Debian Wheezy, Python 2.7, Quatanium python-onvif client
Hardware: Raspberry Pi 2 B, IP camera on local router, wifi/VNC for development
The required PTZ functions include Absolute Move, Relative Move, Continuous Move, Stop and using Preset positions. With the extracted test code below, I have all of that working except Absolute and Relative Moves. All of this code executes without any errors but the camera does not move for the Absolute or Relative Moves. I hope someone can suggest the problem with those two functions. The example is a bit long but I have tried to include enough code to show the contrast between working and non-working (with upper-case comments) portions for reference and test.
A test sketch:
#!/usr/bin/python
#-------------------------------------------------------------------------------
#Test of Python and Quatanium Python-ONVIF with NETCAT camera PT-PTZ2087
#ONVIF Client implementation is in Python
#For IP control of PTZ, the camera should be compliant with ONVIF Profile S
#The PTZ2087 reports it is ONVIF 2.04 but is actually 2.4 (Netcat said text not changed after upgrade)
#------------------------------------------------------------------------------
import onvifconfig
if __name__ == '__main__':
#Do all setup initializations
ptz = onvifconfig.ptzcam()
#*****************************************************************************
# IP camera motion tests
#*****************************************************************************
print 'Starting tests...'
#Set preset
ptz.move_pan(1.0, 1) #move to a new home position
ptz.set_preset('home')
# move right -- (velocity, duration of move)
ptz.move_pan(1.0, 2)
# move left
ptz.move_pan(-1.0, 2)
# move down
ptz.move_tilt(-1.0, 2)
# Move up
ptz.move_tilt(1.0, 2)
# zoom in
ptz.zoom(8.0, 2)
# zoom out
ptz.zoom(-8.0, 2)
#Absolute pan-tilt (pan position, tilt position, velocity)
#DOES NOT RESULT IN CAMERA MOVEMENT
ptz.move_abspantilt(-1.0, 1.0, 1.0)
ptz.move_abspantilt(1.0, -1.0, 1.0)
#Relative move (pan increment, tilt increment, velocity)
#DOES NOT RESULT IN CAMERA MOVEMENT
ptz.move_relative(0.5, 0.5, 8.0)
#Get presets
ptz.get_preset()
#Go back to preset
ptz.goto_preset('home')
exit()
The referenced class:
#*****************************************************************************
#IP Camera control
#Control methods:
# rtsp video streaming via OpenCV for frame capture
# ONVIF for PTZ control
# ONVIF for setup selections
#
# Starting point for this code was from:
# https://github.com/quatanium/python-onvif
#*****************************************************************************
import sys
sys.path.append('/usr/local/lib/python2.7/dist-packages/onvif')
from onvif import ONVIFCamera
from time import sleep
class ptzcam():
def __init__(self):
print 'IP camera initialization'
#Several cameras that have been tried -------------------------------------
#Netcat camera (on my local network) Port 8899
self.mycam = ONVIFCamera('192.168.1.10', 8899, 'admin', 'admin', '/etc/onvif/wsdl/')
#This is a demo camera that anyone can use for testing
#Toshiba IKS-WP816R
#self.mycam = ONVIFCamera('67.137.21.190', 80, 'toshiba', 'security', '/etc/onvif/wsdl/')
print 'Connected to ONVIF camera'
# Create media service object
self.media = self.mycam.create_media_service()
print 'Created media service object'
print
# Get target profile
self.media_profile = self.media.GetProfiles()[0]
# Use the first profile and Profiles have at least one
token = self.media_profile._token
#PTZ controls -------------------------------------------------------------
print
# Create ptz service object
print 'Creating PTZ object'
self.ptz = self.mycam.create_ptz_service()
print 'Created PTZ service object'
print
#Get available PTZ services
request = self.ptz.create_type('GetServiceCapabilities')
Service_Capabilities = self.ptz.GetServiceCapabilities(request)
print 'PTZ service capabilities:'
print Service_Capabilities
print
#Get PTZ status
status = self.ptz.GetStatus({'ProfileToken':token})
print 'PTZ status:'
print status
print 'Pan position:', status.Position.PanTilt._x
print 'Tilt position:', status.Position.PanTilt._y
print 'Zoom position:', status.Position.Zoom._x
print 'Pan/Tilt Moving?:', status.MoveStatus.PanTilt
print
# Get PTZ configuration options for getting option ranges
request = self.ptz.create_type('GetConfigurationOptions')
request.ConfigurationToken = self.media_profile.PTZConfiguration._token
ptz_configuration_options = self.ptz.GetConfigurationOptions(request)
print 'PTZ configuration options:'
print ptz_configuration_options
print
self.requestc = self.ptz.create_type('ContinuousMove')
self.requestc.ProfileToken = self.media_profile._token
self.requesta = self.ptz.create_type('AbsoluteMove')
self.requesta.ProfileToken = self.media_profile._token
print 'Absolute move options'
print self.requesta
print
self.requestr = self.ptz.create_type('RelativeMove')
self.requestr.ProfileToken = self.media_profile._token
print 'Relative move options'
print self.requestr
print
self.requests = self.ptz.create_type('Stop')
self.requests.ProfileToken = self.media_profile._token
self.requestp = self.ptz.create_type('SetPreset')
self.requestp.ProfileToken = self.media_profile._token
self.requestg = self.ptz.create_type('GotoPreset')
self.requestg.ProfileToken = self.media_profile._token
print 'Initial PTZ stop'
print
self.stop()
#Stop pan, tilt and zoom
def stop(self):
self.requests.PanTilt = True
self.requests.Zoom = True
print 'Stop:'
#print self.requests
print
self.ptz.Stop(self.requests)
print 'Stopped'
#Continuous move functions
def perform_move(self, timeout):
# Start continuous move
ret = self.ptz.ContinuousMove(self.requestc)
print 'Continuous move completed', ret
# Wait a certain time
sleep(timeout)
# Stop continuous move
self.stop()
sleep(2)
print
def move_tilt(self, velocity, timeout):
print 'Move tilt...', velocity
self.requestc.Velocity.PanTilt._x = 0.0
self.requestc.Velocity.PanTilt._y = velocity
self.perform_move(timeout)
def move_pan(self, velocity, timeout):
print 'Move pan...', velocity
self.requestc.Velocity.PanTilt._x = velocity
self.requestc.Velocity.PanTilt._y = 0.0
self.perform_move(timeout)
def zoom(self, velocity, timeout):
print 'Zoom...', velocity
self.requestc.Velocity.Zoom._x = velocity
self.perform_move(timeout)
#Absolute move functions --NO ERRORS BUT CAMERA DOES NOT MOVE
def move_abspantilt(self, pan, tilt, velocity):
self.requesta.Position.PanTilt._x = pan
self.requesta.Position.PanTilt._y = tilt
self.requesta.Speed.PanTilt._x = velocity
self.requesta.Speed.PanTilt._y = velocity
print 'Absolute move to:', self.requesta.Position
print 'Absolute speed:',self.requesta.Speed
ret = self.ptz.AbsoluteMove(self.requesta)
print 'Absolute move pan-tilt requested:', pan, tilt, velocity
sleep(2.0)
print 'Absolute move completed', ret
print
#Relative move functions --NO ERRORS BUT CAMERA DOES NOT MOVE
def move_relative(self, pan, tilt, velocity):
self.requestr.Translation.PanTilt._x = pan
self.requestr.Translation.PanTilt._y = tilt
self.requestr.Speed.PanTilt._x = velocity
ret = self.requestr.Speed.PanTilt._y = velocity
self.ptz.RelativeMove(self.requestr)
print 'Relative move pan-tilt', pan, tilt, velocity
sleep(2.0)
print 'Relative move completed', ret
print
#Sets preset set, query and and go to
def set_preset(self, name):
self.requestp.PresetName = name
self.requestp.PresetToken = '1'
self.preset = self.ptz.SetPreset(self.requestp) #returns the PresetToken
print 'Set Preset:'
print self.preset
print
def get_preset(self):
self.ptzPresetsList = self.ptz.GetPresets(self.requestc)
print 'Got preset:'
print self.ptzPresetsList[0]
print
def goto_preset(self, name):
self.requestg.PresetToken = '1'
self.ptz.GotoPreset(self.requestg)
print 'Going to Preset:'
print name
print
@Ottavio, Sorry that I did not make it clear that the camera I used for this test, a Netcat PT-PTZ2084XM-A reported via ONVIF query that it did support Absolute and Relative moves. I have subsequently verified via the onvif.org site that this camera has not been tested and verified to meet onvif standards. I also have verified that the above code does work correctly with a Amcrest IP2M-841B ptz camera. The upshot of all of this is to never trust the claim that a camera is ONVIF 2.x compatible without testing it. Even the Amcrest has problems with both ONVIF and cgi commands for zoom. Neither Netcat nor Amcrest have been very helpful in resolving these technical problems.
Upvotes: 5
Views: 26144
Reputation: 4168
AbsoluteMake
and RelativeMove
in the Profile S specifications are CONDITIONAL MANDATORY
, thus it is not guaranteed a-priori that they are supported.
You need to check the camera's features.
Upvotes: 2