您现在的位置是:网站首页> AI人工智能

AI硬件

摘要

AI硬件

1.jpg


👍笔记本如何玩AI🟢一个视频解决笔记本玩AI的所有问题

深度相机

jetson开发板

AI开发板怎么选

小智AI机器人专题

小智esp32c3

小智ai机智能聊天器人

小智AI机器人主页(各类板子固件下载等各类资料)源码主页,点击查看文档

代码模拟解析




👍笔记本如何玩AI🟢一个视频解决笔记本玩AI的所有问题

笔记本+二手主机+扩展坞外置显卡

闲鱼购买主板:e5-2666v3x99板套装



深度相机

深度摄像头和普通摄像头最大的区别在于其工作原理不同。普通摄像头只能够获取二维图像信息,无法获得物体的深度、厚度等三维信息。而深度摄像头则具有立体视觉感知系统,能够同时获取物体的空间位置和深度信息


工业相机和普通相机的区别:

1、工业相机的性能稳定可靠易于安装,结构紧凑结实不易损坏,可连续工作时间长,在较差的环境下也能使用,而普通相机是做不到这些的。

2、工业相机的快门时间非常短,可以抓拍高速运动的物体。高速旋转移动的物体,用工业相机抓拍一张图像,仍能够清晰辨别,这是普通相机做不到的。

3、工业相机的图像传感器是逐行扫描的,而普通的相机的图像传感器是隔行扫描的, 逐行扫描的图像传感器生产工艺比较复杂,成品率低,出货量少。

4、工业相机的帧率远远高于普通相机。工业相机每秒可以拍摄十幅到几百幅图片,而普通相机只能拍摄2-3幅图像,相差较大。

5、工业相机输出的是裸数据,其光谱范围也往往比较宽,比较适合进行高质量的图像处理算法,而普通相机拍摄的图片,其光谱范围只适合人眼视觉,图像质量较差,不利于分析处理。

6、 工业相机相对普通相机来说价格更贵。


面阵相机,感光芯片为面型,被测物体可以静止也可以运动,相机每次曝光就能够拍摄一张照片。运动拍照时,只要曝光时间(即拍摄一张照片的时间)足够短,能够小于被测物运动一个精度的时间,就能保证图像的精度。

线阵相机,感光芯片为线型,被测物体和相机间要有相对运动状态才能成像,有非常高的行频和横向分辨率,价格较高。


主要参数

感光芯片尺寸:面阵相机以芯片对角线的长度来度量,线阵相机以感光芯片的横向长度度量。

像素深度:是指存储每个像素所用的数据位数,对于黑白相机,像素深度定义了灰度值从全黑到过曝的灰阶数。常用8位像元深度的相机,输出的图像等级是2的八次方。即0-255,共256级,也有像元深度10位的相机,共1024级。

分辨率:感光芯片上有多少格像元,就是多少分辨率的相机,像素越多,分辨率越高,展示就越细节。

精度:用来描述图像上每个像素的实际物理尺寸。

帧率、行频:面阵相机的帧率是指一秒钟能拍多少张图像,线阵相机的行频是指一秒钟内相机扫描多少行。

增益:是指输入信号和输出信号的放大比例,通常用来提升整体亮度。

噪点:指感光芯片把光信号变成电信号并输出的过程中产生的不属于物体的部分影像。信噪比是指真实图像信号与图像噪声的比例。

光谱响应:感光芯片对光不同波长的响应能力不一样,一般会用响应曲线表示,可按感应光谱区分为:普通可见光相机,红外相机,紫外相机等。

触发:相机接收一次触发信号就会采集一次图像;还可以设置延时,收到触发信号过了设置好的时间再拍照。同样具备触发输出功能,拍照时候也可同时发送一个信号到其他的器件共同工作。

曝光时间:感光芯片接收光照射的时间,通常曝光时间越长图像越亮,但曝光时间过长可能产生拖影。曝光方式主要可分为行曝光和帧曝光。譬如:在被测物与相机相对运动时,线阵相机采用的就是逐行曝光,一次采集一行图像;面阵相机采用的就是帧曝光,一次采集一张图像。


相机的标准

相机通用协议(GenICam),目的是全行业实现相同应用编程接口。

通用传输层(GenTL):将传输层编程接口标准化;

