掘金 人工智能 2024年07月08日
帮助盲人“看到”世界的 AI 硬件,能行吗?
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了一款帮助盲人“看到”世界的 AI 硬件的开发尝试。该硬件通过摄像头拍摄物理世界,并将图像信息发送给多模态大模型进行理解,最终以语音形式告知用户前方的路况信息。文章详细介绍了硬件的开发流程,包括测试摄像头、麦克风、蓝牙、WIFI、网络连接以及大模型识别能力。

😄 **硬件设计与功能**: 该硬件旨在为盲人提供实时路况信息,帮助他们更好地感知周围环境。硬件包含摄像头、麦克风、网络连接模块(WIFI 和蓝牙)以及一个 ESP32 开发板。开发板用于控制硬件功能,并将摄像头拍摄的图像发送给大模型进行识别。

😊 **模块测试**: 文章详细介绍了对硬件各个模块的功能测试,包括摄像头、麦克风、蓝牙、WIFI 和网络连接。测试结果表明,所有模块均能正常工作,满足硬件开发需求。

😉 **大模型测试**: 作者使用 GPT-4o 对大模型识别路况的能力进行了测试,并以一张盲道被占的图片为例,展示了大模型可以识别出道路中的摩托车、盲道上的铁架和石块等影响盲道畅通的关键因素。

😎 **未来展望**: 文章最后总结了硬件开发的进展,并展望了未来的开发方向,包括进一步完善大模型的识别能力,以及提升硬件的整体性能和用户体验。

我们打算做一款帮助盲人“看到”世界的 AI 硬件。

这个想法的起因是某天中午下班,笔者正在路上走着,忽听到后面传来很轻的歌声。回头看,一个戴着墨镜的男人拿着盲杖,正摸索着沿盲道前行。生活中很少遇到盲人,于是特意留意了下。他立得很直,嘴巴轻轻开合发出歌声,虽然走得慢,却每一步都很扎实。笔者和他一起走了一段,看到前方的盲道上停了一辆摩托车。走在我前面另一个女生尝试去搬走摩托车,见状我也快步上前搭了把手,一起移开了它。因为赶时间,移开车后我就走开了,歌声也越来越远。

后来我想,假如没有人把车移开,就算有盲杖探路,可能也会给这位朋友造成一些不大不小的困扰吧。有什么办法可以提前告知他前方的路况吗?巧的是,多模态大模型能通过自然语言对话、理解图像,理论上正好能充当这位朋友的眼睛。

于是有了这个产品的尝试。

按设想,用户交互的流程是佩戴硬件->摄像头拍摄物理世界发给大模型->大模型理解后以语音形式告知用户前方的路况信息。硬件不可少的模块包括:摄像头、麦克风,网络连接先用WIFI,另外可能需要蓝牙连接手机。

选择的开发板是 XIAO ESP32 S3,笔者是 ESP32 开发的纯新人,故而拿到硬件之后先测试各个模块的功能,同时学习开发过程。

开发板真容如下:

测试代码直接选择的官方示例,地址: https://wiki.seeedstudio.com/cn/xiao_esp32s3_camera_usage/

测试摄像头

下方仅摘抄主要流程代码并在其中加上注释,可视作伪代码理解流程。

