基于STM32设计的人体健康检测仪

news2024/9/23 11:17:20

一、项目介绍

当前文章介绍基于STM32设计的人体健康检测仪。设备采用STM32系列MCU作为主控芯片,配备血氧浓度传感器(使用MAX30102血氧浓度检测传感器)、OLED屏幕和电池供电等外设模块。设备可以广泛应用于医疗、健康等领域。可以帮助医生和病人更好地了解病情变化,提高治疗效果和生活质量。设备也可以用于健康管理、运动监测等场景,帮助用户了解自己的身体状况,保持健康的生活方式。

在项目中,使用了KEIL作为开发平台和工具,通过血氧模块采集人体的心跳和血氧浓度参数,并通过OLED屏幕显示现在的心跳和血氧浓度。同时,通过指标分析,提供采集到的数据与正常指标比对,分析被检测人员的健康状态。采集的数据可通过蓝牙或者WIFI传递给手机APP进行处理,方便用户随时了解自己的身体状况。

本设计采用STM32为主控芯片,搭配血氧浓度传感器和OLED屏幕,实现了人体健康数据的采集和展示,并对采集到的数据进行分析,判断被检测人员的健康状态。同时,设计使用蓝牙或WiFi将采集到的数据传递给手机APP进行处理。

image-20230618132149185

image-20230618132108207

二、项目设计思路

2.1 硬件设计

(1)主控芯片:STM32系列MCU,负责驱动其他外设模块;

(2)血氧浓度传感器:使用MAX30102血氧浓度检测传感器,用于采集人体的心跳和血氧浓度参数;

(3)OLED屏:用于显示现在的心跳和血氧浓度;

2.2 软件设计

(1) 通过血氧模块采集人体的心跳和血氧浓度参数;

(2) 通过OLED屏显示现在的心跳和血氧浓度;

(3) 对采集到的数据进行指标分析,将采集到的数据与正常指标比对,分析被检测人员的健康状态;

(4) 采集的数据可通过蓝牙或WiFi传递给手机APP进行处理。

2.3 技术实现

(1)设计采用AD8232心电图(ECG)模块和MAX30102血氧模块采集心跳和血氧浓度参数,并通过I2C接口连接主控芯片STM32。

(2)OLED屏使用I2C接口与主控芯片STM32连接。

(3)采集到的数据通过算法进行指标分析,将采集到的数据与正常指标比对,判断被检测人员的健康状态。

(4)设备通过蓝牙或WiFi将采集到的数据传递给手机APP进行处理。

三、代码设计

3.1 MAX30102血氧模块代码

I2C协议代码:

#define MAX30102_I2C_ADDR 0xAE

