Examples¶
Controller Addresses¶
Use addresses() to see the different addresses that are available.
>>> import gclib
>>> print(addresses())
192.168.0.40, DMC4040 Rev 1.3i, 10601
COM5, DMC-41x3
GALILPCI0
If using an ethernet controller that doesn’t have an IP address yet, it will show up in ip_requests(). Use assign_ip() to give the controller an IP. If successful, the controller will begin showing up in addresses() under the new address.
>>> print(ip_requests())
00:50:4c:20:29:69, DMC4000, 10601
>>> assign_ip('00:50:4C:20:29:69', '192.168.0.40')
Connection Management¶
To use a controller with gclib, pass the address and an optional baud rate (for serial connections) to Controller() to receive a controller object.
>>> dmc = gclib.Controller('192.168.0.40')
Now we can see some basic info about the open connection.
>>> dmc.address()
'192.168.0.40'
>>> dmc.revision_information()
'DMC4040 Rev 1.3i'
>>> dmc.serial_number()
10601
Commands¶
To issue commands, use Controller.command() with an open connection.
>>> dmc.command('MG "Hello World"')
'Hello World'
Errors¶
If a gclib call is unsuccessful, an Error() exception will be thrown with a description of the error.
>>> dmc.command('invalid')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
dmc.command('invalid')
~~~~~~~~~~~^^^^^^^^^^^
gclib._ext.Error: Command "invalid" caused error code 1: The controller returned a question mark
Program & Arrays¶
Use Controller.program() to get the controller’s program, and use Controller.set_program() to set it.
>>> dmc.set_program('MG "Hello World"\nEN')
>>> print(dmc.program())
MG "Hello World"
EN
Use Controller.array() and Controller.set_array() similarly for arrays. Use the first and last arguments to transfer only part of the array.
>>> dmc.command('DM test[5]')
>>> dmc.set_array('test', '1, 2, 3, 4, 5', 0, 4)
>>> dmc.array('test', 1, 3)
'2.0000, 3.0000, 4.0000'
Unsolicited Data¶
Blocking¶
For synchronous usage, subscribe without providing a callback or user data pointer.
>>> dmc.subscribe_messages()
Once subscribed, you can then wait a specified amount of time for unsolicited data to arrive.
>>> dmc.message(1000) # Time out if message doesn't arrive within one second
Callback¶
For asynchronous usage, subscribe with a callback function. Each time unsolicited data arrives, your callback will be invoked.
>>> dmc.subscribe_messages(lambda message : print(message))
>>> dmc.command('XQ')
''
Hello World
Caution
The callback will be invoked on a separate thread. Be sure to protect any shared data!
>>> dmc.subscribe_messages(lambda message : print(f'Got message: "{message}"'))
>>> dmc.subscribe_interrupts(lambda interrupt : print(f'Got interrupt: {interrupt.type}'))
>>> dmc.subscribe_data_records(lambda data_record : (
print(f'Got data record, sample {data_record.sample()}'),
dmc.set_data_records(0),
))
>>> dmc.set_interrupts(Interrupt.ProgramStopped)
>>> dmc.set_program('WT 100; MG "Hello World"; EN')
>>> dmc.command('XQ')
>>> dmc.set_data_records(1000)
Got message: "Hello World"
Got interrupt: Type.ProgramStopped
For a full list of data record fields, see DataRecord.
Note
Controllers with default settings will not generate interrupts or data records. Use Controller.set_interrupts() and Controller.set_data_records() to configure your controller if needed.
Galil Connect¶
On the device hosting the remote gcaps server, use set_published().
>>> dmc.set_published('pi')
On the client, use list_servers() to view all available gcaps servers. Pass a server name to set_server() for future gclib calls to be routed through that gcaps server. When done, call set_server() with no arguments to disconnect from the remote gcaps server.
>>> list_servers()
'pi'
>>> set_server('pi')
>>> addresses()
'COM5'
>>> gclib.Controller("COM5").revision_info()
'DMC31010 Rev 1.4f'
>>> set_server()
Example Project: Record and Replay¶
The ‘Record’ example uses RA in continuous mode along with Controller.array() to allow recording movement for an arbitrary amount of time. It produces a file with the recorded positions of Axis A.
import gclib
import sys
import time
def main():
if (len(sys.argv) != 3):
print(f"Usage: record.py ADDRESS SECONDS", file=sys.stderr)
return
dmc = gclib.Controller(sys.argv[1])
try:
dmc.command('MO')
dmc.command('DM posA[1000]')
dmc.command('RA posA[]')
dmc.command('RD _TPA')
dmc.command('RC 1,-1000') # Assuming TM1000, record at 2ms intervals (1ms on DMC30010 / EDD37010 / RIO47000)
start = 0
end = -1
positions = None
start_time = time.time()
file = open("positions.txt", "w")
while (time.time() - start_time < float(sys.argv[2])):
time.sleep(0.5); # Assumes TM1000
end = int(float(dmc.command("MG_RD")))
positions = dmc.array('posA', start, (0 if end < start else end))
if end < start:
positions += ', ' + dmc.array('posA', 0, end)
positions = positions.replace(',', '\n')
file.write(positions + '\n')
start = end
file.close()
except gclib.Error as e:
print(e)
except OSError:
print('Failed to open positions.txt')
dmc.command("RC 0")
if __name__ == '__main__':
main()
The ‘Replay’ example uses the file produced by ‘Record’ along with CM to accurately reproduce the recorded movement. Note that axis A must be properly set up for motion.
import gclib
import sys
import time
def main():
if len(sys.argv) != 2:
print(f'Usage: replay.py ADDRESS', file=sys.stderr)
return 1
dmc = gclib.Controller(sys.argv[1])
try:
dmc.command('SH A')
dmc.command('CM A')
dmc.command('DT -1')
contour_space = int(float(dmc.command('MG_CM')))
f = open("positions.txt", "r")
last_position = None
for line in f.read().splitlines():
position = int(float(line))
if last_position:
movement = position - last_position
try:
dmc.command(f'CD {str(movement)}')
except gclib.Error:
if (dmc.command('TC1') != '32 Segment buffer full'):
raise
if (int(float(dmc.command('MG_DT'))) == -1):
dmc.command('DT 1')
time.sleep(0.1)
last_position = position
f.close()
while int(float(dmc.command('MG_CM'))) < contour_space:
time.sleep(0.5)
except gclib.Error as e:
print(e)
except OSError:
print('Failed to open positions.txt')
dmc.command('CD 0=0')
dmc.command('MO')
if __name__ == '__main__':
main()