void photo_save(const char * fileName) {  // 调用摄像头拍摄一帧画面  camera_fb_t *fb = esp_camera_fb_get();  // 保存图像  writeFile(SD, fileName, fb->buf, fb->len);  // 释放图像 buffer  esp_camera_fb_return(fb);}// 图像存储到 SD 卡void writeFile(fs::FS &fs, const char * path, uint8_t * data, size_t len){  File file = fs.open(path, FILE_WRITE);  file.close();}// ESP32 的初始化代码void setup() {  // 初始化串口  Serial.begin(115200);  // 初始化相机  esp_err_t err = esp_camera_init(&config);}// ESP32 的循环程序入口void loop() {  char filename[32];  sprintf(filename, "/image1.jpg");  photo_save(filename);  Serial.printf("Saved picture: %s\r\n", filename);}

上面的代码执行完毕会在 SD 卡中保存摄像头拍摄的画面,我们在其中找到下图,是笔者电脑屏幕正播放的内容,摄像头功能正常。

测试麦克风

void setup() {  Serial.begin(115200);  // 设置 I2S 接口使用的引脚,并初始化 I2S 接口  I2S.setAllPins(-1, 42, 41, -1, -1);  I2S.begin(PDM_MONO_MODE, SAMPLE_RATE, SAMPLE_BITS)  // 麦克风开始录制音频  record_wav();}void loop() {  // 不执行复杂逻辑}void record_wav(){  // 打开要保存的音频文件  File file = SD.open("/"WAV_FILE_NAME".wav", FILE_WRITE);  // 生成 wav 格式文件的头信息  generate_wav_header(wav_header, record_size, SAMPLE_RATE);  // 往 wav 文件写头信息  file.write(wav_header, WAV_HEADER_SIZE);  // 开始记录音频  esp_i2s::i2s_read(esp_i2s::I2S_NUM_0, rec_buffer, record_size, &sample_size, portMAX_DELAY);  // 往 wav 文件保存音频  file.write(rec_buffer, record_size)  // 释放 buffer  free(rec_buffer);  file.close();}

上面代码执行完毕后,会在 SD 卡中保存麦克风录制的 20 秒音频文件,我们看到确实保存了,且播放正常。

测试蓝牙

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {    void onResult(BLEAdvertisedDevice advertisedDevice) {      Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());    }};void setup() {  Serial.begin(115200);  Serial.println("Scanning...");  BLEDevice::init("");  pBLEScan = BLEDevice::getScan();  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());  pBLEScan->setActiveScan(true);  pBLEScan->setInterval(100);  pBLEScan->setWindow(99);}void loop() {   // 开始扫描蓝牙信号  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);  Serial.print("Devices found: ");  Serial.println(foundDevices.getCount());  Serial.println("Scan done!");  pBLEScan->clearResults();  delay(10000);}

上述代码执行完毕会列出附近扫描到的蓝牙信号,打开 Serial Monitor,可以看到正常扫描得到了结果:

测试 WIFI

void setup() {  Serial.begin(115200);}void loop() {  // 开始扫描 WIFI 信号,返回附近的 WIFI 数量  int n = WiFi.scanNetworks();  Serial.println("scan done");  if (n == 0) {      Serial.println("no networks found");  } else {    Serial.print(n);    Serial.println(" networks found");    for (int i = 0; i < n; ++i) {      // 打印 WIFI 信息      Serial.print(i + 1);      Serial.print(": ");      Serial.print(WiFi.SSID(i));      Serial.print(" (");      Serial.print(WiFi.RSSI(i));      Serial.print(")");      Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*");      delay(10);    }  }  Serial.println("");  // 延迟 5s 进行下一次扫描  delay(5000);}

上述代码运行完毕会列出周围 WIFI 的信息,实际结果显示工作正常:

测试网络连接

void setup() {    USE_SERIAL.begin(115200);    wifiMulti.addAP("MY WIFI SSID", "PASSWORD");}void loop() {    // 当 WIFI 连接上    if((wifiMulti.run() == WL_CONNECTED)) {        // 请求测试网页        http.begin("http://example.com/index.html");        int httpCode = http.GET();                // 成功返回结果        if(httpCode == HTTP_CODE_OK) {            String payload = http.getString();            USE_SERIAL.println(payload);        }        http.end();    }    delay(5000);}

上述代码将请求测试网页,并返回测试网页的代码。从测试结果看功能正常:

测试大模型

最后,我们测试大模型是否能为盲人朋友识别路况,以最简单的图片中盲道被占的图片为例:

我们用 GPT-4o 来进行测试,结果如下:

我们看到大模型将道路中的摩托车、盲道上的铁架和石块都识别出来了,这是影响盲道畅通的关键因素。当然其中还有一些元素识别有问题,作为后续改进的项目。

总结:

本文对购买的 XIAO ESP32 S3 开发板,测试了摄像头、麦克风、蓝牙、WIFI、网络连接以及最后的大模型识别能力,发现基本功能满足需求。后续将以此为基础,进行该硬件的开发。

欢迎关注哦~

希望各位能提提意见,比如这个想法可行性、实用性,或者其它帮助完善的其它想法都可以的。

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

AI 辅助 盲人 路况识别 多模态大模型 硬件开发
相关文章