void MAX30102_I2C_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    I2C_InitTypeDef   I2C_InitStructure;

    /* Enable GPIOB clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    /* Enable I2C1 and I2C2 clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 | RCC_APB1Periph_I2C2, ENABLE);

    // Configure I2C SCL and SDA pins
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // Open-drain output
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // Configure I2C parameters
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 100000; // 100KHz
    I2C_Init(I2C1, &I2C_InitStructure);

    // Enable I2C
    I2C_Cmd(I2C1, ENABLE);
}

void MAX30102_I2C_WriteReg(uint8_t reg, uint8_t value)
{
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, MAX30102_I2C_ADDR, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(I2C1, reg);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_SendData(I2C1, value);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTOP(I2C1, ENABLE);
}

uint8_t MAX30102_I2C_ReadReg(uint8_t reg)
{
    uint8_t value;

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, MAX30102_I2C_ADDR, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(I2C1, reg);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, MAX30102_I2C_ADDR, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

    I2C_AcknowledgeConfig(I2C1, DISABLE);
    value = I2C_ReceiveData(I2C1);

    I2C_GenerateSTOP(I2C1, ENABLE);

    return value;
}

void MAX30102_I2C_ReadArray(uint8_t reg, uint8_t* data, uint8_t len)
{
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, MAX30102_I2C_ADDR, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(I2C1, reg);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, MAX30102_I2C_ADDR, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

    while(len > 1)
    {
        I2C_AcknowledgeConfig(I2C1, ENABLE);
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
        *data++ = I2C_ReceiveData(I2C1);
        len--;
    }

    I2C_AcknowledgeConfig(I2C1, DISABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
    *data++ = I2C_ReceiveData(I2C1);

    I2C_GenerateSTOP(I2C1, ENABLE);
}

MAX30102的初始化函数和数据获取函数:

void MAX30102_Init(void)
{
    MAX30102_I2C_Init();

    // Reset the device
    MAX30102_I2C_WriteReg(0x09, 0x40);
    HAL_Delay(100);
    MAX30102_I2C_WriteReg(0x09, 0x00);

    // Set FIFO average to 4 samples
    MAX30102_I2C_WriteReg(0x08, 0x03);

    // Set LED pulse amplitude
    MAX30102_I2C_WriteReg(0x0C, 0x1F);
    MAX30102_I2C_WriteReg(0x0D, 0x1F);

    // Set sample rate to 100Hz
    MAX30102_I2C_WriteReg(0x0F, 0x04);

    // Enable the red LED only
    MAX30102_I2C_WriteReg(0x11, 0x02);

    // Read the temperature value to start a reading
    MAX30102_I2C_ReadReg(0x1F);
}

uint32_t MAX30102_GetHeartRate(void)
{
    uint8_t buffer[MAX30102_FIFO_DEPTH*4];
    MAX30102_Data sensor_data = {0};
    uint16_t ir_value;
    uint16_t red_value;
    uint8_t byte_count, fifo_overflow;

    // Check if any data is available in FIFO
    byte_count = MAX30102_I2C_ReadReg(0x06) - MAX30102_I2C_ReadReg(0x04);
    if(byte_count > 0)
    {
        fifo_overflow = MAX30102_I2C_ReadReg(0x09) & 0x80;

        // Read the data from FIFO
        MAX30102_I2C_ReadArray(0x07, buffer, byte_count);

        // Parse the data
        for(int i=0; i<byte_count; i+=4)
        {
            ir_value = ((uint16_t)buffer[i] << 8) | buffer[i+1];
            red_value = ((uint16_t)buffer[i+2] << 8) | buffer[i+3];

            // Update the sensor data
            MAX30102_UpdateData(&sensor_data, ir_value, red_value);
        }

        if(!fifo_overflow && MAX30102_CheckForBeat(sensor_data.IR_AC_Signal_Current))
        {
            return MAX30102_HeartRate(sensor_data.IR_AC_Signal_Previous, 16);
        }
    }

    return 0;
}

数据处理函数:

void MAX30102_UpdateData(MAX30102_Data* data, uint16_t ir_value, uint16_t red_value)
{
    int32_t ir_val_diff = ir_value - data->IR_AC_Signal_Current;
    int32_t red_val_diff = red_value - data->Red_AC_Signal_Current;

    // Update IR AC and DC signals
    data->IR_AC_Signal_Current = (ir_val_diff + (7 * data->IR_AC_Signal_Previous)) / 8;
    data->IR_DC_Signal_Current = (ir_value + data->IR_AC_Signal_Current + (2 * data->IR_DC_Signal_Current)) / 4;
    data->IR_AC_Signal_Previous = data->IR_AC_Signal_Current;

    // Update Red AC and DC signals
    data->Red_AC_Signal_Current = (red_val_diff + (7 * data->Red_AC_Signal_Previous)) / 8;
    data->Red_DC_Signal_Current = (red_value + data->Red_AC_Signal_Current + (2 * data->Red_DC_Signal_Current)) / 4;
    data->Red_AC_Signal_Previous = data->Red_AC_Signal_Current;

    // Update IR and Red AC signal peak-to-peak values
    if(data->IR_AC_Signal_Current > data->IR_AC_Max)
        data->IR_AC_Max = data->IR_AC_Signal_Current;
    else if(data->IR_AC_Signal_Current < data->IR_AC_Min)
        data->IR_AC_Min = data->IR_AC_Signal_Current;

    if(data->Red_AC_Signal_Current > data->Red_AC_Max)
        data->Red_AC_Max = data->Red_AC_Signal_Current;
    else if(data->Red_AC_Signal_Current < data->Red_AC_Min)
        data->Red_AC_Min = data->Red_AC_Signal_Current;
}

uint8_t MAX30102_CheckForBeat(int32_t ir_val)
{
    static uint8_t beat_detection_enabled = 1;
    static uint32_t last_beat_time = 0;
    static int32_t threshold = 0x7FFFFF;

    uint32_t delta_time;
    int32_t beat_amplitude;

    if(beat_detection_enabled)
    {
        // Increment the beat counter
        MAX30102_beat_counter++;

        // Calculate the threshold value
        threshold += (ir_val - threshold) / 8;

        // Check if a beat has occurred
        if(ir_val > threshold && MAX30102_beat_counter > 20)
        {
            delta_time = micros() - last_beat_time;
            last_beat_time = micros();
            beat_amplitude = ir_val - threshold;
            if(delta_time < 1000 || delta_time > 2000 || beat_amplitude < 20 ||
            beat_amplitude > 1000) { return 0; }
                   // Reset the beat counter and set the threshold value
        MAX30102_beat_counter = 0;
        threshold = ir_val;

        return 1;
    }
}

return 0;
}

uint32_t MAX30102_HeartRate(int32_t ir_val, uint8_t samples) { int32_t ir_val_sum = 0;
// Calculate the sum of IR values
for(int i=0; i<samples; i++)
{
    ir_val_sum += MAX30102_IR_Sample_Buffer[i];
}

// Calculate the average IR value
ir_val_sum /= samples;

// Calculate the heart rate
return (uint32_t)(60 * MAX30102_SAMPLING_FREQUENCY / (ir_val - ir_val_sum));
}

3.2 OLED显示屏驱动代码

I2C协议代码:

#define SSD1306_I2C_ADDR 0x78

void SSD1306_I2C_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    I2C_InitTypeDef   I2C_InitStructure;

    /* Enable GPIOB clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    /* Enable I2C1 and I2C2 clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 | RCC_APB1Periph_I2C2, ENABLE);

    // Configure I2C SCL and SDA pins
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // Open-drain output
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // Configure I2C parameters
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 100000; // 100KHz
    I2C_Init(I2C1, &I2C_InitStructure);

    // Enable I2C
    I2C_Cmd(I2C1, ENABLE);
}

void SSD1306_I2C_WriteReg(uint8_t reg, uint8_t value)
{
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, SSD1306_I2C_ADDR, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(I2C1, 0x00);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_SendData(I2C1, reg);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_SendData(I2C1, value);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTOP(I2C1, ENABLE);
}

void SSD1306_I2C_WriteArray(uint8_t* data, uint16_t len)
{
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, SSD1306_I2C_ADDR, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    while(len--)
    {
        I2C_SendData(I2C1, *data++);
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    }

    I2C_GenerateSTOP(I2C1, ENABLE);
}

SSD1306的初始化函数和数据更新函数:

#define SSD1306_WIDTH 128
#define SSD1306_HEIGHT 64
#define SSD1306_BUFFER_SIZE (SSD1306_WIDTH*SSD1306_HEIGHT/8)

uint8_t SSD1306_Buffer[SSD1306_BUFFER_SIZE];

void SSD1306_Init(void)
{
    SSD1306_I2C_Init();

    // Turn display off
    SSD1306_DisplayOff();

    // Set the clock to a high value for faster data transfer
    SSD1306_I2C_WriteReg(0x0F, 0x80);

    // Set multiplex ratio to default value (63)
    SSD1306_I2C_WriteReg(0xA8, 0x3F);

    // Set the display offset to 0
    SSD1306_I2C_WriteReg(0xD3, 0x00);

    // Display start line is 0
    SSD1306_I2C_WriteReg(0x40, 0x00);

    // Set segment remap to inverted
    SSD1306_I2C_WriteReg(0xA1, 0xC0);

    // Set COM output scan direction to inverted
    SSD1306_I2C_WriteReg(0xC8, 0xC0);

    // Disable display offset shift
    SSD1306_I2C_WriteReg(0xD7, 0x9F);

    // Set display clock divide ratio/oscillator frequency to default value (8/0xF0)
    SSD1306_I2C_WriteReg(0xD5, 0xF0);

    // Enable charge pump regulator
    SSD1306_I2C_WriteReg(0x8D, 0x14);

    // Set memory addressing mode
    // Set the display to normal mode (not inverted)
SSD1306_I2C_WriteReg(0xA6, 0xA6);

// Set the contrast to a default value of 127
SSD1306_I2C_WriteReg(0x81, 0x7F);

// Turn the display back on
SSD1306_DisplayOn();

// Clear the display buffer
SSD1306_ClearBuffer();

// Update the display with the cleared buffer
SSD1306_UpdateDisplay();
}

void SSD1306_UpdateDisplay(void) { uint8_t column, page;
}for(page=0; page<8; page++)
{
    SSD1306_I2C_WriteReg(0xB0+page, 0x00);
    SSD1306_I2C_WriteReg(0x10, 0x00);
    SSD1306_I2C_WriteReg(0x00, 0x00);

    for(column=0; column<SSD1306_WIDTH; column++)
    {
        SSD1306_I2C_WriteArray(&SSD1306_Buffer[column + page*SSD1306_WIDTH], 1);
    }
}
}
void SSD1306_ClearBuffer(void) { memset(SSD1306_Buffer, 0x00, sizeof(SSD1306_Buffer)); }

void SSD1306_SetPixel(uint8_t x, uint8_t y, uint8_t color) { if(x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT) { return; }
}if(color)
{
    SSD1306_Buffer[x + (y/8)*SSD1306_WIDTH] |= (1 << (y%8));
}
else
{
    SSD1306_Buffer[x + (y/8)*SSD1306_WIDTH] &= ~(1 << (y%8));
}
}

四、总结

本设计采用STM32为主控芯片,配合血氧浓度传感器和OLED屏幕,实现了人体健康数据的采集和展示,并通过算法对采集到的数据进行分析,判断被检测人员的健康状态。同时,设计使用蓝牙或WiFi将采集到的数据传递给手机APP进行处理。设计基本满足了人体健康检测仪的技术要求和环境要求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/811194.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring源码(三)Spring Bean生命周期

Bean的生命周期就是指&#xff1a;在Spring中&#xff0c;一个Bean是如何生成的&#xff0c;如何销毁的 Bean生命周期流程图 1、生成BeanDefinition Spring启动的时候会进行扫描&#xff0c;会先调用org.springframework.context.annotation.ClassPathScanningCandidateCompo…

【C++入门到精通】C++入门 —— 类和对象(了解类和对象)

目录 一、类和对象的历史由来 二、面向过程和面向对象的初步认识 三、类 1.引子 2.类的定义 3.类的访问限定符及封装 ⭕访问限定符 &#x1f6a9;访问限定符解释说明 &#x1f6a9;struct 与 class 的区别 1. 默认访问级别&#xff1a; 2. 继承权限&#xff08;默认的…

安全基础 --- html标签 + 编码

html标签 &#xff08;1&#xff09;detail标签 <details>标签用来折叠内容&#xff0c;浏览器会折叠显示该标签的内容。 <1> 含义&#xff1a; <details> 这是一段解释文本。 </details> 用户点击这段文本&#xff0c;折叠的文本就会展开&#x…

山西电力市场日前价格预测【2023-07-31】

日前价格预测 预测明日&#xff08;2023-07-31&#xff09;山西电力市场全天平均日前电价为294.49元/MWh。其中&#xff0c;最高日前电价为318.11元/MWh&#xff0c;预计出现在19: 30。最低日前电价为278.89元/MWh&#xff0c;预计出现在00: 15。 价差方向预测 1&#xff1a;实…

Git远程仓库的创建、克隆、推送和拉取

文章目录 1.前言2.远程仓库的创建3.远程仓库的克隆3.1 使用HTTPS进行克隆3.2 使用SSH进行克隆 4.远程仓库的推送5. 远程仓库的拉取 1.前言 在之前的文章中,讲解了Git的一些基本概念和常用的命令. 是时候干一件大事了-实现多人协助开发! 环境:Centos7云服务器 代码托管平台: G…

基于LSTM神经网络的BIM对象识别【BIM+AI】

BIM 模型中的一个基本数据是对象的名称&#xff0c;尤其是房间。 没有专有名称&#xff0c;人们就不可能理解模型/设计的内容。 在本文中&#xff0c;我们尝试使用 Tensorflow 构建一个基于该数据识别房间的LSTM神经网络模型。 推荐&#xff1a;用 NSDT设计器 快速搭建可编程3D…

第一章HelloWorld

确认环境 java -version javac编写代码 public class HelloWorld{public static void main(String[] args){System.out.println("HelloWorld");} }编译运行 javac HelloWord.java编译java文件成class字节码文件 java HelloWorld运行.class字节码文件 备注 容易…

手把手教你使用stable diffusion生成自己的艺术二维码

艺术二维码制作指南 导读midjourneystable diffusion 环境准备安装stable diffusion webuisd-webui-qrcode-toolkit安装 草料二维码模型准备QR PatternQR Code MonsterIoC Lab Control Net 艺术二维码制作1. 二维码信息提取2. 使用QR Tookit生成二维码3. 下载二维码图片4. prom…

电脑维护指南:让你的战友始终高效稳定

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

管理类联考——写作——论说文——实战篇——立意篇——真题审题立意汇总分类

难度&#xff1a;*号越多越难&#xff0c;越需要看。 角度3——4种材料类型、4个立意对象、5种写作态度 寓言类材料**** 2022年 鸟类会飞是因为它们在进化中不断优化了其身体结构。飞行是一项较为特殊的运动&#xff0c;鸟类的躯干进化出了适合飞行的流线型。飞行也是一项需…

【数理知识】刚体基本运动

文章目录 1 刚体定义2 自由刚体3 两种基本运动1 平动2 转动 4 举例 11 计算质心位置&#xff0c;求差得到平移向量2 计算协方差矩阵3 奇异值分解4 计算旋转矩阵 Ref 1 刚体定义 刚体就是质点间距离保持不变的质点系。 刚体的空间位置由任意与刚体固连的不共线三点决定。 2 自…

HDMI协议实现彩条静态显示方块移动

文章目录 前言一、硬件原理1、硬件设计原理图2、引脚图 二、系统设计1、系统模块框图2、RTL视图3、RGB2DVI 模块框图4、ALTDDIO_OUT IP 核的信号框图 三、HDMI的行&场时序1、时序图2、常见显示器时序参数 四、源码1、video_driver(显示驱动模块)2、serializer_10_to_1(并转…

微信公众号接入AI ChatGPT机器人bot的详细教程

微信公众号可以与客服系统进行对接&#xff0c;实现智能自动回复或者人工回复的公众号客服系统实现对接的前提是需要公众号为认证的服务号&#xff0c;实现的功能概况&#xff1a;公众号客服接口对接&#xff0c;公众号模板消息提醒&#xff0c;网页授权获取到微信的昵称头像&a…

Python实现GA遗传算法优化支持向量机回归模型(SVR算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;最早是由美国的 John holland于20世…

tinkerCAD案例:24. Ruler - Measuring Lengths 标尺 -量勺

tinkerCAD案例&#xff1a;24. Ruler - Measuring Lengths 标尺 - 测量长度 Project Overview: 项目概况&#xff1a; A machine shop, where any idea can become a reality, can cost millions and million of dollars. Still, the most important tool in the shop is the…

基于Open3D的点云处理12-体素化

体素化Voxelization 体素&#xff08;voxel&#xff09;是像素&#xff08;pixel&#xff09;、体积&#xff08;volume&#xff09;和元素&#xff08;element&#xff09;的组合词&#xff0c;相当于3D空间中的像素; 体素化是通过用空间均匀大小的体素网格(voxel grid)来模…

openpnp - ReferenceStripFeeder 改版零件

文章目录 openpnp - ReferenceStripFeeder 改版零件概述笔记整体效果散料飞达主体磁铁仓盖板飞达编带中间压条飞达编带两边压条装配体用的8mm编带模型END openpnp - ReferenceStripFeeder 改版零件 概述 官方推荐了ReferenceStripFeeder的模型smd_strip_feeders_mod_tray.zip…

【C++学习】STL容器——vector

目录 一、vector的介绍及使用 1.1 vector的介绍 1.2 vector的使用 1.2.1 vector的定义 1.2.2 vector iterator 的使用 1.2.3 vector 空间增长问题 1.2.4 vector 增删查改 1.2.5 vector 迭代器失效问题&#xff08;重点&#xff09; 二、vector深度剖析及模拟实现 ​编辑…

【JavaSE】数组的定义与使用

【本节目标】 1. 理解数组基本概念 2. 掌握数组的基本用法 3. 数组与方法互操作 4. 熟练掌握数组相关的常见问题和代码 目录 1. 数组的基本概念 1.1什么是数组 1.2 数组的创建及初始化 1.3 数组的使用 2. 数组是引用类型 2.1基本类型变量与引用类型变量的区别 2.2再谈引用…

慎思笃行,兴业致远:金融行业的数据之道

《中庸》中说&#xff0c;“博学之&#xff0c;审问之&#xff0c;慎思之&#xff0c;明辨之&#xff0c;笃行之”。这段话穿越千年&#xff0c;指引着中国千行百业的发展。对于金融行业来说&#xff0c;庞大的数据量可以说是“博学”的来源。但庞大的数据体量&#xff0c;既是…