openGL实时显示IMU姿态

openGL实时显示IMU姿态,用于验证IMU标定效果

  1. 获取IMU数据: 首先,你需要获取IMU传感器的数据,包括姿态(如欧拉角、四元数)以及可能的陀螺仪、加速度计和磁力计数据。
  2. 解析姿态数据:
    解析IMU传感器提供的姿态数据,通常为欧拉角或四元数。如果姿态是欧拉角,则通常以角度的形式表示,例如roll、pitch和yaw。
  3. 将姿态转换为OpenGL坐标系:
    根据IMU传感器提供的姿态数据,将其转换为OpenGL的世界坐标系。通常,IMU的姿态数据可能使用不同的坐标系,例如欧拉角的旋转顺序可能不同,或者四元数的坐标系表示方式可能不同。
  4. 绘制模型:
    使用OpenGL绘制模型或几何图形来表示IMU的姿态。你可以绘制一个简单的模型(如立方体)或者更复杂的模型(如飞机、汽车等)来表示物体的方向和旋转。
  5. 更新姿态数据: 定期更新IMU传感器提供的姿态数据,并重新绘制OpenGL中的模型,以反映物体的最新姿态。

C++ socket将IMU姿态信息发送到主机

        void LoggerWrite(const char *data, int len, const char *remote, int port)
        {
            static int logger_fd = -1;
            if (logger_fd < 0)
            {
                logger_fd = socket(AF_INET, SOCK_DGRAM, 0);
                if (logger_fd < 0)
                {
                    printf("socket create error\n");
                    return;
                }
                struct sockaddr_in server_addr;
                memset(&server_addr, 0, sizeof(server_addr));
                server_addr.sin_family = AF_INET;
                server_addr.sin_port = htons(port);
                server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

                if (bind(logger_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
                {
                    printf("bind error\n");
                    return;
                }
            }

            struct sockaddr_in client_addr;
            memset(&client_addr, 0, sizeof(client_addr));
            client_addr.sin_family = AF_INET;
            client_addr.sin_port = htons(port);
            client_addr.sin_addr.s_addr = inet_addr(remote);
            sendto(logger_fd, data, len, 0, (struct sockaddr *)&client_addr, sizeof(client_addr));
        }

python 接收数据并实时显示IMU姿态

import socket
import threading
import numpy as np
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PyQt5.QtWidgets import QApplication, QOpenGLWidget, QMainWindow


class OpenGLWidget(QOpenGLWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.rotate = np.array([0.0, 0.0, 0.0, 0.0])

    def initializeGL(self):
        glClearColor(0.0, 0.0, 0.0, 1.0)
        glEnable(GL_DEPTH_TEST)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45, 4 / 3, 0.1, 50.0)
        glMatrixMode(GL_MODELVIEW)

    def resizeGL(self, w, h):
        glViewport(0, 0, w, h)

    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()
        glTranslatef(0.0, 0.0, -5.0)

        glRotatef(self.rotate[0], self.rotate[1], self.rotate[2], self.rotate[3])

        self.drawCube()
        self.drawAxis()

    @staticmethod
    def drawCube():
        glBegin(GL_QUADS)

        # red face
        glColor3f(1.0, 0.0, 0.0)
        glVertex3f(0.5, 0.5, -0.5)
        glVertex3f(-0.5, 0.5, -0.5)
        glVertex3f(-0.5, 0.5, 0.5)
        glVertex3f(0.5, 0.5, 0.5)

        # red face
        glColor3f(1.0, 0.0, 0.0)
        glVertex3f(0.5, -0.5, 0.5)
        glVertex3f(-0.5, -0.5, 0.5)
        glVertex3f(-0.5, -0.5, -0.5)
        glVertex3f(0.5, -0.5, -0.5)

        # blue face
        glColor3f(0.0, 0.0, 1.0)
        glVertex3f(0.5, 0.5, 0.5)
        glVertex3f(-0.5, 0.5, 0.5)
        glVertex3f(-0.5, -0.5, 0.5)
        glVertex3f(0.5, -0.5, 0.5)

        glColor3f(0.0, 0.0, 1.0)

        glVertex3f(0.5, -0.5, -0.5)
        glVertex3f(-0.5, -0.5, -0.5)
        glVertex3f(-0.5, 0.5, -0.5)
        glVertex3f(0.5, 0.5, -0.5)

        # green face
        glColor3f(0.0, 1.0, 0.0)

        glVertex3f(-0.5, 0.5, 0.5)
        glVertex3f(-0.5, 0.5, -0.5)
        glVertex3f(-0.5, -0.5, -0.5)
        glVertex3f(-0.5, -0.5, 0.5)

        # green face
        glColor3f(0.0, 1.0, 0.0)

        glVertex3f(0.5, 0.5, -0.5)
        glVertex3f(0.5, 0.5, 0.5)
        glVertex3f(0.5, -0.5, 0.5)
        glVertex3f(0.5, -0.5, -0.5)
        glEnd()

    @staticmethod
    def drawAxis():
        glLineWidth(5.0)
        glBegin(GL_LINES)

        glColor3f(1.0, 1.0, 1.0)
        glVertex3f(-1.0, 0.0, 0.0)
        glVertex3f(1.0, 0.0, 0.0)

        glColor3f(1.0, 1.0, 1.0)
        glVertex3f(0.0, -1.0, 0.0)
        glVertex3f(0.0, 1.0, 0.0)

        glColor3f(1.0, 1.0, 1.0)
        glVertex3f(0.0, 0.0, -1.0)
        glVertex3f(0.0, 0.0, 1.0)
        glEnd()

        # Add arrows
        glBegin(GL_TRIANGLES)

        # x-axis arrow
        glColor3f(1.0, 1.0, 1.0)
        glVertex3f(1.0, 0.0, 0.0)
        glVertex3f(0.9, 0.1, 0.0)
        glVertex3f(0.9, -0.1, 0.0)
        # y-axis arrow
        glColor3f(1.0, 1.0, 1.0)
        glVertex3f(0.0, 1.0, 0.0)
        glVertex3f(0.1, 0.9, 0.0)
        glVertex3f(-0.1, 0.9, 0.0)
        # z-axis arrow
        glColor3f(1.0, 1.0, 1.0)
        glVertex3f(0.0, 0.0, 1.0)
        glVertex3f(0.0, 0.1, 0.9)
        glVertex3f(0.0, -0.1, 0.9)
        glEnd()

    def updateRotation(self, angle, rx, ry, rz):
        self.rotate = np.array([angle, rx, ry, rz])
        self.update()


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.wig = OpenGLWidget()
        self.setWindowTitle("OpenGL Cube Rotation")
        self.setGeometry(100, 100, 800, 600)
        self.setCentralWidget(self.wig)

    def update_rotation(self, angle, rx, ry, rz):
        self.wig.updateRotation(angle, rx, ry, rz)
        self.wig.update()

    def reset_rotation(self):
        self.wig.rotate = np.array([0.0, 0.0, 0.0, 0.0])
        self.wig.update()


def socket_recv(window):
    # 创建一个UDP socket
    reader = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 绑定端口
    reader.bind(('192.168.143.32', 8888))

    # 键盘输入
    while True:
        # 接收imu数据 rx, ry, rz
        response, _ = reader.recvfrom(4096)
        print('Server response:', response.decode())
        angle, rx, ry, rz = response.decode().split(' ')
        window.update_rotation(float(angle), float(rx), float(ry), float(rz))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.reset_rotation()
    thread = threading.Thread(target=socket_recv, args=(mainWindow,))
    thread.start()
    mainWindow.show()
    sys.exit(app.exec_())

显示效果
IMU姿态

  • 15
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由于IMU姿态解算涉及到许多数学知识和算法,因此需要一定的数学和编程基础才能进行。以下是一个简单的基于卡尔曼滤波的IMU姿态解算MATLAB代码示例: ```matlab % IMU姿态解算MATLAB代码示例 % 初始化状态向量,包括姿态、角速度和角度偏差 x = [0 0 0 0 0 0 0 0 0]'; % 初始化状态协方差矩阵 P = eye(9); % 初始化IMU测量误差协方差矩阵 R = diag([0.1 0.1 0.1 0.01 0.01 0.01]); % 初始化IMU测量噪声 Q = diag([0.001 0.001 0.001 0.0001 0.0001 0.0001]); % 初始化时间步长 dt = 0.01; % 加载IMU数据 load imu_data.mat; % 计算IMU数据长度 n = length(imu_data); % 初始化姿态角度 pitch = zeros(n,1); roll = zeros(n,1); yaw = zeros(n,1); % 开始姿态解算 for i=2:n % 计算角度变化 wx = imu_data(i,1); wy = imu_data(i,2); wz = imu_data(i,3); ax = imu_data(i,4); ay = imu_data(i,5); az = imu_data(i,6); [pitch(i),roll(i),yaw(i)] = imu_filter(wx, wy, wz, ax, ay, az, dt, x); end % 绘制姿态角度图像 plot(pitch); hold on; plot(roll); plot(yaw); legend('pitch','roll','yaw'); xlabel('Sample'); ylabel('Angle (deg)'); % 定义姿态解算函数 function [pitch,roll,yaw] = imu_filter(wx, wy, wz, ax, ay, az, dt, x) % 计算旋转矩阵和旋转角度 R = rotx(x(1))*roty(x(2))*rotz(x(3)); [yaw,pitch,roll] = dcm2angle(R); pitch = pitch*180/pi; roll = roll*180/pi; yaw = yaw*180/pi; % 构建状态转移矩阵 A = [eye(3) -R*dt zeros(3,3); zeros(3,3) eye(3) -dt*eye(3); zeros(3,3) zeros(3,3) eye(3)]; % 构建控制矩阵 B = [zeros(3,3);eye(3);zeros(3,3)]; % 计算预测状态和协方差矩阵 x = A*x + B*[wx;wy;wz;ax;ay;az]; P = A*P*A' + Q; % 构建测量矩阵 H = [zeros(3,6) eye(3)]; % 计算卡尔曼增益 K = P*H'/(H*P*H' + R); % 计算测量残差 z = [ax;ay;az]; z_hat = H*x; y = z - z_hat; % 更新状态和协方差矩阵 x = x + K*y; P = (eye(9) - K*H)*P; % 返回姿态角度 pitch = x(1); roll = x(2); yaw = x(3); end % 定义旋转矩阵函数 function R = rotx(theta) c = cosd(theta); s = sind(theta); R = [1 0 0; 0 c -s; 0 s c]; end function R = roty(theta) c = cosd(theta); s = sind(theta); R = [c 0 s; 0 1 0; -s 0 c]; end function R = rotz(theta) c = cosd(theta); s = sind(theta); R = [c -s 0; s c 0; 0 0 1]; end ``` 该代码使用了卡尔曼滤波算法进行IMU姿态解算,包括状态预测、测量更新和状态更新等步骤。通过加载IMU数据,计算角度变化并传入姿态解算函数进行处理,最终得到姿态角度数据并绘制出图像。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值