通用应用编程接口(GenApi):用于设计相机的应用程序开发接口;

标准特点命名规范(SFNC):将相机子描述文件中的相机特点的名称、类型、意义和使用标准化;

传输接口:

GigE:应用最广泛的相机标准接口,基于以太网通信标准制定;

USB3.0:接口简单,即插即用,便于安装,高性能;

IEEE1394:俗称火线,苹果公司在1987年发行的串行标准,传输速度高且稳定;

Camera Link:一款强大、完善的通信接口方式,把相机和图像采集卡之间的连接标准化,包括提供数据传输、相机定时、串口通信和实时向相机发送信号;

同轴线缆(CoaXPress):其在1km的电缆长度内可提供的传输速度可达惊人的1Gbit/s,已经能够满足多数应用场景。



AI开发板怎么选

没钱:RK3566 RK3568 RK3562 RK3576 RK3588 RK3588S  华为Altlas开发板 香橙派AI pro

有钱:jetson Jetson AGX Orin

Seeed Grove Vision AI V2(图像识别,k230 k230d)

地瓜机器人RDK X5



代码模拟解析

已实现功能

Wi-Fi / ML307 Cat.1 4G

离线语音唤醒 ESP-SR

支持两种通信协议(Websocket 或 MQTT+UDP)

采用 OPUS 音频编解码

基于流式 ASR + LLM + TTS 架构的语音交互

声纹识别,识别当前说话人的身份 3D Speaker

OLED / LCD 显示屏,支持表情显示

电量显示与电源管理

支持多语言(中文、英文、日文)

支持 ESP32-C3、ESP32-S3、ESP32-P4 芯片平台

通过设备端 MCP 实现设备控制(音量、灯光、电机、GPIO 等)

通过云端 MCP 扩展大模型能力(智能家居控制、PC桌面操作、知识搜索、邮件收发等)



小智 AI 硬件端将语音推送到平台的技术流程主要涉及语音采集、音频编码、网络传输三个核心环节,以下从技术角度详细解析并提供关键代码示例(以 ESP32-S3 平台为例):

一、技术流程解析

语音采集

硬件端通过麦克风(如 INMP441 全向麦克风)采集模拟语音信号,经 ADC 转换为数字信号(PCM 格式),通常配置为:

采样率:16kHz(语音识别常用)

位深:16bit(单声道)

数据格式:Little-endian

音频预处理与编码

原始 PCM 数据体积较大(16kHz×16bit=32kb/s),需压缩编码(如 MP3、AAC 或 OPUS),减少网络传输带宽。ESP32 可通过硬件编解码模块或软件库(如libmp3lame)实现。

网络传输

通过 WiFi 或 4G 模块(如 EC20)将编码后的音频数据以流式传输方式发送到平台,常用协议:

HTTP POST:适合短语音片段(如唤醒词后的指令)

WebSocket:适合长对话(保持连接,实时推送)

二、关键代码实现(ESP32-S3 + Arduino 框架)

以下代码包含语音采集、MP3 编码、WiFi 传输的核心逻辑:

1. 依赖库与初始化

需安装 ESP32Audio(音频采集)、WiFi(网络)、libmp3lame(MP3 编码)库。

三、关键技术说明

音频采集优化

若使用模拟麦克风,需通过analogRead()采集并做降噪处理(如滑动平均滤波)。

I2S 接口可直接对接数字麦克风,减少干扰,代码中需正确配置BCLK_PIN(位时钟)、LRC_PIN(左右声道)、DOUT_PIN(数据输出)。

编码效率

MP3 编码在 ESP32 上可能占用较多 CPU,可改用更轻量的编码(如 ADPCM),或使用硬件编解码模块(如 ES8388)。

流式传输

长语音场景建议用 WebSocket(如WebSocketsClient库),保持连接并分帧发送,示例中 HTTP POST 适合短语音(10 秒内)。

平台交互

后端平台需提供音频接收接口,解析 MP3 后调用 ASR(语音识别)服务(如百度 AI、讯飞),再将文本返回给硬件端。


模拟代码

硬件端:

#include <WiFi.h>

#include <HTTPClient.h>

#include <Audio.h>       // 音频采集库

#include "lame.h"       // MP3编码库


// 配置参数

const char* ssid = "你的WiFi名称";

