低成本作弊神器?使用ESP32将通义千问AI接入学生计算器

小零羊 2024-10-20 08:31:03 阅读 88

前因:

IT之家 9 月 24 日消息,YouTube 频道 ChromaLock 于 9 天前发布视频,介绍了名为 TI-32 的改造电路板,加装在德州仪器 TI-84 Plus 图形计算器上,可以接入 ChatGPT

IT之家查询公开资料,在 PSAT、SAT 和 ACT 大学入学考试、IB 和 AP 考试中,标准化组织已经批准考生使用 TI-84 Plus 图形计算器。

ChromaLock 探索了该计算器的连接端口,设计了名为 TI-32 的改造电路板,其中一个支持 Wi-Fi 的微型微控制器 Seed Studio ESP32-C3(价格约为 5 美元)以及其他元件,用于连接无线系统。

ChromaLock 为微控制器和计算器开发了定制软件,并在 GitHub 上已开源。

该系统模拟了另一个 TI-84,允许人们使用计算器内置的“发送”和“获取”命令来传输文件。这样,用户就可以轻松下载一个启动程序,访问各种专为作弊设计的“小程序”。

除 ChatGPT 界面外,该设备还提供其他几种作弊工具。图像浏览器允许用户访问存储在中央服务器上的预先准备好的视觉辅助工具。

通过应用程序浏览器功能,学生不仅可以下载游戏作为考后娱乐,还可以下载伪装成程序源代码的文本小抄。

但是该计算器售价1100人民币左右,抛开ESP32C3不谈,还得改造电路板

所以准备制造一个低成本的AI分析器

制作思路:

(目前只是理论和思路,等我做出来发教程)

准备工作:

ESP32-DEVKIT *10.96寸TFT彩屏 ST7735S 分辨率160x80 (推荐这个,因为是宽屏小屏,放到计算器不易看出)ov2640摄像头模块 200w像素 支持jpeg输出通义千问api_key(需要去阿里云百炼申请:跳转过去)由于是devkit板子,所以需要面包板,400孔和830孔都行

当然,也有其它的硬件可以选择ESP32CAM自带OV3660或者OV2640,上手即用

接线:

(摄像头以OV2640为例 屏幕以ST7735S为例)

摄像头模块引脚 ESP32 DevKit C引脚
3.3V 3.3V
GND GND
SIOC GPIO27
SIOD GPIO26
XCLK GPIO0
VSYNC GPIO25
HREF GPIO23
PCLK GPIO22
D7 GPIO36
D6 GPIO39
D5 GPIO21
D4 GPIO19
D3 GPIO18
D2 GPIO5
D1 GPIO4
D0 GPIO15
VSYNC GPIO25
HREF GPIO23
PCLK GPIO22
PWDN GPIO32
RESET GPIO-1

安装必要库

ArduinoJson:打开Arduino IDE,进入<code>工具 -> 库管理,搜索ArduinoJson并安装。ESP32-CAM:打开Arduino IDE,进入文件 -> 示例 -> ESP32 -> ESP32CAM,查看示例代码并安装相关库。

ESP32 和 ST7735S 的连接方式如下:

TFT_MISO -> 无需连接(SPI不需要)TFT_MOSI -> GPIO23TFT_SCLK -> GPIO18TFT_CS -> GPIO5TFT_DC -> GPIO16TFT_RST -> GPIO173.3V -> 3.3VGND -> GND

安装必要库

Adafruit_ST7735:打开Arduino IDE,进入工具 -> 库管理,搜索Adafruit_ST7735并安装。Adafruit_GFX:打开Arduino IDE,进入工具 -> 库管理,搜索Adafruit_GFX并安装。

 代码:

思路很简单,配置好WiFi 摄像头和通义千问后,无非就是把照片转为BASE64,构造一下请求体,最后解析下响应而已。此代码只是例子,需要根据实际效果调整,使用硬件模块不同所配置也不同

#include <WiFi.h>

#include <HTTPClient.h>

#include <ArduinoJson.h>

#include <Adafruit_GFX.h>

#include <Adafruit_ST7735.h>

// WiFi设置

const char* ssid = "SSID";

const char* password = "PASSWORD";

// 通义千问API设置

const char* api_url = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions";

const char* api_key = "写自己的";

// 摄像头配置

#define PWDN_GPIO_NUM 32

#define RESET_GPIO_NUM -1

#define XCLK_GPIO_NUM 0

#define SIOD_GPIO_NUM 26

#define SIOC_GPIO_NUM 27

#define Y9_GPIO_NUM 35

#define Y8_GPIO_NUM 34

#define Y7_GPIO_NUM 39

#define Y6_GPIO_NUM 36

#define Y5_GPIO_NUM 21

