CocoPi.js 39 KB

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