const char* password = "你的WiFi密码";

const char* server_url = "https://你的平台API地址"; // 接收语音的后端接口


// 音频采集配置

AudioInputI2S audioInput;  // 假设使用I2S麦克风(如INMP441)

const int sampleRate = 16000;

const int bitsPerSample = 16;

const int bufferSize = 1024; // 音频缓冲区大小


// MP3编码配置

lame_global_struct* lame;

unsigned char mp3Buffer[bufferSize * 2]; // 编码后缓冲区


// WiFi客户端

WiFiClient client;

HTTPClient http;


void setup() {

  Serial.begin(115200);

  

  // 1. 初始化WiFi

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

    Serial.print(".");

  }

  Serial.println("WiFi连接成功");


  // 2. 初始化音频采集

  audioInput.setPinout(BCLK_PIN, LRC_PIN, DOUT_PIN); // 配置I2S引脚(依硬件定义)

  audioInput.setSampleRate(sampleRate);

  audioInput.setBitsPerSample(bitsPerSample);


  // 3. 初始化MP3编码器

  lame = lame_init();

  lame_set_in_samplerate(lame, sampleRate);

  lame_set_num_channels(lame, 1); // 单声道

  lame_set_brate(lame, 32); // 比特率32kbps

  lame_init_params(lame);

}


void loop() {

  if (WiFi.status() != WL_CONNECTED) {

    Serial.println("WiFi断开,重新连接...");

    WiFi.reconnect();

    delay(1000);

    return;

  }


  // 4. 采集PCM数据

  int16_t pcmBuffer[bufferSize];

  int bytesRead = audioInput.read(pcmBuffer, bufferSize);

  

  if (bytesRead > 0) {

    // 5. PCM转MP3编码

    int mp3Size = lame_encode_buffer(lame, 

                                    pcmBuffer,  // 左声道PCM

                                    NULL,       // 右声道(单声道为NULL)

                                    bytesRead,  // 样本数

                                    mp3Buffer,  // 输出缓冲区

                                    sizeof(mp3Buffer));


    if (mp3Size > 0) {

      // 6. 发送MP3数据到平台

      sendAudioToServer(mp3Buffer, mp3Size);

    }

  }

}


// 发送音频数据到平台

void sendAudioToServer(unsigned char* data, int len) {

  http.begin(client, server_url);

  http.addHeader("Content-Type", "audio/mpeg"); // 声明MP3格式

  http.addHeader("Authorization", "Bearer 你的API密钥"); // 平台认证


  int httpCode = http.POST(data, len);

  if (httpCode == 200) {

    Serial.println("音频推送成功");

    String response = http.getString();

    Serial.println("平台响应:" + response); // 可解析平台返回的文本结果

  } else {

    Serial.printf("推送失败,错误码:%d\n", httpCode);

  }

  http.end();

}


服务端模拟代码:

from fastapi import FastAPI, UploadFile, File, HTTPException

from fastapi.responses import JSONResponse

import whisper

import openai

import os

import tempfile

from pydantic import BaseModel


# 配置项(请替换为实际值)

OPENAI_API_KEY = "你的OpenAI API密钥"

WHISPER_MODEL = "base"  # 可选:tiny/base/small/medium/large(精度递增,资源需求递增)

AI_MODEL = "gpt-3.5-turbo"  # 或其他模型如gpt-4


# 初始化服务

app = FastAPI(title="小智AI语音处理服务")

openai.api_key = OPENAI_API_KEY


# 加载Whisper语音识别模型

asr_model = whisper.load_model(WHISPER_MODEL)


class AIChatResponse(BaseModel):

    text: str  # AI回复文本

    request_id: str  # 请求唯一标识


@app.post("/api/voice/process", response_model=AIChatResponse)