#define Y4_GPIO_NUM 19

#define Y3_GPIO_NUM 18

#define Y2_GPIO_NUM 5

#define VSYNC_GPIO_NUM 25

#define HREF_GPIO_NUM 23

#define PCLK_GPIO_NUM 22

// TFT LCD配置

#define TFT_CS 5

#define TFT_DC 16

#define TFT_RST 17

#define TFT_MOSI 23

#define TFT_SCLK 18

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

void setup() {

// 初始化串口通信

Serial.begin(115200);

// 初始化TFT LCD

tft.initR(INITR_BLACKTAB); // 初始化屏幕

tft.setRotation(1); // 设置屏幕方向

tft.fillScreen(ST7735_BLACK);

// 初始化摄像头

camera_config_t config;

config.ledc_channel = LEDC_CHANNEL_0;

config.ledc_timer = LEDC_TIMER_0;

config.pin_d0 = Y2_GPIO_NUM;

config.pin_d1 = Y3_GPIO_NUM;

config.pin_d2 = Y4_GPIO_NUM;

config.pin_d3 = Y5_GPIO_NUM;

config.pin_d4 = Y6_GPIO_NUM;

config.pin_d5 = Y7_GPIO_NUM;

config.pin_d6 = Y8_GPIO_NUM;

config.pin_d7 = Y9_GPIO_NUM;

config.pin_xclk = XCLK_GPIO_NUM;

config.pin_pclk = PCLK_GPIO_NUM;

config.pin_vsync = VSYNC_GPIO_NUM;

config.pin_href = HREF_GPIO_NUM;

config.pin_sscb_sda = SIOD_GPIO_NUM;

config.pin_sscb_scl = SIOC_GPIO_NUM;

config.pin_pwdn = PWDN_GPIO_NUM;

config.pin_reset = RESET_GPIO_NUM;

config.xclk_freq_hz = 20000000;

config.pixel_format = PIXFORMAT_JPEG;

config.frame_size = FRAMESIZE_UXGA; // 分辨率

config.jpeg_quality = 12; // JPEG质量

config.fb_count = 1;

// 初始化摄像头

esp_err_t err = esp_camera_init(&config);

if (err != ESP_OK) {

Serial.printf("Camera init failed with error 0x%x", err);

return;

}

// 连接到WiFi

WiFi.begin(ssid, password);

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

delay(1000);

Serial.println("Connecting to WiFi...");

}

Serial.println("Connected to WiFi");

// 设置HTTP客户端

HTTPClient http;

http.begin(api_url);

http.addHeader("Content-Type", "application/json");

http.addHeader("Authorization", "Bearer " + String(api_key));

}

void loop() {

// 拍摄照片

camera_fb_t * fb = esp_camera_fb_get();

if (!fb) {

Serial.println("Camera capture failed");

return;

}

// 将照片转换为Base64编码

size_t encodedLen = base64_encoded_length(fb->len);

char *encodedData = (char *)malloc(encodedLen + 1);

base64_encode(encodedData, (const uint8_t *)fb->buf, fb->len);

// 构造JSON请求体

String payload = "{\"messages\":[{\"role\":\"user\",\"content\":\"![](data:image/jpeg;base64," + String(encodedData) + ")\"}]}";

// 发送POST请求

HTTPClient http;

http.begin(api_url);

http.addHeader("Content-Type", "application/json");

http.addHeader("Authorization", "Bearer " + String(api_key));

int httpResponseCode = http.POST(payload);

if (httpResponseCode > 0) {

// 读取响应

String response = http.getString();

Serial.println(response);

// 解析JSON响应

DynamicJsonDocument doc(1024);

DeserializationError error = deserializeJson(doc, response);

if (!error) {

String answer = doc["choices"][0]["message"]["content"].as<String>(); // 根据实际API返回的字段名称进行调整

Serial.println("Answer: " + answer);

// 在TFT LCD上显示答案

tft.fillScreen(ST7735_BLACK);

tft.setTextColor(ST7735_WHITE);

tft.setTextSize(1); // 设置字体大小

tft.setCursor(0, 0);

tft.print(answer);

} else {

Serial.println("Error parsing JSON");

}

} else {

Serial.println("Error on sending POST: " + String(httpResponseCode));

}

// 释放资源

esp_camera_fb_return(fb);

free(encodedData);

// 延迟一段时间再发送下一个请求

delay(10000);

}

至于怎么安装进计算器内,需要看具体硬件,需要在后面开孔放摄像头,具体怎么隐藏怎么来吧

直接把计算器的主板扔掉,换上ESP32,哈哈哈

对于此项目,我叫它“ExamScanAI

希望有大佬看到此文章可以研发出更完美更完善的



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。