【2022得捷电子创新设计大赛】博物馆奇妙,耶!
[复制链接]
本帖最后由 nemon 于 2022-10-30 17:03 编辑
一、作品简介:
博物馆私人导游助手,本来是想做出个PDA,但发现本人只有拧螺丝的水平,所以现在功能是这样的:
1】电子标签端:从服务器拉取信息,生成可供扫描的平面二维码;
2】个人用户移动端:扫描展品的彩色码,显示对应的展品说明。
二、系统框图(图文结合)
1】标签:esp先建立wifi连接,然后用http访问服务器,获取一个链接的文本,得到文本后用QRCode库转换成二维码点阵,然后显示在LCD屏上。
2】个人终端:esp通过摄像头扫描彩色码,如果没有识别出,则继续扫描,直到识别到预设的编码,找到对应的说明文字,显示在LCD屏上。
三、各部分功能说明(图文结合)
1】电子标签端:
开启外部SPI RAM,以同时支持网络协议和LCD显示。
获取http返回后,取最后一行:
…………
char recv_buf[64];
char result_buf[64];
int result_buf_ptr=0;
int result_buf_cnt=0;
…………
result_buf_ptr=0;
result_buf_cnt=0;
bzero(result_buf, sizeof(result_buf));
do {
bzero(recv_buf, sizeof(recv_buf));
r = read(s, recv_buf, sizeof(recv_buf)-1);
for(int i = 0; i < r; i++) {
putchar(recv_buf);
result_buf_cnt++;
if(result_buf_cnt>=150 && recv_buf=='\n'){//让过http头,150是随便写的,0也无所谓
result_buf_ptr=0;
bzero(result_buf, sizeof(result_buf));
}
if(result_buf_ptr<64 && recv_buf!='\n' ){
result_buf[result_buf_ptr]=recv_buf;
result_buf_ptr++;
}
}
} while(r > 0);
使用在git上的QR生成库(https://github.com/ricmoo/QRCode):
// Create the QR code
/* */
QRCode qrcode;
uint8_t qrcodeData[qrcode_getBufferSize( MY_QR_VER )];
qrcode_initText(&qrcode, qrcodeData, MY_QR_VER , 0, msg);
uint16_t *data_buf = (uint16_t *)heap_caps_calloc(IMAGE_WIDTH * IMAGE_HIGHT, sizeof(uint16_t), MALLOC_CAP_SPIRAM);
for (int j = 0; j < IMAGE_HIGHT; j++) {
for (int i = 0; i < IMAGE_WIDTH; i++) {
color = color_white;
data_buf[i + IMAGE_WIDTH * j] =color;
}
}
/*
*************************************************************/
int p_x = 4 ,p_y = 4;
for(int n_y =0 ; n_y< MY_QR_SIZE ;n_y++){
p_x = 4 ;
for(int n_x =0 ; n_x< MY_QR_SIZE ;n_x++){
color = qrcode_getModule(&qrcode, n_y, n_x )==1?color_black:color_white;
for(int n_d_j =0 ; n_d_j<8;n_d_j++){
for(int n_d_i =0 ; n_d_i<8;n_d_i++){
data_buf[ ( p_x + n_d_i ) + IMAGE_WIDTH * ( p_y + n_d_j ) ] = color;
}
}
p_x +=8;
}
p_y +=8;
}
lcd_set_index(0, 0, IMAGE_WIDTH - 1, IMAGE_HIGHT - 1);
lcd_write_data((uint8_t *)data_buf, IMAGE_WIDTH * IMAGE_HIGHT * sizeof(uint16_t));
vTaskDelay(2000 / portTICK_RATE_MS);
free(data_buf);
return;
}
更新缓存后推送给lcd:
2】个人终端:
能力和时间所限,没有用解二维码的库,而是自己造了个“彩色码”:
从摄像头拿到jpeg图像后,解成RGB565位图,在屏幕上画4个框,当每个框里颜色的平均值符合阈值时,就认为是该颜色,那么4个框就的组合就可以确定一个简短的代码了。
wile true循环,用vTaskDelay延时。在取景待扫描状态,屏幕中心显示提示。
然后不停地取摄像头数组取数,分别求4个框里的rgb三色的平均值:
int get_avg(uint16_t* data, int y,int x,int h,int w,int left ,int length ){
int i,j,v,mask=(1<<length)-1;
long long sum=0;
for(i=0;i<h;i++){
for(j=0;j<w;j++){
v=( uint16_exchange_HL(data[ (y+i)*IMAGE_WIDTH + (x+j) ]) >> left ) & mask ;
sum+=v;
}
}
//printf("%lld -> %lld . %d \n", sum ,sum/(w*h) ,mask );
return sum/(w*h);
}
int ger_color_idx( uint8_t r , uint8_t g , uint8_t b ){
if(r>COLOR_THRESHOLD_HIGH_RED && g <=COLOR_THRESHOLD_LOW_GREEN && b<=COLOR_THRESHOLD_LOW_BLUE){
return COLOR_CAM_RED;
}
if(r<=COLOR_THRESHOLD_LOW_RED && g >COLOR_THRESHOLD_HIGH_GREEN && b<=COLOR_THRESHOLD_LOW_BLUE){
return COLOR_CAM_GREEN;
}
if(r<=COLOR_THRESHOLD_LOW_RED && g <=COLOR_THRESHOLD_LOW_GREEN && b>COLOR_THRESHOLD_HIGH_BLUE){
return COLOR_CAM_BLUE;
}
if(r>COLOR_THRESHOLD_HIGH_RED && g >COLOR_THRESHOLD_HIGH_GREEN && b>COLOR_THRESHOLD_HIGH_BLUE){
return COLOR_CAM_WHITE;
}
return COLOR_CAM_UNKONW;
}
int check_color_idx( int r0, int g0, int b0, int r1, int g1, int b1, int r2, int g2, int b2, int r3, int g3, int b3 ){
if(
COLOR_CAM_WHITE == ger_color_idx( r0,g0,b0 )
&& COLOR_CAM_GREEN == ger_color_idx( r1,g1,b1 )
&& COLOR_CAM_RED == ger_color_idx( r2,g2,b2 )
&& COLOR_CAM_BLUE == ger_color_idx( r3,g3,b3 )
){
return 2;
}
return -1;
}
识别出之后,调用 KEIL带的 Font_6x8_h.h字模,显示文字:
const unsigned int Font_cnt = 96;
const unsigned char Font_key[] = {
' ' ,'!' ,'"' ,'#' ,'$' ,'%' ,'&' ,'\'','(' ,')' ,'*' ,'+' ,
',' ,'-' ,'.' ,'/' ,'0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,
'8' ,'9' ,':' ,';' ,'<' ,'=' ,'>' ,'?' ,'@' ,'A' ,'B' ,'C' ,
'D' ,'E' ,'F' ,'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,
'P' ,'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,'W' ,'X' ,'Y' ,'Z' ,'[' ,
'\\',']' ,'^' ,'_' ,'\'','a' ,'b' ,'c' ,'d' ,'e' ,'f' ,'g' ,
'h' ,'i' ,'j' ,'k' ,'l' ,'m' ,'n' ,'o' ,'p' ,'q' ,'r' ,'s' ,
't' ,'u' ,'v' ,'w' ,'x' ,'y' ,'z' ,'{' ,'|' ,'}' ,'~' ,' ' ,
};
unsigned char * Font_BMP(char c){
unsigned int i=0;
unsigned char * p = (unsigned char *)Font_6x8_h ;
for(i=0;i<Font_cnt;i++){
if(c==Font_key){
p += i*8 ;
return p ;
}
}
return p;
}
效果如图:
显示内容为:" You find it ! This is a leaf ."
四、作品源码
1】电子标签端:https://download.eeworld.com.cn/detail/nemon/625312
2】个人移动端:https://download.eeworld.com.cn/detail/nemon/625311
五、作品功能演示视频
1】电子标签端:视频演示了正在显示二维码,可以扫一下,看是否与服务器上0x01的返回值对应:
VID_20221029_202815 电子标签
2】个人移动端:视频显示了,在扫描“彩色码”之前,屏幕显示的内容,以及识别后,屏幕显示" You find it ! This is a leaf ."码是要和展品对应的,所以配个叶子作为“展品”。
VID_20221030_115503 扫描彩色码
六、项目总结
通过动手,感受到了ESP32系列及工具的支持,熟悉了各例程的功能,了解了 ESP32-S2-Kaluga-1套件的用法。
主要收获:初步接触esp的组件库概念和用法,实践了开启外部SPI RAM解决资源问题的方法。
遗憾:未能在赛期内解决摄像头申请DMA内存不足的问题,未能完成二维码识别库的移植。
七、其他
感谢主办方和群友!
补充内容 (2022-10-30 17:29):
发帖分享:
1】[作品提交] 【2022得捷电子创新设计大赛】博物馆奇妙,耶!
https://bbs.eeworld.com.cn/thread-1222165-1-1.html
2】[经验分享] 【2022得捷电子创新设计大赛】我只是图像的搬运工
https://bbs.eeworld.com.cn/thread-1222164-1-1.html
3】[经验分享] 【2022得捷电子创新设计大赛】内存不够,不能蛮干
https://bbs.eeworld.com.cn/thread-1222163-1-1.html
4】[经验分享] 【2022得捷电子创新设计大赛】到货啦。开箱!
https://bbs.eeworld.com.cn/thread-1210636-1-1.html
|