Skip to content

Commit 9179fb2

Browse files
committed
added visa device handler for a PI C-633 Stepper Motor Controller
1 parent d10ac77 commit 9179fb2

1 file changed

Lines changed: 171 additions & 0 deletions

File tree

pyscada/visa/devices/PI_C-633.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from pyscada.visa.devices import GenericDevice
5+
from pyscada.models import VariableProperty
6+
from datetime import datetime
7+
from math import floor
8+
9+
import logging
10+
11+
logger = logging.getLogger(__name__)
12+
# -*- coding: utf-8 -*-
13+
"""Object based access to the PI C-633 Stepper Motor Controller
14+
15+
16+
Example::
17+
18+
unit = C633('ASRL/dev/ttyUSB0::INSTR')
19+
unit.connect()
20+
unit.disconnect()
21+
"""
22+
__author__ = "Martin Schröder"
23+
__copyright__ = "Copyright 2019, Technische Universität Berlin"
24+
__credits__ = []
25+
__license__ = "GPLv3"
26+
__version__ = "0.1.0"
27+
__maintainer__ = "Martin Schröder"
28+
__email__ = "m.schroeder@tu-berlin.de"
29+
__status__ = "Beta"
30+
__docformat__ = 'reStructuredText'
31+
32+
import pyvisa
33+
from datetime import datetime
34+
from math import floor
35+
from time import sleep, time
36+
37+
38+
class C633(object):
39+
_isconfigured = False
40+
pos_max = -1
41+
pos_min = -1
42+
43+
def __init__(self):
44+
self.instr = None
45+
46+
def connect(self, instr):
47+
if self.instr is None and instr is None:
48+
return
49+
self.instr = instr
50+
51+
def configure(self):
52+
logger.debug(self.instr.query('*IDN?'))
53+
logger.debug(self.instr.query('ERR?'))
54+
self.instr.write('SVO 1 1') # enable servo 1
55+
logger.debug(self.instr.query('SVO?'))
56+
logger.debug(self.instr.query('POS?'))
57+
self.instr.write('FNL 1') # reference move to lower limit
58+
timeout = time() + 10 # 10s timeout
59+
while self.instr.query('FRF?') != '1=1':
60+
sleep(0.1)
61+
logger.debug(self.instr.query('POS?'))
62+
if time() > timeout:
63+
return False
64+
self.pos_max = self.parse_value(self.instr.query('TMX?'))
65+
self.pos_min = self.parse_value(self.instr.query('TMN?'))
66+
self._isconfigured = True
67+
68+
def get_value(self,stage=1):
69+
pos_data = self.instr.query('POS?')
70+
return self.parse_value(pos_data, stage=stage)
71+
72+
def set_value(self,pos,stage=1):
73+
if not self._isconfigured:
74+
return False
75+
if pos > self.pos_max:
76+
return False
77+
if pos < self.pos_min:
78+
return False
79+
self.instr.write('MOV %d %1.8f'%(stage,pos))
80+
81+
def parse_value(self,str_data,stage=1):
82+
data = str_data.split('=')
83+
return float(data[-1])
84+
85+
def query(self,cmd):
86+
self.instr.timeout = 1000
87+
self.instr.write(cmd)
88+
data = []
89+
while True:
90+
d = self.instr.read()
91+
if d == '':
92+
break
93+
data.append(d)
94+
return data
95+
96+
from time import sleep
97+
class Handler(GenericDevice):
98+
"""
99+
C-633 and other Devices with the same command set
100+
"""
101+
smc = None
102+
def connect(self):
103+
#super(Handler, self).connect()
104+
super().connect()
105+
self.smc = C633()
106+
if self.inst is None:
107+
return
108+
try:
109+
logger.info(self.inst.query('*IDN?'))
110+
except:
111+
self.inst = None
112+
return
113+
self.smc.connect(self.inst)
114+
#for variable in self._variables.values():
115+
# data_type, channel = variable.visavariable.device_property.upper().split(';')
116+
# self.smc.set_channel(channel=channel, data_type=data_type)
117+
self.smc.configure()
118+
119+
def before_read(self):
120+
pass
121+
122+
def read_data(self,variable_instance):
123+
"""
124+
read values from the device
125+
"""
126+
if self.inst is None:
127+
return None
128+
if not self.smc._isconfigured:
129+
return None
130+
stage = int(variable_instance.visavariable.device_property.upper())
131+
return self.smc.get_value(stage)
132+
133+
134+
def write_data(self,variable_id, value, task):
135+
"""
136+
write values to the device
137+
"""
138+
variable = self._variables[variable_id]
139+
if task.variable_property is not None:
140+
# write the freq property to VariableProperty use that for later read
141+
vp = VariableProperty.objects.update_or_create_property(variable=variable, name=task.property_name.upper(),
142+
value=value, value_class='FLOAT64')
143+
return True
144+
if variable.visavariable.variable_type == 0: # configuration
145+
# only write to configuration variables
146+
stage = int(variable.visavariable.device_property.upper())
147+
self.smc.set_value(value,stage)
148+
return value
149+
else:
150+
return False
151+
152+
def parse_value(self,result):
153+
"""
154+
takes a string in the HP3456A format and returns a float value or None if not parseable
155+
"""
156+
try:
157+
i = 0
158+
value = result[i]
159+
"""
160+
timestamp = datetime(int(result[i+1]),
161+
int(result[i+2]),
162+
int(result[i+3]),
163+
int(result[i+4]),
164+
int(result[i+5]),
165+
int(floor(result[i+6])),
166+
int(round((result[i+6]%1)*1000))).timestamp()
167+
"""
168+
return value
169+
except:
170+
return None
171+

0 commit comments

Comments
 (0)