数字孪生示范项目——从单摆谈起(4)IoT探索

发布于:2023-02-18 ⋅ 阅读:(452) ⋅ 点赞:(0)

  IoT的探索历程是真的曲折且有趣呀,我是对它又爱又恨,爱在它做成之后比做成物理模型更有成就感,因为IoT真正实现了数字孪生的核心步骤——数据可视化,可是IoT也很可恨,可恨在做成功实在是太艰难了,难到甚至让我变更了短学期要达成的目标,硬生生把单摆项目做成类单摆——复摆,险些让我没能够在短学期结束之前完成当初定下的里程碑。

  那么对于该项目而言,IoT具体是什么呢?其实数字孪生就是要让虚拟的仿真模型与现实世界中的实体模型相对应,可是现实中的实体模型有太多的不确定因素了,这就导致在设计虚拟仿真模型时需要耗费大量的功夫去不断地修改,这样最终才能达到同频、对应的效果。

  为了实现虚拟仿真模型与实体模型的对应,我首先是需要设计选择传感器。个人认为,传感器就是沟通现实世界与虚拟世界的桥梁,有着至关重要的作用。所以选择一个合适的传感器,并且能抓到数据,且抓回来的数据还能跟现实世界的真实情况对应起来,是曲折复杂的。而且,不能想当然的认为抓回来数据肉眼看上去没问题就可以了,实际上还是要用抓回来的数据去真正把图像画出来,才具有说服力。这也是我做这个项目感受到的较为重要的一点。

  那么IoT在本项目中,具体体现在:首先是选择传感器,并且选择好要获取传感器能读出来的哪个数据;其次,是设计算法来抓取传感器中的数据,并且能实时显示出来;再次,是如何利用好传感器传回来的数据,比如发送到服务器用于绘制图像(本项目即是如此),最后,是综合利用数据,实现可视化。

  首先我在选择传感器上,选择了waffle nano开发板上自带的ICM20948九轴陀螺仪传感器,因为本身我的实验装置就不能设计的太过复杂,不要引入太多无关紧要的线,且本身ICM20948就是一个非常不错且精确的传感器,能实时反馈读取出来的加速度、角速度、磁场数据。

  选择好了传感器,并且改装了TypeC接口的供电电池,下一步就要开始设计算法。刚开始,我查阅了单摆的有关公式,发现利用角速度数据可以实现读取出角度。这个想法和出发点是好的,可是角速度其实是陀螺仪读取出来的,如果单摆静止在某个位置时,其角速度为0,就会导致数据不正确,且只有在单摆完全符合理想化的单摆运动时,角速度返回的角度数据才是正确的。

 而且在设计角速度返回角度的算法中,由公式推导出theta=arccos()括号里有一个函数,但是arccos函数是有定义域的,如果我传感器晃动的过快,会导致程序报错。所以一开始我从角速度出发的出发点就是错误的,这样会带来非常多的局限。

  我目前才大一,这个项目可以说是第一次接触IoT,对各种传感器还不是很了解,在求教了一位同实验室的学长之后,发现应该利用一开始我抛弃的加速度数据会更合理。

这是传感器读取加速度的原理:

ICM20948传感器有x轴、y轴、z轴的数据,因为我在上篇blog里说到已经把模型简化到二维的钟摆模型,所以我只取用了x轴、y轴两个数据。

 这是对于waffle nano开发板来说的x轴、y轴的坐标。当单摆摆动到一定的方向时:

  红色的坐标轴表示是以地面为参考系的坐标轴,蓝色的轴还是waffle nano转动之后以自身为参考系建立的坐标轴。 红色的theta就表示偏转的角度,那么该怎么计算呢?

 首先,要明确的一点是,传感器中所谓的x轴、y轴分量,计算theta时要把其坐标分解到以地面为参考系的坐标中。所以目标到现在已经很明确,可以根据传感器目前偏的位置,来计算出角度。

def read_coord():
    read_success=False
    while (not read_success):
        read_success=(imu.dataupdate() and imu.dataready())
        src_data_x=imu.acc_x()  
        src_data_y=imu.acc_y()  
        src_data_z=imu.acc_z()  
    
    
    l=0.25
    theta= math.atan2(src_data_y, src_data_x)
    x=l*math.sin(theta)
    y=l*math.cos(theta)
    tup=(x,y)
    return tup

l表示我的绳长,我这里直接以元组的形式把x、y轴坐标直接返回,这样就有利于我下一步进行图像绘制了。

  接着是把数据上传到jetson nano上,用jupyter上的python3进行图形绘制

while(1):
    str=client_socket.recv(8)
    str2=struct.unpack("ff", str)
    
    x = str2[0]
    y = str2[1]
    
    x = x + 0.25
    
    drawX = int(500 * x / 0.5)
    drawY = int(300 * y / 0.25)
    
    drawBall(drawX, drawY)

以上就是绘制球的语法。

期间进行了非常多的探索,不仅局限于探索jupyter的画图过程,期间因为做不出来也失望过,烦躁过,愤懑过,不过庆幸最终还是在同组学长的帮助下利用CV成功绘制出了小球的图像。

以下是基于python3的jupyter的代码块实现

from socket import  *
import gc
import matplotlib.pyplot as plt
import os
import struct
import numpy as np
import cv2 as cv
import time
import ipywidgets as widgets
from IPython.display import display

def imshow(name, img):
    if(not name in windowsObj):
        windowsObj[name] = widgets.Image(format='jpg', height=img.shape[0], width=img.shape[1])
        display(windowsObj[name])

    windowsObj[name].value = cv.imencode('.jpg', img)[1].tobytes()

maxHeight = 480
maxWidth = 640

centerPoint = [int(500 / 2), 0]

def drawBall(x, y):
    image = np.zeros([maxHeight, maxWidth, 1], dtype=np.uint8)
    
    cv.line(image, (centerPoint[0], centerPoint[1]), (x, y), (255), 3)
    cv.circle(image, (x, y), 20, (255), -1)
    
    imshow('frame', image)

windowsObj = {}

tcp_server = socket(AF_INET,SOCK_STREAM)
address = ('192.168.3.53',8863)
tcp_server.bind(address)
tcp_server.listen(128)
client_socket, clientAddr = tcp_server.accept()

currentTime = time.time()

while(1):
    str=client_socket.recv(8)
    str2=struct.unpack("ff", str)
    
    x = str2[0]
    y = str2[1]
    
    x = x + 0.25
    
    drawX = int(500 * x / 0.5)
    drawY = int(300 * y / 0.25)
    
    drawBall(drawX, drawY)
    
    gc.collect()
client_socket.close()

 

最终成功绘制出能反映单摆实时位置的图像。 


网站公告

今日签到

点亮在社区的每一天
去签到