Micropython 之 旋转立方块
入门 ESP32-C3,学习Micropython还是先从自己手上的模块开始,MPU6050是一个很好的选择,很多场合都用得上。记得几年前用STM32F103接过MPU6050,然后用匿名上位机观测模拟飞机的飞控状态:横滚,俯仰,旋转,然后就没有了。资料看着看着,有一个旋转立方块的范例,用SSD1306 OLED屏显示,于是用面包板接线,修改I2C的接脚后就看到立方块转起来。
想想立方块的旋转也能和陀螺仪结合,但是是如何产生立方块和如何旋转的呢?区区40几行的代码就能完成这个动作有点神奇,开始分析代码发现,自己的数学没学好:向量,矩阵和线性代数一塌糊涂。于是开启了自我补课之旅,先把ESP32-C3 和 micropython放一边,在 慕课网 和 哔哩哔哩 下载一堆线性代数,矩阵变换:
看得似懂非懂的,好像跟我的旋转立方块有关系,但又不是很直接,线性代数得水很深,我怕陷进去走岔了。
今天看到一篇 知乎 (超详细!)计算机图形学 入门篇 1. 变换矩阵,课程资料来源于《Fundamentals of Computer Graphics》以及闫老师的GAMES 101课程GAMES101: 现代计算机图形学入门,原来这个视频集我已经下载过了,而且只有前面4个视频是我所需要的,就顺便把pdf课件也下载:
边看视频,边在pdf课件里做笔记:二维矩阵对向量的变换,推广到三维矩阵对向量的变换,不就是我需要的知识吗。学习完这个视频教材,回头再来分析旋转立方块,呵呵还能看出不规整的地方,做了一些排版,增加了自己了解后的注释:
1 # -*- coding: UTF-8 -*- 2 # 合宙CORE ESP32-C3 核心板板载2颗LED + 16MB Flash(原4MB) 3 # (GPIO12) D4 GND, 高电平有效 4 # (GPIO13) D5 GND, 高电平有效 5 6 from math import cos, sin, pi 7 from machine import SoftI2C, Pin 8 from ssd1306 import SSD1306_I2C 9 10 cube = [[-15, -15, -15], [-15, 15, -15], [15, 15, -15], [15, -15, -15], # 下方逆时针4点向量:1,2,3,4 11 [-15, -15, 15], [-15, 15, 15], [15, 15, 15], [15, -15, 15]] # 上方逆时针4点向量:5,6,7,8 12 lineid = [1, 2, 2, 3, 3, 4, 4, 1, # 下方逆时针2点一线,4线段 13 5, 6, 6, 7, 7, 8, 8, 5, # 上方逆时针2点一线,4线段 14 8, 4, 7, 3, 6, 2, 5, 1] # 上下垂直2点一线,4线段 15 16 i2c = SoftI2C(scl=Pin(0), sda=Pin(1)) 17 oled = SSD1306_I2C(128, 64, i2c, addr=0x3c) 18 oled.fill(0) 19 20 21 def matconv(a, matrix): # M(3x3) * a(3x1) 22 res = [0, 0, 0] 23 for i in range(0, 3): 24 res[i] = matrix[i][0] * a[0] + matrix[i][1] * a[1] + matrix[i][2] * a[2] 25 for i in range(0, 3): 26 a[i] = res[i] 27 return a # a(3x1) 28 29 30 def rotate(obj, x, y, z): 31 x = x / pi 32 y = y / pi 33 z = z / pi 34 rx = [[1, 0, 0], [0, cos(x), -sin(x)], [0, sin(x), cos(x)]] 35 ry = [[cos(y), 0, sin(y)], [0, 1, 0], [-sin(y), 0, cos(y)]] 36 rz = [[cos(z), -sin(z), 0], [sin(z), cos(z), 0], [0, 0, 1]] 37 matconv(matconv(matconv(obj, rz), ry), rx) 38 39 def drawcube(x, y, z): 40 oled.fill(0) 41 for i in range(0, 8): 42 rotate(cube[i], x, y, z) 43 for i in range(0, 24, 2): 44 x1 = int(64 + cube[lineid[i] - 1][0]) # 128/2 = 64 45 y1 = int(32 + cube[lineid[i] - 1][1]) # 64/2 = 32, no z1 [2] 46 x2 = int(64 + cube[lineid[i + 1] - 1][0]) # 128/2 = 64 47 y2 = int(32 + cube[lineid[i + 1] - 1][1]) # 64/2 = 32, no z2 [2] 48 oled.line(x1, y1, x2, y2, 1) 49 # print(lineid[i], cube[lineid[i] - 1][0], cube[lineid[i] - 1][1], 50 # lineid[i+1], cube[lineid[i + 1] - 1][0], cube[lineid[i + 1] - 1][1]) 51 oled.show() 52 53 cnt = 0 54 while 1: 55 drawcube(0.1, 0.2, 0.3) 56 print(cnt, end=' ') 57 cnt += 1