Skip to content

Commit 06fa130

Browse files
committed
Merge remote-tracking branch 'refs/remotes/origin/dev' into wheels-pos-ack
2 parents 5b91e51 + d06cd42 commit 06fa130

File tree

3 files changed

+231
-18
lines changed

3 files changed

+231
-18
lines changed

arduino_alvik/arduino_alvik.py

Lines changed: 204 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def __new__(cls):
2626
return cls._instance
2727

2828
def __init__(self):
29+
self.i2c = _ArduinoAlvikI2C(A4, A5)
2930
self._packeter = ucPack(200)
3031
self.left_wheel = _ArduinoAlvikWheel(self._packeter, ord('L'), alvik=self)
3132
self.right_wheel = _ArduinoAlvikWheel(self._packeter, ord('R'), alvik=self)
@@ -100,54 +101,66 @@ def _progress_bar(percentage: float) -> None:
100101
word = marks_str + f" {percentage}% \t"
101102
sys.stdout.write(bytes((word.encode('utf-8'))))
102103

103-
def _idle(self, delay_=1, check_on_thread=False) -> None:
104+
def _lenghty_op(self, iterations=10000000) -> int:
105+
result = 0
106+
for i in range(1, iterations):
107+
result += i * i
108+
return result
109+
110+
def _idle(self, delay_=1, check_on_thread=False, blocking=False) -> None:
104111
"""
105112
Alvik's idle mode behaviour
106113
:return:
107114
"""
108-
109115
NANO_CHK.value(1)
110-
sleep_ms(500)
116+
self.i2c.set_single_thread(True)
117+
118+
if blocking:
119+
self._lenghty_op(50000)
120+
else:
121+
sleep_ms(500)
111122
led_val = 0
112123

113124
try:
114125
while not self.is_on():
126+
115127
if check_on_thread and not self.__class__._update_thread_running:
116128
break
117-
_ESP32_SDA = Pin(A4, Pin.OUT)
118-
_ESP32_SCL = Pin(A5, Pin.OUT)
119-
_ESP32_SCL.value(1)
120-
_ESP32_SDA.value(1)
121-
sleep_ms(100)
122-
_ESP32_SCL.value(0)
123-
_ESP32_SDA.value(0)
124129

125130
cmd = bytearray(1)
126131
cmd[0] = 0x06
127-
i2c = I2C(0, scl=ESP32_SCL, sda=ESP32_SDA)
128-
i2c.writeto(0x36, cmd)
129-
soc_raw = struct.unpack('h', i2c.readfrom(0x36, 2))[0]
132+
133+
self.i2c.start()
134+
self.i2c.writeto(0x36, cmd)
135+
136+
soc_raw = struct.unpack('h', self.i2c.readfrom(0x36, 2))[0]
130137
soc_perc = soc_raw * 0.00390625
131138
self._progress_bar(round(soc_perc))
132-
sleep_ms(delay_)
139+
if blocking:
140+
self._lenghty_op(10000)
141+
else:
142+
sleep_ms(delay_)
133143
if soc_perc > 97:
134144
LEDG.value(0)
135145
LEDR.value(1)
136146
else:
137147
LEDR.value(led_val)
138148
LEDG.value(1)
139149
led_val = (led_val + 1) % 2
140-
print("********** Alvik is on **********")
150+
self.i2c.set_single_thread(False)
151+
if self.is_on():
152+
print("********** Alvik is on **********")
141153
except KeyboardInterrupt:
142154
self.stop()
143155
sys.exit()
144156
except Exception as e:
145157
pass
146-
# print(f'Unable to read SOC: {e}')
158+
print(f'Unable to read SOC: {e}')
147159
finally:
148160
LEDR.value(1)
149161
LEDG.value(1)
150162
NANO_CHK.value(0)
163+
self.i2c.set_single_thread(False)
151164

152165
@staticmethod
153166
def _snake_robot(duration: int = 1000):
@@ -184,6 +197,7 @@ def begin(self) -> int:
184197
if not self.is_on():
185198
print("\n********** Please turn on your Arduino Alvik! **********\n")
186199
sleep_ms(1000)
200+
self.i2c.set_main_thread(_thread.get_ident())
187201
self._idle(1000)
188202
self._begin_update_thread()
189203

