-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcapacitivesCircles.py
217 lines (175 loc) · 8.71 KB
/
capacitivesCircles.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
from utime import ticks_ms
from _thread import allocate_lock
from mpr121 import MPR121
class CapacitivesCircles():
MAX_DELAY_INCR_DECR_MS = 1000
STEP_TRIGGER_INCR_DEGREE = [25, 10, 5]
NO_INCR_DECR_EVENT = 0
INNER_CIRCLE_INCR_EVENT = 1
INNER_CIRCLE_DECR_EVENT = 2
OUTER_CIRCLE_INCR_EVENT = 3
OUTER_CIRCLE_DECR_EVENT = 4
CALIBRATION_THRESHOLD = 10
def __init__(self, i2c, i2c_lock):
self.i2c = i2c
self.i2c_lock = i2c_lock
self.is_mpr_detected = 0x5A in self.i2c.scan()
if self.is_mpr_detected:
self.mpr = MPR121(self.i2c)
else:
self.mpr = None
# the circles are routed on the PCB for convenience and doesn't follow electrodes
# numbering, this list help to re-order everything
self.list_concordance_sensor = [5, 4, 3, 11, 10, 9, 8, 7, 6, 2, 1, 0]
self.last_inner_circle_angle = 0
self.last_outer_circle_angle = 0
self.inner_circle_angle = 0
self.outer_circle_angle = 0
self.last_inner_circle_angle_timestamp_ms = ticks_ms()
self.last_outer_circle_angle_timestamp_ms = ticks_ms()
self.touch_sensitivity_lock = allocate_lock()
self._touch_sensitivity = 1
self.flip_lock = allocate_lock()
self._flip = False
self.calibration_array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
if self.is_mpr_detected:
self.calibration_sensor()
@property
def flip(self):
to_return = 0
self.flip_lock.acquire()
to_return = self._flip
self.flip_lock.release()
return to_return
@flip.setter
def flip(self, flip):
self.flip_lock.acquire()
self._flip = flip
self.flip_lock.release()
@property
def touch_sensitivity(self):
to_return = 0
self.touch_sensitivity_lock.acquire()
to_return = self._touch_sensitivity
self.touch_sensitivity_lock.release()
return to_return
@touch_sensitivity.setter
def touch_sensitivity(self, touch_sensitivity):
self.touch_sensitivity_lock.acquire()
self._touch_sensitivity = touch_sensitivity
self.touch_sensitivity_lock.release()
# During calibration, do NOT touch the Capacitives Circles
def calibration_sensor(self):
for averaging_index in range(0, 16):
for i in range(0, 12):
if averaging_index < 8:
# read multiple the sensor and drop the data, at boot the filtered data are
self.mpr.filtered_data(i)
# not yet relevent
else:
self.calibration_array[i] = self.calibration_array[i] + \
self.mpr.filtered_data(i)
for i in range(0, 12):
self.calibration_array[i] = self.calibration_array[i]/8
def get_touch_circles_updates(self):
if self.is_mpr_detected:
local_touch_sensitivity = self.touch_sensitivity
datas = []
inner_circle_len = 0
outer_circle_len = 0
angle = 0
incr_decr_event = CapacitivesCircles.NO_INCR_DECR_EVENT
inner_angle_updated = False
outer_angle_updated = False
self.i2c_lock.acquire()
temp_data = self.mpr.all_filtered_data()
self.i2c_lock.release()
# if there is an error while reading the capacitive touch sensor, we return "0"
if temp_data == None:
return False, False, CapacitivesCircles.NO_INCR_DECR_EVENT, 0
for i in range(0, 12):
data = temp_data[i]
if data < (self.calibration_array[i]-CapacitivesCircles.CALIBRATION_THRESHOLD):
if self.list_concordance_sensor[i] < 6:
inner_circle_len += 1
else:
outer_circle_len += 1
datas.append((self.list_concordance_sensor[i], data))
datas = sorted(datas, key=lambda x: x[0])
if len(datas) > 1 and len(datas) < 4:
if inner_circle_len > outer_circle_len:
datas = [x for x in datas if x[0] < 6]
outer_circle_len = 0
else:
datas = [x for x in datas if x[0] > 5]
inner_circle_len = 0
elif len(datas) != 1:
datas = []
if len(datas) == 2:
sensor_distance = abs(datas[0][0] - datas[1][0])
if sensor_distance != 1 and sensor_distance != 5:
datas = []
if len(datas) > 0:
angle = 0
if inner_circle_len > 0:
index_factor_offset = 0
else:
index_factor_offset = 6
if len(datas) == 1:
angle = (datas[0][0]-index_factor_offset)*60
else:
indexes = [x[0] for x in datas]
if (0 in indexes and 5 in indexes) or (6 in indexes and 11 in indexes):
data_first_sensor = datas[1][1]
data_second_sensor = datas[0][1]
index_factor = datas[1][0] - index_factor_offset
else:
data_first_sensor = datas[0][1]
data_second_sensor = datas[1][1]
index_factor = datas[0][0] - index_factor_offset
# old angle computation, doesn't work well
# factor = (data_first_sensor-50)/(110-50)
# angle = index_factor*60 + factor*60
# if 0 in indexes and 1 in indexes:
difference = data_first_sensor - data_second_sensor
factor = (difference+90)/180
angle = index_factor*60 + factor*60
if self.flip == True:
angle = angle + 180
if inner_circle_len > 0:
if ticks_ms() - self.last_inner_circle_angle_timestamp_ms < CapacitivesCircles.MAX_DELAY_INCR_DECR_MS:
delta = self.last_inner_circle_angle-angle
# didn't put 360° in test but a little less to trigger it properly when passing from 360° to 0
# and vice versa
if (delta > CapacitivesCircles.STEP_TRIGGER_INCR_DEGREE[local_touch_sensitivity] and delta < 340) or delta < -340:
incr_decr_event = CapacitivesCircles.INNER_CIRCLE_INCR_EVENT
self.last_inner_circle_angle = angle
elif delta < -CapacitivesCircles.STEP_TRIGGER_INCR_DEGREE[local_touch_sensitivity] or delta > 340:
incr_decr_event = CapacitivesCircles.INNER_CIRCLE_DECR_EVENT
self.last_inner_circle_angle = angle
else:
# do this to prevent incr-decr when we touch the sensor after long time
self.last_inner_circle_angle = angle
self.inner_circle_angle = angle
self.last_inner_circle_angle_timestamp_ms = ticks_ms()
inner_angle_updated = True
else:
if ticks_ms() - self.last_outer_circle_angle_timestamp_ms < CapacitivesCircles.MAX_DELAY_INCR_DECR_MS:
delta = self.last_outer_circle_angle-angle
# didn't put 360° in test but a little less to trigger it properly when passing from 360° to 0
# and vice versa
if (delta > CapacitivesCircles.STEP_TRIGGER_INCR_DEGREE[local_touch_sensitivity] and delta < 340) or delta < -340:
incr_decr_event = CapacitivesCircles.OUTER_CIRCLE_INCR_EVENT
self.last_outer_circle_angle = angle
elif delta < -CapacitivesCircles.STEP_TRIGGER_INCR_DEGREE[local_touch_sensitivity] or delta > 340:
incr_decr_event = CapacitivesCircles.OUTER_CIRCLE_DECR_EVENT
self.last_outer_circle_angle = angle
else:
# do this to prevent incr-decr when we touch the sensor after long time
self.last_outer_circle_angle = angle
self.outer_circle_angle = angle
self.last_outer_circle_angle_timestamp_ms = ticks_ms()
outer_angle_updated = True
return inner_angle_updated, outer_angle_updated, incr_decr_event, angle
else:
return False, False, CapacitivesCircles.NO_INCR_DECR_EVENT, 0