async def process_voice(file: UploadFile = File(...)):

    """接收语音文件,转文字后调用AI处理"""

    try:

        # 1. 验证文件格式

        if not file.filename.endswith((".mp3", ".wav", ".m4a")):

            raise HTTPException(status_code=400, detail="仅支持MP3/WAV/M4A格式音频")


        # 2. 保存临时音频文件

        with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_file:

            content = await file.read()

            temp_file.write(content)

            temp_file_path = temp_file.name


        # 3. 语音识别(Whisper)

        # 自动检测语言并转文字

        result = asr_model.transcribe(temp_file_path, language="zh")  # 强制中文识别

        recognized_text = result["text"].strip()

        print(f"识别到文本: {recognized_text}")


        # 4. 调用AI模型处理

        ai_response = openai.ChatCompletion.create(

            model=AI_MODEL,

            messages=[

                {"role": "system", "content": "你是小智AI助手,用简洁友好的语言回复用户"},

                {"role": "user", "content": recognized_text}

            ],

            temperature=0.7  # 控制回复随机性

        )

        ai_text = ai_response.choices[0].message["content"].strip()


        # 清理临时文件

        os.unlink(temp_file_path)


        return {

            "text": ai_text,

            "request_id": ai_response.id  # 使用OpenAI的请求ID作为唯一标识

        }


    except Exception as e:

        print(f"处理错误: {str(e)}")

        raise HTTPException(status_code=500, detail=f"服务处理失败: {str(e)}")


# 启动服务(本地测试用)

if __name__ == "__main__":

    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=8000)  # 监听所有网络接口,端口8000


终端解码播放

#include "opus/opus.h"

#include "driver/i2s.h"

#include <stdlib.h>

#include <string.h>


// 音频配置参数

#define SAMPLE_RATE 16000    // 采样率:16kHz

#define CHANNELS 1           // 单声道

#define FRAME_SIZE 320       // 帧大小(16000Hz下20ms对应320样本)

#define MAX_PACKET_SIZE 1024 // 最大OPUS数据包大小


// OPUS解码器实例

static OpusDecoder *decoder = NULL;

static int decoder_error;


// 初始化OPUS解码器

bool opus_decoder_init() {

    // 创建OPUS解码器

    decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &decoder_error);

    if (decoder_error != OPUS_OK || decoder == NULL) {

        printf("OPUS decoder init failed: %d\n", decoder_error);

        return false;

    }

    

    // 初始化I2S音频输出(根据硬件配置调整)

    i2s_config_t i2s_config = {

        .mode = I2S_MODE_MASTER | I2S_MODE_TX,

        .sample_rate = SAMPLE_RATE,

        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,

        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // 单声道

        .communication_format = I2S_COMM_FORMAT_STAND_I2S,

        .dma_buf_count = 4,

        .dma_buf_len = 1024,

        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1

    };

    

    i2s_pin_config_t pin_config = {

        .bck_io_num = 26,  // 音频时钟线(根据硬件定义)

        .ws_io_num = 25,   // 声道选择线

        .data_out_num = 22,// 数据输出线

        .data_in_num = -1  // 不使用输入

    };

    

    if (i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL) != ESP_OK) {

        printf("I2S driver install failed\n");

        return false;

    }

    

    if (i2s_set_pin(I2S_NUM_0, &pin_config) != ESP_OK) {

        printf("I2S set pin failed\n");

        i2s_driver_uninstall(I2S_NUM_0);

        return false;

    }

    

    printf("OPUS decoder and I2S initialized\n");

    return true;

}


// 解码并播放OPUS音频数据

void opus_decode_and_play(uint8_t *opus_data, int data_len) {

    if (!decoder || !opus_data || data_len <= 0) return;

    

    // 分配PCM输出缓冲区(16位采样)

    int16_t pcm_buffer[FRAME_SIZE * 2]; // 预留双倍空间防止溢出

    memset(pcm_buffer, 0, sizeof(pcm_buffer));

    

    // 解码OPUS数据为PCM

    int decoded_samples = opus_decode(

        decoder,

        opus_data,

        data_len,

        pcm_buffer,

        FRAME_SIZE,

        0 // 不需要向前兼容

    );

    

    if (decoded_samples < 0) {

        printf("OPUS decode error: %d\n", decoded_samples);

        return;

    }

    

    // 通过I2S播放PCM数据

    size_t bytes_written;

    i2s_write(I2S_NUM_0, 

              pcm_buffer, 

              decoded_samples * sizeof(int16_t), 

              &bytes_written, 

              portMAX_DELAY);

}


// 释放解码器资源

void opus_decoder_destroy() {

    if (decoder) {

        opus_decoder_destroy(decoder);

        decoder = NULL;

    }

    i2s_driver_uninstall(I2S_NUM_0);

}









Top