CocoPi.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. '''
  2. =========================================================
  3. ______ ______
  4. /\ _ \ /\ _ \ __
  5. \ \ \/\_\ ____ ____ ___\ \ \_\ \/\_\
  6. \ \ \/_/_ / __ \ / __ \ / __'\ \ __/\/_/_
  7. \ \ \_\ \/\ \_\ \/\ \__//\ \_\ \ \ \/ /\ \
  8. \ \____/\ \____/\ \____\ \____/\ \_\ \ \_\
  9. \/___/ \/___/ \/____/\/___/ \/_/ \/_/
  10. __
  11. /\ \ __ ----------------
  12. \ \ \ /\_\ ____ __ __ __ _ pi.cocorobo.hk
  13. \ \ \ \/_/_ / _ \/\ \/\ \/\ \/ \ ----------------
  14. \ \ \____ /\ \/\ \/\ \ \ \_\ \/> </ SYSTEM VERSION
  15. \ \_____\\ \_\ \_\ \_\ \____//\_/\_\ -- 23.06.01 ---
  16. \/_____/ \/_/\/_/\/_/\/___/ \//\/_/ ----------------
  17. =========================================================
  18. '''
  19. #########################################################
  20. # ------------------------------------------------------
  21. #| 封装包内容: | 类名称: |
  22. #|-------------------------------|----------------------|
  23. #| 2023.02.16: | |
  24. #| 【添加】 | |
  25. #| 1、AHT20温湿度传感器 | AHT20 |
  26. #| 2、MPU6050陀螺仪六轴传感器 | MPU6050 |
  27. #| 3、板载4颗按钮A、B、C、D | BUTTON |
  28. #| 4、光线强度传感器 | LIGHTINTENSITY |
  29. #| 5、板载LED灯! | LED |
  30. #| 6、直流电机 | DCMOTOR |
  31. #| 7、模拟舵机 | SERVO |
  32. #|------------------------------------------------------|
  33. #| 2023.02.27: | |
  34. #| 【修复完善】 | BUTTON、LED |
  35. #| 【添加】 | WIFI |
  36. #|------------------------------------------------------|
  37. #| 2023.03.09: | |
  38. #| 【修复完善】 | LED |
  39. #|------------------------------------------------------|
  40. #| 2023.03.14: | |
  41. #| 【修复完善】 | SERVO |
  42. #|-------------------------------------------------------
  43. #| 2023.06.01: | |
  44. #| 【替换】 | BUTTON |
  45. #| 【替换】 | LED |
  46. #| 【替换】 | DCMOTOR |
  47. #| 【替换】 | SERVO |
  48. #| 【添加】 | RGB |
  49. #| 【添加】 | ADC |
  50. #| 【添加】 | DAC |
  51. #| 【添加】 | INPUT |
  52. #| 【添加】 | OUT |
  53. #| 【添加】 | UvcVideo |
  54. #|-------------------------------------------------------
  55. #| 2023.06.15: | |
  56. #| 【更改】 | STM8S |
  57. #|-------------------------------------------------------
  58. #########################################################
  59. from smbus2 import SMBus
  60. import time
  61. import math
  62. from maix import gpio
  63. import os
  64. import SUNXI_GPIO
  65. from maix import camera
  66. import time
  67. import sys
  68. sys.path.append('/root/preset/server')
  69. ##################################
  70. # 1、AHT20温湿度传感器 #
  71. ##################################
  72. AHT20_I2CADDR = 0x38
  73. AHT20_CMD_SOFTRESET = [0xBA]
  74. AHT20_CMD_INITIALIZE = [0xBE, 0x08, 0x00]
  75. AHT20_CMD_MEASURE = [0xAC, 0x33, 0x00]
  76. AHT20_STATUSBIT_BUSY = 7 # The 7th bit is the Busy indication bit. 1 = Busy, 0 = not.
  77. AHT20_STATUSBIT_CALIBRATED = 3 # The 3rd bit is the CAL (calibration) Enable bit. 1 = Calibrated, 0 = not
  78. class AHT20:
  79. # Usage: AHT20 crc8 checker.
  80. # A total of 6 * 8 bits data need to check. G(x) = x8 + x5 + x4 + 1 -> 0x131(0x31), Initial value = 0xFF. No XOROUT.
  81. N_DATA = 6
  82. # 1 * 8 bits CRC
  83. N_CRC = 1
  84. # Initial value. Equal to bit negation the first data (status of AHT20)
  85. INIT = 0xFF
  86. # Useful value to help calculate
  87. LAST_8_bit = 0xFF
  88. # Devide number retrieve from CRC-8 MAXIM G(x) = x8 + x5 + x4 + 1
  89. CRC_DEVIDE_NUMBER = 0x131
  90. # I2C communication driver for AHT20, using only smbus2
  91. def __init__(self, BusNum=2):
  92. # Initialize AHT20
  93. self.BusNum = BusNum
  94. self.cmd_soft_reset()
  95. # Check for calibration, if not done then do and wait 10 ms
  96. if not self.get_status_calibrated == 1:
  97. self.cmd_initialize()
  98. while not self.get_status_calibrated() == 1:
  99. time.sleep(0.01)
  100. def get_normalized_bit(self,value, bit_index):
  101. # Return only one bit from value indicated in bit_index
  102. return (value >> bit_index) & 1
  103. def cmd_soft_reset(self):
  104. # Send the command to soft reset
  105. with SMBus(self.BusNum) as i2c_bus:
  106. i2c_bus.write_i2c_block_data(AHT20_I2CADDR, 0x0, AHT20_CMD_SOFTRESET)
  107. time.sleep(0.04) # Wait 40 ms after poweron
  108. return True
  109. def cmd_initialize(self):
  110. # Send the command to initialize (calibrate)
  111. with SMBus(self.BusNum) as i2c_bus:
  112. i2c_bus.write_i2c_block_data(AHT20_I2CADDR, 0x0 , AHT20_CMD_INITIALIZE)
  113. return True
  114. def cmd_measure(self):
  115. # Send the command to measure
  116. with SMBus(self.BusNum) as i2c_bus:
  117. i2c_bus.write_i2c_block_data(AHT20_I2CADDR, 0, AHT20_CMD_MEASURE)
  118. time.sleep(0.08) # Wait 80 ms after measure
  119. return True
  120. def get_status(self):
  121. # Get the full status byte
  122. with SMBus(self.BusNum) as i2c_bus:
  123. return i2c_bus.read_i2c_block_data(AHT20_I2CADDR, 0x0, 1)[0]
  124. return True
  125. def get_status_calibrated(self):
  126. # Get the calibrated bit
  127. return self.get_normalized_bit(self.get_status(), AHT20_STATUSBIT_CALIBRATED)
  128. def get_status_busy(self):
  129. # Get the busy bit
  130. return self.get_normalized_bit(self.get_status(), AHT20_STATUSBIT_BUSY)
  131. def get_measure(self):
  132. # Get the full measure
  133. # Command a measure
  134. self.cmd_measure()
  135. # Check if busy bit = 0, otherwise wait 80 ms and retry
  136. while self.get_status_busy() == 1:
  137. time.sleep(0.08) # Wait 80 ns
  138. # TODO: do CRC check
  139. # Read data and return it
  140. with SMBus(self.BusNum) as i2c_bus:
  141. return i2c_bus.read_i2c_block_data(AHT20_I2CADDR, 0x0, 7)
  142. def mod2_division_8bits(self,a, b, number_of_bytes, init_value):
  143. "calculate mod2 division in 8 bits. a mod b. init_value is for crc8 init value."
  144. head_of_a = 0x80
  145. # Processiong a
  146. a = a << 8
  147. # Preprocessing head_of_a
  148. for i in range(0, number_of_bytes):
  149. head_of_a = head_of_a << 8
  150. b = b << 8
  151. init_value = init_value << 8
  152. a = a ^ init_value
  153. while (head_of_a > 0x80):
  154. # Find a 1
  155. if (head_of_a & a):
  156. head_of_a = head_of_a >> 1
  157. b = b >> 1
  158. a = a ^ b
  159. else:
  160. head_of_a = head_of_a >> 1
  161. b = b >> 1
  162. # This will show calculate the remainder
  163. # print("a:{0}\thead of a:{1}\tb:{2}".format(
  164. # bin(a), bin(head_of_a), bin(b)))
  165. return a
  166. def AHT20_crc8_calculate(self,all_data_int):
  167. init_value = INIT
  168. # Preprocess all the data and CRCCode from AHT20
  169. data_from_AHT20 = 0x00
  170. # Preprocessing the first data (status)
  171. # print(bin(data_from_AHT20))
  172. for i_data in range(0, len(all_data_int)):
  173. data_from_AHT20 = (data_from_AHT20 << 8) | all_data_int[i_data]
  174. # print(bin(data_from_AHT20))
  175. mod_value = self.mod2_division_8bits(
  176. data_from_AHT20, CRC_DEVIDE_NUMBER, len(all_data_int), init_value)
  177. # print(mod_value)
  178. return mod_value
  179. def AHT20_crc8_check(self,all_data_int):
  180. """
  181. The input data shoule be:
  182. Status Humidity0 Humidity1 Humidity2|Temperature0 Temperature1 Temperature2 CRCCode.
  183. In python's int64.
  184. """
  185. mod_value = self.AHT20_crc8_calculate(all_data_int[:-1])
  186. if (mod_value == all_data_int[-1]):
  187. return True
  188. else:
  189. return False
  190. def get_measure_CRC8(self):
  191. """
  192. This function will calculate crc8 code with G(x) = x8 + x5 + x4 + 1 -> 0x131(0x31), Initial value = 0xFF. No XOROUT.
  193. return: all_data (1 bytes status + 2.5 byes humidity + 2.5 bytes temperature + 1 bytes crc8 code), isCRC8_pass
  194. """
  195. all_data = self.get_measure()
  196. isCRC8_pass = self.AHT20_crc8_check(all_data)
  197. return all_data, isCRC8_pass
  198. def get_temperature(self):
  199. # Get a measure, select proper bytes, return converted data
  200. measure = self.get_measure()
  201. measure = ((measure[3] & 0xF) << 16) | (measure[4] << 8) | measure[5]
  202. measure = measure / (pow(2,20))*200-50
  203. return measure
  204. def get_temperature_crc8(self):
  205. isCRC8Pass = False
  206. while (not isCRC8Pass):
  207. measure, isCRC8Pass = self.get_measure_CRC8()
  208. time.sleep(80 * 10**-3)
  209. measure = ((measure[3] & 0xF) << 16) | (measure[4] << 8) | measure[5]
  210. measure = measure / (pow(2,20))*200-50
  211. return measure
  212. def get_humidity(self):
  213. # Get a measure, select proper bytes, return converted data
  214. measure = self.get_measure()
  215. measure = (measure[1] << 12) | (measure[2] << 4) | (measure[3] >> 4)
  216. measure = measure * 100 / pow(2,20)
  217. return measure
  218. def get_humidity_crc8(self):
  219. isCRC8Pass = False
  220. while (not isCRC8Pass):
  221. measure, isCRC8Pass = self.get_measure_CRC8()
  222. time.sleep(80 * 10**-3)
  223. measure = (measure[1] << 12) | (measure[2] << 4) | (measure[3] >> 4)
  224. measure = measure * 100 / pow(2,20)
  225. return measure
  226. ##################################
  227. # 2、MPU6050陀螺仪六轴传感器 #
  228. ##################################
  229. SLAVE_ADDR = 0x68
  230. PWR_MGMT_1 = 0x6B
  231. PWR_MGMT_2 = 0x6C
  232. WHO_AM_I = 0x75
  233. GYRO_X = 0x43
  234. GYRO_Y = 0x45
  235. GYRO_Z = 0x47
  236. ACCL_X = 0x3B
  237. ACCL_Y = 0x3D
  238. ACCL_Z = 0x3F
  239. class MPU6050:
  240. def __init__(self, BusNum=2):
  241. # Initialize mpu6050
  242. self.BusNum = BusNum
  243. self.cmd_soft_reset()
  244. def cmd_soft_reset(self):
  245. # Send the command to soft reset
  246. with SMBus(self.BusNum) as bus:
  247. bus.write_byte_data(SLAVE_ADDR, PWR_MGMT_1, 0)
  248. time.sleep(0.04) # Wait 40 ms after poweron
  249. def read_byte(self,addr):
  250. with SMBus(self.BusNum) as bus:
  251. return bus.read_byte_data(SLAVE_ADDR,addr)
  252. def read_word(self,addr):
  253. with SMBus(self.BusNum) as bus:
  254. h = bus.read_byte_data(SLAVE_ADDR, addr)
  255. l = bus.read_byte_data(SLAVE_ADDR, addr+1)
  256. val = (h << 8) + l
  257. return val
  258. def read_word_i2c(self,addr):
  259. val = self.read_word(addr)
  260. if (val >= 0x8000):
  261. return -((65535 - val) + 1)
  262. else:
  263. return val
  264. def dist(self,x, y):
  265. return math.sqrt((x*x) + (y*y))
  266. def get_x_rotat(self,x,y, z):
  267. rad = math.atan2(y,self.dist(x, z))
  268. return math.degrees(rad)
  269. def get_y_rotat(self,x, y, z):
  270. rad = math.atan2(x,self.dist(y, z))
  271. return -math.degrees(rad)
  272. def read_gyro(self):
  273. GYR_X = self.read_word_i2c(GYRO_X)
  274. GYR_Y = self.read_word_i2c(GYRO_Y)
  275. GYR_Z = self.read_word_i2c(GYRO_Z)
  276. #print ("GYRO -> X:{:04.2f} Y:{:04.2f} Z:{:04.2f}".format((GYR_X/131), (GYR_Y/131), (GYR_Z/131)))
  277. return (GYR_X/131), (GYR_Y/131), (GYR_Z/131)
  278. def read_acc(self):
  279. ACC_X = self.read_word_i2c(ACCL_X)
  280. ACC_Y = self.read_word_i2c(ACCL_Y)
  281. ACC_Z = self.read_word_i2c(ACCL_Z)
  282. CALC_ACC_X = ACC_X/16384.0
  283. CALC_ACC_Y = ACC_Y/16384.0
  284. CALC_ACC_Z = ACC_Z/16384.0
  285. #print ("ACCL -> X:{:04.2f} Y:{:04.2f} Z:{:04.2f}".format(CALC_ACC_X, CALC_ACC_Y, CALC_ACC_Z))
  286. #print("ROTATE -> X:{:04.2f} Y:{:04.2f}\n".format(get_x_rotat(CALC_ACC_X, CALC_ACC_Y, CALC_ACC_Z), get_y_rotat(CALC_ACC_X, CALC_ACC_Y, CALC_ACC_Z)))
  287. return CALC_ACC_X, CALC_ACC_Y, CALC_ACC_Z,self.get_x_rotat(CALC_ACC_X, CALC_ACC_Y, CALC_ACC_Z),self.get_y_rotat(CALC_ACC_X, CALC_ACC_Y, CALC_ACC_Z)
  288. def get_gyro_x(self):
  289. return self.read_gyro()[0]
  290. def get_gyro_y(self):
  291. return self.read_gyro()[1]
  292. def get_gyro_z(self):
  293. return self.read_gyro()[2]
  294. def get_acc_x(self):
  295. return self.read_acc()[0]
  296. def get_acc_y(self):
  297. return self.read_acc()[1]
  298. def get_acc_z(self):
  299. return self.read_acc()[2]
  300. def get_angle_x(self):
  301. return self.read_acc()[3]
  302. def get_angle_y(self):
  303. return self.read_acc()[4]
  304. '''
  305. ##################################
  306. # 3、板载4颗按钮A、B、C、D #
  307. ##################################
  308. class BUTTON:
  309. import os
  310. def __init__(self, gpioId):
  311. sendMsg_1='echo '
  312. sendMsg_2=' > /sys/class/gpio/export'
  313. sendMsg_3=' > /sys/class/gpio/unexport'
  314. sendMsg_4='echo "in" > /sys/class/gpio/gpio'
  315. sendMsg_5='/direction'
  316. sendMsg_6='/sys/class/gpio/gpio'
  317. sendMsg_7='/value'
  318. self.gpio=str(224+gpioId)
  319. self.msgStart=sendMsg_1+self.gpio+sendMsg_2
  320. self.msgMode=sendMsg_4+self.gpio+sendMsg_5
  321. self.msgDel=sendMsg_1+self.gpio+sendMsg_3
  322. self.msgGet=sendMsg_6+self.gpio+sendMsg_7
  323. def is_pressed(self):
  324. import os
  325. if(os.access(self.msgGet, os.F_OK) is False):
  326. os.system(self.msgStart)
  327. os.system(self.msgMode)
  328. with open(self.msgGet, "rb") as self.file:
  329. self.getValue=int(self.file.read())
  330. if self.getValue != 1:
  331. return True
  332. else:
  333. return False
  334. def __del__(self):
  335. os.system(self.msgDel)
  336. '''
  337. ##################################
  338. # 3、板载4颗按钮A、B、C、D #
  339. ##################################
  340. class BUTTON:
  341. def __init__(self, gpioId):
  342. self.gpio=224+gpioId
  343. SUNXI_GPIO.setcfg(self.gpio, SUNXI_GPIO.IN)
  344. def is_pressed(self):
  345. self.getValue=SUNXI_GPIO.input(self.gpio)
  346. if self.getValue != 1:
  347. return True
  348. else:
  349. return False
  350. ##################################
  351. # 4、光线强度传感器 #
  352. ##################################
  353. class LIGHTINTENSITY:
  354. def __init__(self, addr=b"0x05070080") -> None:
  355. self.addr = addr
  356. self.path = "/sys/class/sunxi_dump/dump"
  357. self.file = open(self.path, "wb+")
  358. self.last = self.value()
  359. def value(self):
  360. self.file.write(b"0x05070080")
  361. self.file.seek(0)
  362. return int(self.file.read()[:-1], 16)
  363. def __del__(self):
  364. try:
  365. if self.file:
  366. self.file.close()
  367. del self.file
  368. except Exception as e:
  369. pass
  370. '''
  371. ##################################
  372. # 5、板载LED灯 #
  373. ##################################
  374. class LED:
  375. import os
  376. def __init__(self, gpioId=14):
  377. sendMsg_1='echo '
  378. sendMsg_2=' > /sys/class/gpio/export'
  379. sendMsg_3=' > /sys/class/gpio/unexport'
  380. sendMsg_4='echo "out" > /sys/class/gpio/gpio'
  381. sendMsg_5='/direction'
  382. self.sendMsg_6=' > /sys/class/gpio/gpio'
  383. self.sendMsg_7='/value'
  384. self.sendMsg_8='echo '
  385. self.gpio=str(224+gpioId)
  386. self.msgStart=sendMsg_1+self.gpio+sendMsg_2
  387. self.msgMode=sendMsg_4+self.gpio+sendMsg_5
  388. self.msgDel=sendMsg_1+self.gpio+sendMsg_3
  389. self.msgGet=self.sendMsg_6+self.gpio+self.sendMsg_7
  390. def out(self,value):
  391. import os
  392. os.system(self.msgStart)
  393. os.system(self.msgMode)
  394. if value==0 or value==1:
  395. self.value=value
  396. else:
  397. self.value=0
  398. self.msgSet=self.sendMsg_8+str(self.value)+self.sendMsg_6+self.gpio+self.sendMsg_7
  399. os.system(self.msgSet)
  400. def __del__(self):
  401. os.system(self.msgDel)
  402. '''
  403. ##################################
  404. # 5、板载LED灯 #
  405. ##################################
  406. class LED:
  407. def __init__(self, gpioId=69):
  408. self.gpioId=gpioId
  409. SUNXI_GPIO.setcfg(self.gpioId, SUNXI_GPIO.OUT)
  410. def out(self,value):
  411. if value==0 or value==1:
  412. self.value=1-value
  413. else:
  414. self.value=0
  415. SUNXI_GPIO.output(self.gpioId,self.value)
  416. '''
  417. ##################################
  418. # 6、直流电机 #
  419. ##################################
  420. class DCMOTOR:
  421. def __init__(self,dcMotorID="M1"):
  422. self.motorId=dcMotorID
  423. os.system('i2cset -y 2 0x40 0x00 0x00') #初始化
  424. #设定频率freq=50,预分频prescale=int(25000000.0 / 4096.0 / freq + 0.5)
  425. os.system('i2cset -y 2 0x40 0x00 0x10') #设定pca9685为睡眠模式
  426. os.system('i2cset -y 2 0x40 0xfe 0x7a') #设定预分频
  427. os.system('i2cset -y 2 0x40 0x00 0x00') #重新初始化
  428. time.sleep(0.01)
  429. os.system('i2cset -y 2 0x40 0x00 0xa1') #设定pca9685为活跃模式
  430. def numberMap(self,value, leftMin, leftMax, rightMin, rightMax):
  431. leftSpan = leftMax - leftMin
  432. rightSpan = rightMax - rightMin
  433. valueScaled = float(value - leftMin) / float(leftSpan)
  434. return rightMin + (valueScaled * rightSpan)
  435. def dcMotorOffRegisterValue(self,dcMotorSetSpeed):
  436. dcMotorOffRegister = int(self.numberMap(dcMotorSetSpeed,0,255,0,4095))
  437. dcMotorOffRegister_L = hex(dcMotorOffRegister & 0xff)
  438. dcMotorOffRegister_H = hex((dcMotorOffRegister >> 8) & 0xff)
  439. return dcMotorOffRegister_L, dcMotorOffRegister_H
  440. def dcMotorControl(self,dcMotorSetSpeed=0,dcMotorSetRotationDirection=True):
  441. if self.motorId=="M1":
  442. if dcMotorSetRotationDirection == True:
  443. dcMotorOffRegisterValue6_L ='i2cset -y 2 0x40 0x20 '+str(self.dcMotorOffRegisterValue(dcMotorSetSpeed)[0])
  444. dcMotorOffRegisterValue6_H ='i2cset -y 2 0x40 0x21 '+str(self.dcMotorOffRegisterValue(dcMotorSetSpeed)[1])
  445. os.system('i2cset -y 2 0x40 0x1e 0x00') #设定6通道ON_L为0
  446. os.system('i2cset -y 2 0x40 0x1f 0x00') #设定6通道ON_H为0
  447. os.system(dcMotorOffRegisterValue6_L) #设定6通道OFF_L为速度寄存器值低位
  448. os.system(dcMotorOffRegisterValue6_H) #设定6通道OFF_H为速度寄存器值高位
  449. os.system('i2cset -y 2 0x40 0x22 0x00') #设定7通道ON_L为0
  450. os.system('i2cset -y 2 0x40 0x23 0x00') #设定7通道ON_H为0
  451. os.system('i2cset -y 2 0x40 0x24 0x00') #设定7通道OFF_L为0
  452. os.system('i2cset -y 2 0x40 0x25 0x00') #设定7通道OFF_H为0
  453. elif dcMotorSetRotationDirection == False:
  454. dcMotorOffRegisterValue7_L ='i2cset -y 2 0x40 0x24 '+str(self.dcMotorOffRegisterValue(dcMotorSetSpeed)[0])
  455. dcMotorOffRegisterValue7_H ='i2cset -y 2 0x40 0x25 '+str(self.dcMotorOffRegisterValue(dcMotorSetSpeed)[1])
  456. os.system('i2cset -y 2 0x40 0x1e 0x00') #设定6通道ON_L为0
  457. os.system('i2cset -y 2 0x40 0x1f 0x00') #设定6通道ON_H为0
  458. os.system('i2cset -y 2 0x40 0x20 0x00') #设定6通道OFF_L为0
  459. os.system('i2cset -y 2 0x40 0x21 0x00') #设定6通道OFF_H为0
  460. os.system('i2cset -y 2 0x40 0x22 0x00') #设定7通道ON_L为0
  461. os.system('i2cset -y 2 0x40 0x23 0x00') #设定7通道ON_H为0
  462. os.system(dcMotorOffRegisterValue7_L) #设定7通道OFF_L为速度寄存器值低位
  463. os.system(dcMotorOffRegisterValue7_H) #设定7通道OFF_H为速度寄存器值高位
  464. else:
  465. pass
  466. elif self.motorId=="M2":
  467. if dcMotorSetRotationDirection == True:
  468. dcMotorOffRegisterValue9_L ='i2cset -y 2 0x40 0x2c '+str(self.dcMotorOffRegisterValue(dcMotorSetSpeed)[0])
  469. dcMotorOffRegisterValue9_H ='i2cset -y 2 0x40 0x2d '+str(self.dcMotorOffRegisterValue(dcMotorSetSpeed)[1])
  470. os.system('i2cset -y 2 0x40 0x2a 0x00') #设定9通道ON_L为0
  471. os.system('i2cset -y 2 0x40 0x2b 0x00') #设定9通道ON_H为0
  472. os.system(dcMotorOffRegisterValue9_L) #设定9通道OFF_L为速度寄存器值低位
  473. os.system(dcMotorOffRegisterValue9_H) #设定9通道OFF_H为速度寄存器值高位
  474. os.system('i2cset -y 2 0x40 0x2e 0x00') #设定10通道ON_L为0
  475. os.system('i2cset -y 2 0x40 0x2f 0x00') #设定10通道ON_H为0
  476. os.system('i2cset -y 2 0x40 0x30 0x00') #设定10通道OFF_L为0
  477. os.system('i2cset -y 2 0x40 0x31 0x00') #设定10通道OFF_H为0
  478. elif dcMotorSetRotationDirection == False:
  479. dcMotorOffRegisterValue10_L ='i2cset -y 2 0x40 0x30 '+str(self.dcMotorOffRegisterValue(dcMotorSetSpeed)[0])
  480. dcMotorOffRegisterValue10_H ='i2cset -y 2 0x40 0x31 '+str(self.dcMotorOffRegisterValue(dcMotorSetSpeed)[1])
  481. os.system('i2cset -y 2 0x40 0x2a 0x00') #设定9通道ON_L为0
  482. os.system('i2cset -y 2 0x40 0x2b 0x00') #设定9通道ON_H为0
  483. os.system('i2cset -y 2 0x40 0x2c 0x00') #设定9通道OFF_L为0
  484. os.system('i2cset -y 2 0x40 0x2d 0x00') #设定9通道OFF_H为0
  485. os.system('i2cset -y 2 0x40 0x2e 0x00') #设定10通道ON_L为0
  486. os.system('i2cset -y 2 0x40 0x2f 0x00') #设定10通道ON_H为0
  487. os.system(dcMotorOffRegisterValue10_L) #设定10通道OFF_L为速度寄存器值低位
  488. os.system(dcMotorOffRegisterValue10_H) #设定10通道OFF_H为速度寄存器值高位
  489. else:
  490. pass
  491. else:
  492. pass
  493. def __del__(self):
  494. if self.motorId=="M1":
  495. os.system('i2cset -y 2 0x40 0x1e 0x00') #设定6通道ON_L为0
  496. os.system('i2cset -y 2 0x40 0x1f 0x00') #设定6通道ON_H为0
  497. os.system('i2cset -y 2 0x40 0x20 0x00') #设定6通道OFF_L为0
  498. os.system('i2cset -y 2 0x40 0x21 0x00') #设定6通道OFF_H为0
  499. os.system('i2cset -y 2 0x40 0x22 0x00') #设定7通道ON_L为0
  500. os.system('i2cset -y 2 0x40 0x23 0x00') #设定7通道ON_H为0
  501. os.system('i2cset -y 2 0x40 0x24 0x00') #设定7通道OFF_L为0
  502. os.system('i2cset -y 2 0x40 0x25 0x00') #设定7通道OFF_H为0
  503. elif self.motorId=="M2":
  504. os.system('i2cset -y 2 0x40 0x2a 0x00') #设定9通道ON_L为0
  505. os.system('i2cset -y 2 0x40 0x2b 0x00') #设定9通道ON_H为0
  506. os.system('i2cset -y 2 0x40 0x2c 0x00') #设定9通道OFF_L为0
  507. os.system('i2cset -y 2 0x40 0x2d 0x00') #设定9通道OFF_H为0
  508. os.system('i2cset -y 2 0x40 0x2e 0x00') #设定10通道ON_L为0
  509. os.system('i2cset -y 2 0x40 0x2f 0x00') #设定10通道ON_H为0
  510. os.system('i2cset -y 2 0x40 0x30 0x00') #设定10通道OFF_H为0
  511. os.system('i2cset -y 2 0x40 0x31 0x00') #设定10通道OFF_L为0
  512. else:
  513. pass
  514. '''
  515. '''
  516. ##################################
  517. # 7、模拟舵机 #
  518. ##################################
  519. class SERVO:
  520. def __init__(self,servoID="S1"):
  521. self.servoId=servoID
  522. os.system('i2cset -y 2 0x40 0x00 0x00') #初始化
  523. #设定频率freq=50,预分频prescale=int(25000000.0 / 4096.0 / freq + 0.5)
  524. os.system('i2cset -y 2 0x40 0x00 0x10') #设定pca9685为睡眠模式
  525. os.system('i2cset -y 2 0x40 0xfe 0x7a') #设定预分频
  526. os.system('i2cset -y 2 0x40 0x00 0x00') #重新初始化
  527. time.sleep(0.01)
  528. os.system('i2cset -y 2 0x40 0x00 0xa1') #设定pca9685为活跃模式
  529. def servoOffRegisterValue(self,servoSetDegree):
  530. servoPwmus = (servoSetDegree * 2000 / 180 + 500) # 0.6 ~ 2.4——【2023.03.14更改:0.5~2.5】
  531. servoOffRegister = int(servoPwmus * 4096 / 20000)
  532. servoOffRegister_L = hex(servoOffRegister & 0xff)
  533. servoOffRegister_H = hex((servoOffRegister >> 8) & 0xff)
  534. return servoOffRegister_L, servoOffRegister_H
  535. def servoControl(self,servoSetDegree=0):
  536. if self.servoId=="S1":
  537. servoOffRegisterCmd5_L ="i2cset -y 2 0x40 0x1c "+str(self.servoOffRegisterValue(servoSetDegree)[0])
  538. servoOffRegisterCmd5_H ="i2cset -y 2 0x40 0x1d "+str(self.servoOffRegisterValue(servoSetDegree)[1])
  539. os.system('i2cset -y 2 0x40 0x1a 0x00') #设定5通道ON_L为0
  540. os.system('i2cset -y 2 0x40 0x1b 0x00') #设定5通道ON_H为0
  541. os.system(servoOffRegisterCmd5_L) #设定5通道OFF_L为
  542. os.system(servoOffRegisterCmd5_H) #设定5通道OFF_H为
  543. elif self.servoId=="S2":
  544. servoOffRegisterCmd11_L ="i2cset -y 2 0x40 0x34 "+str(self.servoOffRegisterValue(servoSetDegree)[0])
  545. servoOffRegisterCmd11_H ="i2cset -y 2 0x40 0x35 "+str(self.servoOffRegisterValue(servoSetDegree)[1])
  546. os.system('i2cset -y 2 0x40 0x32 0x00') #设定11通道ON_L为0
  547. os.system('i2cset -y 2 0x40 0x33 0x00') #设定11通道ON_H为0
  548. os.system(servoOffRegisterCmd11_L) #设定11通道OFF_L为
  549. os.system(servoOffRegisterCmd11_H) #设定11通道OFF_H为
  550. else:
  551. pass
  552. def __del__(self):
  553. time.sleep(0.01)
  554. '''
  555. ##################################
  556. # 7、QMI8658 #
  557. ##################################
  558. class QMI8658(object):
  559. def __init__(self, smbus=2, address=0X6B):
  560. self._address = address
  561. import smbus2
  562. self._bus = smbus2.SMBus(smbus)
  563. bRet = self.WhoAmI()
  564. if bRet:
  565. self.Read_Revision()
  566. else:
  567. return None
  568. self.Config_apply()
  569. def _read_byte(self, cmd):
  570. rec = self._bus.read_i2c_block_data(int(self._address), int(cmd), 1)
  571. return rec[0]
  572. def _read_block(self, reg, length=1):
  573. rec = self._bus.read_i2c_block_data(int(self._address), int(reg), length)
  574. return rec
  575. def _read_u16(self, cmd):
  576. LSB = self._bus.read_i2c_block_data(int(self._address), int(cmd), 1)
  577. MSB = self._bus.read_i2c_block_data(int(self._address), int(cmd)+1, 1)
  578. return (MSB[0] << 8) + LSB[0]
  579. def _write_byte(self, cmd, val):
  580. self._bus.write_i2c_block_data(int(self._address), int(cmd), bytes([int(val)]))
  581. def WhoAmI(self):
  582. bRet = False
  583. if (0x05) == self._read_byte(0x00):
  584. bRet = True
  585. return bRet
  586. def Read_Revision(self):
  587. return self._read_byte(0x01)
  588. def Config_apply(self):
  589. # REG CTRL1
  590. self._write_byte(0x02, 0x60)
  591. # REG CTRL2 : QMI8658AccRange_8g and QMI8658AccOdr_1000Hz
  592. self._write_byte(0x03, 0x23)
  593. # REG CTRL3 : QMI8658GyrRange_512dps and QMI8658GyrOdr_1000Hz
  594. self._write_byte(0x04, 0x53)
  595. # REG CTRL4 : No
  596. self._write_byte(0x05, 0x00)
  597. # REG CTRL5 : Enable Gyroscope And Accelerometer Low-Pass Filter
  598. self._write_byte(0x06, 0x11)
  599. # REG CTRL6 : Disables Motion on Demand.
  600. self._write_byte(0x07, 0x00)
  601. # REG CTRL7 : Enable Gyroscope And Accelerometer
  602. self._write_byte(0x08, 0x03)
  603. def Read_Raw_XYZ(self):
  604. xyz = [0, 0, 0, 0, 0, 0]
  605. raw_timestamp = self._read_block(0x30, 3)
  606. raw_acc_xyz = self._read_block(0x35, 6)
  607. raw_gyro_xyz = self._read_block(0x3b, 6)
  608. raw_xyz = self._read_block(0x35, 12)
  609. timestamp = (raw_timestamp[2] << 16) | (
  610. raw_timestamp[1] << 8) | (raw_timestamp[0])
  611. for i in range(6):
  612. # xyz[i]=(raw_acc_xyz[(i*2)+1]<<8)|(raw_acc_xyz[i*2])
  613. # xyz[i+3]=(raw_gyro_xyz[((i+3)*2)+1]<<8)|(raw_gyro_xyz[(i+3)*2])
  614. xyz[i] = (raw_xyz[(i*2)+1] << 8) | (raw_xyz[i*2])
  615. if xyz[i] >= 32767:
  616. xyz[i] = xyz[i]-65535
  617. return xyz
  618. def Read_XYZ(self):
  619. xyz = [0, 0, 0, 0, 0, 0]
  620. raw_xyz = self.Read_Raw_XYZ()
  621. #QMI8658AccRange_8g
  622. acc_lsb_div = (1 << 12)
  623. #QMI8658GyrRange_512dps
  624. gyro_lsb_div = 64
  625. for i in range(3):
  626. xyz[i] = raw_xyz[i]/acc_lsb_div # (acc_lsb_div/1000.0)
  627. xyz[i+3] = raw_xyz[i+3]*1.0/gyro_lsb_div
  628. return xyz
  629. import smbus2
  630. import time
  631. class stm8s(object):
  632. bus = smbus2.SMBus(2) # 2 indicates /dev/i2c-2
  633. address = 0x50
  634. # 0x00 # 触发配置
  635. # 0x01 # 重置配置
  636. # 0x02 # pwm0 历史配置
  637. # 0x03 # pwm1 历史配置
  638. # 引脚配置模式有 1. pwm 2. gpio ouput gpio input 3. adc 4.ws2812_singe 5 ws2812_multi
  639. def __init__(self):
  640. self.reset()
  641. time.sleep(0.05)
  642. pass
  643. def clear(self):
  644. self.write(1, 1)
  645. self.reset()
  646. time.sleep(0.05)
  647. def write(self, addr, val):
  648. for i in range(0, 3):
  649. try:
  650. self.bus.write_byte_data(self.address, addr, val)
  651. time.sleep(0.001) # 1ms
  652. # print(addr, val) # debug
  653. return True
  654. except Exception:
  655. time.sleep(0.01)
  656. continue
  657. return False
  658. def read(self, addr):
  659. for i in range(0, 3):
  660. try:
  661. tmp = self.bus.read_byte_data(self.address, addr)
  662. time.sleep(0.001) # 1ms
  663. # print(addr, tmp) # debug
  664. return tmp
  665. except Exception:
  666. time.sleep(0.01)
  667. continue
  668. return None
  669. def reset(self):
  670. self.write(0, 1)
  671. time.sleep(0.05) # 重启并配置需要时间
  672. def dump(self):
  673. for i in range(0, 32):
  674. print(i, self.read(i))
  675. class singleRgb(stm8s):
  676. def __init__(self):
  677. self.valR=0
  678. self.valG=0
  679. self.valB=0
  680. self.brightness=255
  681. self.show()
  682. def setColor(self,r,g,b):
  683. if(r>=0 and r<=255):
  684. self.valR=int(r*self.brightness/255)
  685. else:
  686. self.valR=0
  687. if(g>=0 and g<=255):
  688. self.valG=int(g*self.brightness/255)
  689. else:
  690. self.valG=0
  691. if(b>=0 and b<=255):
  692. self.valB=int(b*self.brightness/255)
  693. else:
  694. self.valB=0
  695. def setBrightness(self,brightness):
  696. if(brightness>=0 and brightness<=255):
  697. self.brightness=brightness
  698. else:
  699. self.brightness=0
  700. def show(self):
  701. self.write(31, self.valB)
  702. self.write(30, self.valG)
  703. self.write(29, self.valR)
  704. self.write(28, 6)
  705. class dcMotor(stm8s):
  706. def __init__(self,id):
  707. self.id=id
  708. def m1a(self,val=0):
  709. self.write(4,5) #M1A
  710. self.write(5,0)
  711. self.write(6,0)
  712. self.write(7,val)
  713. def m1b(self,val=0):
  714. self.write(8,5) #M1B
  715. self.write(9,0)
  716. self.write(10,0)
  717. self.write(11,val)
  718. def m2a(self,val=0):
  719. self.write(12,5) #M2A
  720. self.write(13,0)
  721. self.write(14,0)
  722. self.write(15,val)
  723. def m2b(self,val=0):
  724. self.write(16,5) #M2B
  725. self.write(17,0)
  726. self.write(18,0)
  727. self.write(19,val)
  728. def dcMotorCtrl(self,dir,speed):
  729. if(0<=speed and speed<=255):
  730. if(self.id ==1): #Motor1
  731. if(dir==0):
  732. self.m1a(speed)
  733. self.m1b(0)
  734. else:
  735. self.m1a(255-speed)
  736. self.m1b(1)
  737. elif(self.id ==2):
  738. if(dir==0):
  739. self.m2a(speed)
  740. self.m2b(0)
  741. else:
  742. self.m2a(255-speed)
  743. self.m2b(1)
  744. else:
  745. pass
  746. class multiFuncGpio(stm8s):
  747. def __init__(self,id=0,mode=0):
  748. self.id=id
  749. self.rgbId=0
  750. self.brightness=255
  751. self.mode=mode
  752. self.write(20+self.id*4,self.mode)
  753. self.reset()
  754. time.sleep(0.05)
  755. ##################################################
  756. # mode | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
  757. #-------------------------------------------------
  758. # Func |free |servo|INPUT| OUT | ADC | PWM | BEEP|
  759. ##################################################
  760. # mode=0,为空闲状态,引脚不执行任何功能
  761. # mode=1,为控制舵机模式,值控制范围为0°~180°
  762. # mode=2,为数字输入模式,返回值0或1
  763. # mode=3,为数字输出模式,输出值为0或1
  764. # mode=4,为ADC采样模式,返回值为0~1023
  765. # mode=5,为PWM输出模式,输出值范围为0~255
  766. # mode=6,为控制蜂鸣器模式,控制范围为20hz~12000hz
  767. # mode=7,为控制灯带模式,暂未实现
  768. # id=0,控制多功能引脚1,向20号寄存器写入模式数据
  769. # id=1,控制多功能引脚2,向24号寄存器写入模式数据
  770. def servoCtrl(self,angle):
  771. if ((angle>=0) and (angle<=180)):
  772. self.write(23+self.id*4,angle)
  773. else:
  774. pass
  775. def digitalRead(self):
  776. try:
  777. self.gpioVal= self.read(23+ self.id*4)
  778. if(self.gpioVal != None):
  779. return 1-self.gpioVal
  780. except:
  781. print("ERROR 233")
  782. def digitalWrite(self,val):
  783. if ((val>=0) and (val<=1)):
  784. self.write(23+self.id*4,val)
  785. else:
  786. pass
  787. def analogRead(self):
  788. try:
  789. self.adcValH= self.read(22+ self.id*4)
  790. self.adcValL= self.read(23+ self.id*4)
  791. if (self.adcValH != None and self.adcValL != None):
  792. # adcValH adcValL 大小端合并 16bit
  793. self.adcVal = self.adcValL + (self.adcValH << 8)
  794. return self.adcVal
  795. except:
  796. print("ERROR 2333")
  797. def analogWrite(self,val):
  798. if ((val>=0) and (val<=255)):
  799. self.write(23+self.id*4,val)
  800. else:
  801. pass
  802. def beep(self,frequency):
  803. if ((val>=20) and (val<=12000)):
  804. self.write(22+self.id*4,val>>8)
  805. self.write(23+self.id*4,val&0b11111111)
  806. else:
  807. pass
  808. def pixelInit_(self):
  809. for i in range(16):
  810. self.setPixelColor(i,0,0,0)
  811. self.pixelShow()
  812. def setBrightness(self,brightness):
  813. if(brightness>=0 and brightness<=255):
  814. self.brightness=brightness
  815. else:
  816. self.brightness=0
  817. def setPixelColor(self,rgbId,r,g,b):
  818. if(rgbId >=0 and rgbId <=15):
  819. self.rgbId=rgbId #rgbId范围:0~15
  820. else:
  821. self.rgbId=0
  822. if(r>=0 and r<=255):
  823. self.valR=int(r*self.brightness/255)
  824. else:
  825. self.valR=0
  826. if(g>=0 and g<=255):
  827. self.valG=int(g*self.brightness/255)
  828. else:
  829. self.valG=0
  830. if(b>=0 and b<=255):
  831. self.valB=int(b*self.brightness/255)
  832. else:
  833. self.valB=0
  834. #self.id的值为0或1,用于控制灯带缓冲区(S1或者S2引脚)
  835. def pixelShow(self):
  836. self.write(32+ self.id*48+self.rgbId*3, self.valR)
  837. self.write(33+ self.id*48+self.rgbId*3, self.valG)
  838. self.write(34+ self.id*48+self.rgbId*3, self.valB)
  839. class UvcVideo(camera.MaixVideo):
  840. def __init__(self, source="/dev/videoX"):
  841. self.source = source
  842. super(UvcVideo, self).__init__()
  843. import os, time
  844. usb_path = '/sys/devices/platform/soc/usbc0/otg_role'
  845. # 确认 usb_path 内容为 usb_host 如果不是,自动设置为 usb_host
  846. if os.popen('cat %s' % usb_path).read().strip() != 'usb_host':
  847. os.system('echo "usb_host" > %s' % usb_path)
  848. time.sleep(2) # 要设置 2s 左右才能初始化工作,否则会报 VIDIOC_S_FMT 失败。
  849. def config(self, size=None, video=2, horizontal=0, vertical=0):
  850. if size == None:
  851. size = (320, 240)
  852. super(UvcVideo, self).config(size)
  853. print('[camera] config input size(%d, %d, %d)' %
  854. (self.width(), self.height(), video))
  855. if self.cam:
  856. self.cam = None
  857. try:
  858. import _coco_camera
  859. self.cam = _coco_camera.Camera(self.width(), self.height(), video, horizontal, vertical)
  860. except Exception as e:
  861. print(e)
  862. self.cam = None
  863. def read(self):
  864. if self.cam == None:
  865. self.config()
  866. if self.cam:
  867. ret, frame = self.cam.read()
  868. if ret:
  869. return frame # bytes
  870. else:
  871. try:
  872. self.config()
  873. except Exception as e:
  874. print(e)
  875. return None
  876. def __del__(self):
  877. if self.cam:
  878. self.cam = None