/elec/quadcopter

To get this branch, use:
bzr branch http://bzr.ed.am/elec/quadcopter
19 by Tim Marston
added python GTK test program that reads and displays the serial data from the
1
#!/usr/bin/python
2
#
3
# rc-interface-test
4
5
6
import pygtk
7
pygtk.require( '2.0' );
8
import gtk, serial, struct
9
from io import BytesIO
10
11
12
class MainDialogue:
13
14
15
	# number of channels to read
16
	NUM_CHANNELS = 8
17
18
	# maximum channel value
19
	MAX_CHANNEL_VALUE = 1000
20
21
	# serial device to use
22
	SERIAL_DEVICE = '/dev/ttyACM0'
23
24
25
	def __init__( self ):
26
		self.link = serial.Serial( self.SERIAL_DEVICE, 9600 )
27
		self.got_one = False
28
		self.channel_values = []
29
		self.quit = False
30
		self.buffer = bytearray()
31
32
33
	def setup_window( self ):
34
35
		# create and set up window
36
		self.window = gtk.Window( gtk.WINDOW_TOPLEVEL )
37
		self.window.connect( "delete_event", self.destroy )
38
		self.window.connect( "destroy", self.destroy )
39
		self.window.set_title( "Testing rc-interface serial comms" );
40
		self.window.set_border_width( 30 )
41
		self.window.set_modal( True )
42
		self.window.connect( "key-press-event", self.key_press_event )
43
44
		# add widgets
45
		table = gtk.Table( self.NUM_CHANNELS, 2 )
46
		table.set_row_spacings( 20 )
47
		table.set_col_spacings( 10 )
48
		self.window.add( table )
49
50
		# add channels
51
		self.controls = []
52
		for a in range( 0, self.NUM_CHANNELS ):
53
54
			label = gtk.Label( "Channel %d" % ( a + 1 ) )
55
			table.attach( label, 0, 1, a, a + 1 )
56
57
			adj = gtk.Adjustment( 0, 0, self.MAX_CHANNEL_VALUE, 1, 0, 0 )
58
			control = gtk.HScale( adj )
59
			control.set_draw_value( False )
60
			control.set_property( 'width-request', 300 )
61
			control.set_sensitive( False )
62
			table.attach( control, 1, 2, a, a + 1 )
63
64
			self.controls.append( control )
65
66
		# show it
67
		self.window.show_all()
68
69
70
	def key_press_event( self, widget, event ):
71
		if event.keyval == gtk.keysyms.Escape:
72
			self.window.destroy()
73
		else:
74
			return False
75
76
77
	def destroy( self, widget, data = None ):
78
		self.quit = True
79
80
81
	def process_serial_data_at( self, pos ):
82
		for a in range( 0, self.NUM_CHANNELS ):
83
			at = 2 * a + pos
84
			value = struct.unpack( "h", self.buffer[ at : at + 2 ] )[ 0 ]
85
86
			# update control
87
			self.controls[ a ].set_value( value )
88
89
90
	def read_serial( self ):
91
92
		# try and read
93
		in_waiting = self.link.inWaiting()
94
		if( in_waiting ):
95
			self.buffer.extend( self.link.read( in_waiting ) )
96
97
			# check buffer for double -1
98
			got = bytearray()
99
			i = 0
100
			while i < len( self.buffer ):
101
102
				# check foir double -1
103
				if i > 0 and self.buffer[ i ] == 255 and \
104
						self.buffer[ i - 1 ] == 255:
105
106
					# if we've got enough data, process it
107
					start_index = i - ( self.NUM_CHANNELS * 2 + 1 )
108
					if start_index >= 0:
109
						self.process_serial_data_at( start_index )
110
111
					# remove everything up to and including this double -1 from
112
					# the serial buffer
113
					self.buffer = self.buffer[ i + 1 : ]
114
					i = 0
115
116
				else:
117
					i += 1
118
119
120
	def main( self ):
121
		self.setup_window()
122
		while not self.quit:
123
124
			# update gtk
125
			while gtk.events_pending():
126
				gtk.main_iteration( False )
127
128
			# check serial interface
129
			self.read_serial()
130
131
132
MainDialogue().main()