@@ -584,6 +598,9 @@ def _update(self, delay_=1):
584598
:param delay_: while loop delay (ms)
585599
:return:
586600
"""
601+
602+
self.i2c.set_main_thread(_thread.get_ident())
603+
587604
while True:
588605
if not self.is_on():
589606
print("Alvik is off")
@@ -1254,6 +1271,177 @@ def _stop_events_thread(cls):
12541271
cls._events_thread_running = False
12551272

12561273

1274+
class _ArduinoAlvikI2C:
1275+
1276+
_main_thread_id = None
1277+
1278+
def __init__(self, sda: int, scl: int):
1279+
"""
1280+
Alvik I2C wrapper
1281+
:param sda:
1282+
:param scl:
1283+
"""
1284+
self._lock = _thread.allocate_lock()
1285+
1286+
self._is_single_thread = False
1287+
1288+
self.sda = sda
1289+
self.scl = scl
1290+
1291+
def set_main_thread(self, thread_id: int):
1292+
"""
1293+
Sets the main thread of control. It will be the only thread allowed if set_single_thread is True
1294+
"""
1295+
with self._lock:
1296+
self.__class__._main_thread_id = thread_id
1297+
1298+
def set_single_thread(self, value):
1299+
"""
1300+
Sets the single thread mode on/off.
1301+
In single mode only the main thread is allowed to access the bus
1302+
"""
1303+
self._is_single_thread = value
1304+
1305+
def is_accessible(self):
1306+
"""
1307+
Returns True if bus is accessible by the current thread
1308+
"""
1309+
return not self._is_single_thread or _thread.get_ident() == self.__class__._main_thread_id
1310+
1311+
def start(self):
1312+
"""
1313+
Bitbanging start condition
1314+
:return:
1315+
"""
1316+
_SDA = Pin(self.sda, Pin.OUT)
1317+
_SDA.value(1)
1318+
sleep_ms(100)
1319+
_SDA.value(0)
1320+
1321+
def init(self, scl, sda, freq=400_000) -> None:
1322+
"""
1323+
init method just for call compatibility
1324+
"""
1325+
print("AlvikWarning:: init Unsupported. Alvik defines/initializes its own I2C bus")
1326+
1327+
def deinit(self):
1328+
"""
1329+
deinit method just for call compatibility
1330+
"""
1331+
print("AlvikWarning:: deinit Unsupported. Alvik defines/initializes its own I2C bus")
1332+
1333+
def stop(self):
1334+
""" Bitbanging stop condition (untested)
1335+
:return:
1336+
"""
1337+
_SDA = Pin(self.sda, Pin.OUT)
1338+
_SDA.value(0)
1339+
sleep_ms(100)
1340+
_SDA.value(1)
1341+
1342+
def scan(self) -> list[int]:
1343+
"""
1344+
I2C scan method
1345+
:return:
1346+
"""
1347+
if not self.is_accessible():
1348+
return []
1349+
with self._lock:
1350+
i2c = I2C(0, scl=Pin(self.scl, Pin.OUT), sda=Pin(self.sda, Pin.OUT))
1351+
return i2c.scan()
1352+
1353+
def readfrom(self, addr, nbytes, stop=True) -> bytes:
1354+
"""
1355+
Wrapping i2c readfrom
1356+
"""
1357+
if not self.is_accessible():
1358+
return bytes(nbytes)
1359+
with self._lock:
1360+
i2c = I2C(0, scl=Pin(self.scl, Pin.OUT), sda=Pin(self.sda, Pin.OUT))
1361+
return i2c.readfrom(addr, nbytes, stop)
1362+
1363+
def writeto(self, addr, buf, stop=True) -> int:
1364+
"""
1365+
Wrapping i2c writeto
1366+
"""
1367+
if not self.is_accessible():
1368+
return 0
1369+
with self._lock:
1370+
i2c = I2C(0, scl=Pin(self.scl, Pin.OUT), sda=Pin(self.sda, Pin.OUT))
1371+
return i2c.writeto(addr, buf, stop)
1372+
1373+
def readinto(self, buf, nack=True) -> None:
1374+
"""
1375+
Wrapping i2c readinto
1376+
"""
1377+
if not self.is_accessible():
1378+
return
1379+
with self._lock:
1380+
i2c = I2C(0, scl=Pin(self.scl, Pin.OUT), sda=Pin(self.sda, Pin.OUT))
1381+
return i2c.readinto(buf, nack)
1382+
1383+
def write(self, buf) -> int:
1384+
"""
1385+
Wrapping i2c write
1386+
"""
1387+
if not self.is_accessible():
1388+
return 0
1389+
with self._lock:
1390+
i2c = I2C(0, scl=Pin(self.scl, Pin.OUT), sda=Pin(self.sda, Pin.OUT))
1391+
return i2c.write(buf)
1392+
1393+
def readfrom_into(self, addr, buf, stop=True) -> None:
1394+
"""
1395+
Wrapping i2c readfrom_into
1396+
"""
1397+
if not self.is_accessible():
1398+
return
1399+
with self._lock:
1400+
i2c = I2C(0, scl=Pin(self.scl, Pin.OUT), sda=Pin(self.sda, Pin.OUT))
1401+
return i2c.readfrom_into(addr, buf, stop)
1402+
1403+
def writevto(self, addr, vector, stop=True) -> int:
1404+
"""
1405+
Wrapping i2c writevto
1406+
"""
1407+
if not self.is_accessible():
1408+
return 0
1409+
with self._lock:
1410+
i2c = I2C(0, scl=Pin(self.scl, Pin.OUT), sda=Pin(self.sda, Pin.OUT))
1411+
return i2c.writevto(addr, vector, stop)
1412+
1413+
def readfrom_mem(self, addr, memaddr, nbytes, addrsize=8) -> bytes:
1414+
"""
1415+
Wrapping i2c readfrom_mem
1416+
"""
1417+
if not self.is_accessible():
1418+
return bytes(nbytes)
1419+
with self._lock:
1420+
i2c = I2C(0, scl=Pin(self.scl, Pin.OUT), sda=Pin(self.sda, Pin.OUT))
1421+
return i2c.readfrom_mem(addr, memaddr, nbytes, addrsize=addrsize)
1422+
1423+
def readfrom_mem_into(self, addr, memaddr, buf, addrsize=8) -> None:
1424+
"""
1425+
Wrapping i2c readfrom_mem_into
1426+
"""
1427+
if not self.is_accessible():
1428+
return
1429+
with self._lock:
1430+
i2c = I2C(0, scl=Pin(self.scl, Pin.OUT), sda=Pin(self.sda, Pin.OUT))
1431+
return i2c.readfrom_mem_into(addr, memaddr, buf, addrsize=addrsize)
1432+
1433+
def writeto_mem(self, addr, memaddr, buf, addrsize=8) -> None:
1434+
"""
1435+
Wrapping i2c writeto_mem
1436+
"""
1437+
if not self.is_accessible():
1438+
return
1439+
with self._lock:
1440+
i2c = I2C(0, scl=Pin(self.scl, Pin.OUT), sda=Pin(self.sda, Pin.OUT))
1441+
return i2c.writeto_mem(addr, memaddr, buf, addrsize=addrsize)
1442+
1443+
1444+
12571445
class _ArduinoAlvikServo:
12581446

12591447
def __init__(self, packeter: ucPack, label: str, servo_id: int, position: list[int | None]):

arduino_alvik/pinout_definitions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
RESET_STM32 = Pin(D3, Pin.OUT) # nano D3 -> STM32 NRST
1414
NANO_CHK = Pin(D4, Pin.OUT) # nano D4 -> STM32 NANO_CHK
1515
CHECK_STM32 = Pin(A6, Pin.IN, Pin.PULL_DOWN) # nano A6/D23 -> STM32 ROBOT_CHK
16-
ESP32_SDA = Pin(A4, Pin.OUT) # ESP32_SDA
17-
ESP32_SCL = Pin(A5, Pin.OUT) # ESP32_SCL
16+
# ESP32_SDA = Pin(A4, Pin.OUT) # ESP32_SDA
17+
# ESP32_SCL = Pin(A5, Pin.OUT) # ESP32_SCL
1818

1919
# LEDS
2020
LEDR = Pin(46, Pin.OUT) #RED ESP32 LEDR

examples/i2c_scan.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from time import sleep_ms
2+
import sys
3+
4+
from arduino_alvik import ArduinoAlvik
5+
6+
alvik = ArduinoAlvik()
7+
alvik.begin()
8+
9+
sleep_ms(1000)
10+
11+
while True:
12+
try:
13+
out = alvik.i2c.scan()
14+
15+
if len(out) == 0:
16+
print("\nNo device found on I2C")
17+
else:
18+
print("\nList of devices")
19+
for o in out:
20+
print(hex(o))
21+
22+
sleep_ms(100)
23+
except KeyboardInterrupt as e:
24+
alvik.stop()
25+
sys.exit()

0 commit comments

Comments
 (0)