以下作品由安信可社區(qū)用戶小浪先生制作
產(chǎn)品開箱
首先謝謝安信可官方送的開發(fā)板,安信可AiPi-Eyes-R2包含清單如下:
| AiPi-Eyes-R2開發(fā)板 | |
| 腔體喇叭-2pin間距1.25mm黃色超薄插頭 | 2 |
| 1.25mm4pin轉(zhuǎn)1.25mm端子反向連接線-200mm(連接攝像頭) | 1 |
| 轉(zhuǎn)接線-1.25mm轉(zhuǎn)2.54mm6p | 1 |
| 攝像頭模組-酷視-CV-031C50-1.25mm4pin接口-130W像素 | 1 |
| 顯示器-4.0寸-RGB接口40寸-像素480x480 | 1 |
| 咪頭-2pin-1.25mm間距-交叉絞線100mm | 2 |
具體開箱流程照片如下:

環(huán)境搭建
因?yàn)橹肮P者已經(jīng)用過Windows開發(fā)小安派-Eyes-S1了,這次使用Linux進(jìn)行開發(fā)。
安裝VMware
筆記本電腦中已經(jīng)安裝過VMware了,可以參考安信可官方給出的安裝教程,具體鏈接如下:安信可官方教程鏈接
安裝Ubuntu22.04
為什么用22.04版本,不用18.04版本呢??
因?yàn)閡buntu官方推出了24.04LST版本,之前的版本應(yīng)該比較穩(wěn)定了,這次嘗試用新版本。也可選用安信可官方推薦的18.04版本,舊版本用得久了網(wǎng)上資源也比較多。
下載ios鏡像文件
登錄ubuntu官網(wǎng)鏈接,點(diǎn)擊如下圖所示位置“check out our alternative downloads”。

往下滑找到“All past releases ?”。

往下滑找到“22.04.05”。

往下滑找到“ubuntu-22.04.5-desktop-amd64.iso”,點(diǎn)擊進(jìn)行下載。

創(chuàng)建虛擬機(jī)
打開VMware,點(diǎn)擊【創(chuàng)建新的虛擬機(jī)】,選擇【典型】,點(diǎn)擊下一步。

選擇【稍后安裝操作系統(tǒng)】,點(diǎn)擊下一步。

選擇客服及操作系統(tǒng)為L(zhǎng)inux,版本為Ubuntu64位。

命名虛擬機(jī),并選擇合適的保存路徑。

指定磁盤容量大小,最少20G,建議40G。

完成虛擬機(jī)創(chuàng)建。

安裝虛擬機(jī)
設(shè)置CD/DVD類型,內(nèi)存至少為4G,筆者的電腦是32G的,所以設(shè)置為8G。雙擊下圖框選處,打開設(shè)置。

設(shè)置內(nèi)存、選擇下載的ISO鏡像文件,點(diǎn)擊確定。

點(diǎn)擊【開啟此虛擬機(jī)】。

選擇第一項(xiàng)install ubuntu,回車。

選擇中文簡(jiǎn)體,點(diǎn)擊【安裝Ubuntu】,這里看著窗口比較小,不要擔(dān)心,后面會(huì)恢復(fù)的。

鍵盤布局默認(rèn)即可,選擇繼續(xù)。

選擇最小安裝,并取消勾選“安裝Ubuntu時(shí)更新”。

選擇現(xiàn)在安裝。

點(diǎn)擊繼續(xù)。

時(shí)區(qū)默認(rèn)shanghai即可,點(diǎn)擊繼續(xù)。

設(shè)置計(jì)算機(jī)名及密碼,然后點(diǎn)擊繼續(xù),等待安裝即可。

安裝好后,直接用密碼登錄即可。

安裝小安派開發(fā)環(huán)境
Ctrl+Alt+T快捷鍵打開終端,輸入以下質(zhì)量+回車,安裝依賴:
sudo apt-get install make gcc vim cmake git ninja-build -y

mkdir創(chuàng)建新的文件夾,cd進(jìn)入文件夾,克隆SDK
git clone -b master https://gitee.com/Ai-Thinker-Open/AiPi-Open-Kits.git

顯示隱藏文件,并將文件中的github改為gitee,保存。
更新子模塊,以防部分文件夾為空,依次執(zhí)行以下命令
cd AiPi-Open-Kitsgit submodule init git submodule update

進(jìn)入SDK文件夾,執(zhí)行腳本文件
cd aithinker_Ai-M6X_SDK/. install.sh

. export.sh

至此,環(huán)境就按照完成了。
誤用VSCode遠(yuǎn)程訪問Ubuntu
VSCode我Windows本地已經(jīng)安裝好了,VSCode是一個(gè)免費(fèi)的軟件,這里就不再介紹如何安裝,比較簡(jiǎn)單,下面介紹一下如何用本地VSCode遠(yuǎn)程訪問Ubuntu。
安裝VSCode插件Remote-SSH
在VSCode擴(kuò)展中搜索,Remote-SSH,進(jìn)行安裝。

在ubuntu中終端輸入以下命令,獲取ubuntu的ip地址。
ifconfig

在VSCode左側(cè)的“遠(yuǎn)程資源管理器”中,按下圖操作,在框中輸入ubuntu的ip地址+回車,選擇選項(xiàng)的第一個(gè)C:Usersxxx.sshconfig。

按下圖操作可以打開配置文件,Host可以任意配置,但是User必須是Ubuntu的用戶名,如果不知道自己的用戶名可以查看終端命令行前面的“@”前面的內(nèi)容就是用戶名,可以直接復(fù)制。


選擇在當(dāng)前窗口建立遠(yuǎn)程連接(->)或者點(diǎn)擊右側(cè)的按鈕,在新窗口建立連接。

選擇遠(yuǎn)程平臺(tái)的系統(tǒng),此處為L(zhǎng)inux。

輸入系統(tǒng)用戶的密碼+回車,即可控制系統(tǒng)了。

編譯程序
首先在Wiindows下的VSCode打開文件夾,點(diǎn)擊確定。

從../AiPi-Open-Kits/aithinker_Ai-M6X_SDK/examples/helloworld文件夾中復(fù)制helloword文件夾到AiPi-Open-Kits目錄下,我這里將文件名修改成了Smart_dvc,修改SDK路徑為圖中所示。

此時(shí)還不能編譯,需要將小安派的配置同步至SDK內(nèi)部,進(jìn)入aithinker_Ai-M6X_SDK文件夾,分步執(zhí)行以下命令:
. update_sdk.sh.
export.sh

然后進(jìn)入到Smart_dvc文件夾,進(jìn)行編譯,發(fā)現(xiàn)會(huì)報(bào)錯(cuò):fatal error: lwip/dns.h: No such file or directory,解決方法是注釋board.c中的#include "lwip/dns.h" 和 ip_addr_t dns_addr 變量定義這兩行代碼。

再次編譯,顯示編譯成功!

此種方法并沒有一勞永逸的解決環(huán)境變量問題,需要每次打開終端都需要執(zhí)行一次.install.sh和. export.sh,具體操作參照我剛發(fā)的一篇文章:一勞永逸解決編譯問題。
下載程序
下載程序就USB轉(zhuǎn)TTL的TX接板子的RX、RX接板子的TX;原則上需要共地,我是通過電腦TypeC對(duì)小安派Eyes-R2供電,所以就不用共地了,在終端執(zhí)行以下命令即可完成程序的下載。
make flash

到這里看串口就會(huì)發(fā)現(xiàn),程序執(zhí)行不了。那是因?yàn)锳iPI-Eyes-R1/R2 出廠時(shí)做了加密處理,所以在運(yùn)行的時(shí)候,需要指定特定的 boot2及驗(yàn)證固件,否則程序可能無法正常運(yùn)行。將工程中的flash_prog_cfg.ini增加以下代碼:
# 配置boot2固件,否則無法使用復(fù)位燒錄功能(Configure boot2 firmware, otherwise the reset burn function cannot be used) [boot2] filedir = ./build/build_out/Rx_boot2*.bin address = 0x000000 [edata] filedir = ./build/build_out/edata.bin address = 0x3e0000 # 配置partition固件,這是必要的(Configuring partition firmware is necessary) [partition] filedir = ./build/build_out/partition*.bin address = 0xE000

將兩個(gè)文件復(fù)制到 ./build/build_out/文件夾下,boot2在以下目錄中:
AiPi-Open-Kitsaithinker_Ai-M6X_SDKbspboardbl616dkconfig
edata.bin在以下目錄:
AiPi-Open-KitsAiPi-Eyes-Rxboardconfig
性能測(cè)試
下載AiPi-Eyes-Rx工程編譯后的文件,可以看到屏幕幀率8FPS、CPU使用率40%。

DIY項(xiàng)目
利用GUI Guider設(shè)計(jì)的界面和心知天氣API獲取近三天的天氣。在工程中使用了FreeRTOS。自己建的工程,自己一點(diǎn)一點(diǎn)搭起來的,程序框架還算可以(還有進(jìn)步的空間,后續(xù)優(yōu)化好了再開源。屏幕刷新率杠杠的)。
效果展示:

工程搭建
工程搭建我遇到的問題,估計(jì)大家都會(huì)遇到,在我往期的帖子里可以看到。我是利用helloword工程一點(diǎn)點(diǎn)搭建的,對(duì)理解工程框架很有幫助,有問題可以留言探討。以下是我往期的帖子:
環(huán)境搭建
查找AiPI-Eyes-R1/R2 特定的 boot2及驗(yàn)證固件
工程框架
天氣時(shí)鐘工程大致可以分為三部分:
1.連接wifi
2.請(qǐng)求api,獲取天氣
3.GUI界面顯示
連接WiFi
連接wifi和http請(qǐng)求部分是參考的這篇文章【教程貼】M61-32S系列連接Wifi 且發(fā)送HTTP請(qǐng)求。
連接wifi部分不需要改動(dòng),http請(qǐng)求部分,確實(shí)會(huì)像這位博主所說的,會(huì)有卡死的的幾率,查閱資料發(fā)現(xiàn),使用的recv函數(shù)是死等待,請(qǐng)求沒有返回時(shí),程序會(huì)跑飛。
筆者在recv前面加入了下面幾行代碼設(shè)置了超時(shí)時(shí)間,算是暫時(shí)解決了這個(gè)問題,跑程序一兩個(gè)小時(shí)沒有卡死,不過還需進(jìn)一步驗(yàn)證測(cè)試。
// 設(shè)置recv超時(shí)時(shí)間 struct timeval tv_out; tv_out.tv_sec = 5; tv_out.tv_usec = 0;
獲取天氣
天氣api是采用的新知天氣api獲取近3天的天氣,前面http請(qǐng)求獲取的數(shù)據(jù)是json數(shù)據(jù),利用開源的cJSON庫(kù)進(jìn)行解析。cJSON庫(kù)下載鏈接。
網(wǎng)上很多人說,在cJSON庫(kù)解析過程中,很容易卡死,那是因?yàn)闆]有及時(shí)刪除cJSON對(duì)象。每次解析完都要?jiǎng)h除,不然解析次數(shù)多了就會(huì)卡死。
cJSON_Delete(root); /*每次調(diào)用cJSON_Parse函數(shù)后,都要釋放內(nèi)存*/
解析代碼如下:
int weather_info_parse(char *weather_data_buf)
{
// 對(duì)接收到的數(shù)據(jù)作相應(yīng)的處理
uint8_t i, j;
uint8_t result_array_size = 0;
uint8_t daily_array_size = 0;
cJSON *root = NULL;
cJSON *item = NULL;
cJSON *results_root = NULL;
cJSON *daily_root = NULL;
root = cJSON_Parse(weather_data_buf);
if (!root)
{
// ESP_LOGI(TAG, "Error before: [%s]n", cJSON_GetErrorPtr());
LOG_I("Error before: [%s]rn", cJSON_GetErrorPtr());
cJSON_Delete(root); /*每次調(diào)用cJSON_Parse函數(shù)后,都要釋放內(nèi)存*/
return -1;
}
// ESP_LOGI(TAG, "%srn", cJSON_Print(root)); /*將完整的數(shù)據(jù)以JSON格式打印出來*/
cJSON *Presult = cJSON_GetObjectItem(root, "results"); /*results 的鍵值對(duì)為數(shù)組,*/
result_array_size = cJSON_GetArraySize(Presult); /*求results鍵值對(duì)數(shù)組中有多少個(gè)元素*/
// ESP_LOGI(TAG, "Presult array size is %dn",result_array_size);
for (i = 0; i < result_array_size; i++)
{
cJSON *item_results = cJSON_GetArrayItem(Presult, i);
char *sresults = cJSON_PrintUnformatted(item_results);
results_root = cJSON_Parse(sresults);
if (!results_root)
{
// ESP_LOGI(TAG, "Error before: [%s]n", cJSON_GetErrorPtr());
LOG_I("Error before: [%s]rn", cJSON_GetErrorPtr());
cJSON_Delete(root); /*每次調(diào)用cJSON_Parse函數(shù)后,都要釋放內(nèi)存*/
return -1;
}
/*-------------------------------------------------------------------*/
cJSON *Plocation = cJSON_GetObjectItem(results_root, "location");
item = cJSON_GetObjectItem(Plocation, "id");
user_sen_config.id = cJSON_Print(item);
// ESP_LOGI(TAG, "id:%sn", user_sen_config.id); /*逐個(gè)打印*/
item = cJSON_GetObjectItem(Plocation, "name");
user_sen_config.name = cJSON_Print(item);
// ESP_LOGI(TAG, "name:%sn", cJSON_Print(item));
item = cJSON_GetObjectItem(Plocation, "country");
user_sen_config.country = cJSON_Print(item);
// ESP_LOGI(TAG, "country:%sn", cJSON_Print(item));
item = cJSON_GetObjectItem(Plocation, "path");
user_sen_config.path = cJSON_Print(item);
// ESP_LOGI(TAG, "path:%sn", cJSON_Print(item));
item = cJSON_GetObjectItem(Plocation, "timezone");
user_sen_config.timezone = cJSON_Print(item);
// ESP_LOGI(TAG, "timezone:%sn", cJSON_Print(item));
item = cJSON_GetObjectItem(Plocation, "timezone_offset");
user_sen_config.timezone_offset = cJSON_Print(item);
// ESP_LOGI(TAG, "timezone_offset:%sn", cJSON_Print(item));
/*-------------------------------------------------------------------*/
cJSON *Pdaily = cJSON_GetObjectItem(results_root, "daily");
daily_array_size = cJSON_GetArraySize(Pdaily);
// ESP_LOGI(TAG, "Pdaily array size is %dn",daily_array_size);
for (j = 0; j < daily_array_size; j++)
{
cJSON *item_daily = cJSON_GetArrayItem(Pdaily, j);
char *sdaily = cJSON_PrintUnformatted(item_daily);
daily_root = cJSON_Parse(sdaily);
if (!daily_root)
{
LOG_I("Error before: [%s]rn", cJSON_GetErrorPtr());
return -1;
}
item = cJSON_GetObjectItem(daily_root, "date");
user_sen_config.day_config[j].date = item-?>valuestring; // cJSON_Print(item)
item = cJSON_GetObjectItem(daily_root, "text_day");
user_sen_config.day_config[j].text_day = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "code_day"); user_sen_config.day_config[j].code_day = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "text_night");
user_sen_config.day_config[j].text_night = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "code_night");
user_sen_config.day_config[j].code_night = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "high");
user_sen_config.day_config[j].high = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "low");
user_sen_config.day_config[j].low = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "rainfall");
user_sen_config.day_config[j].rainfall = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "precip");
user_sen_config.day_config[j].precip = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "wind_direction");
user_sen_config.day_config[j].wind_direction = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "wind_direction_degree");
user_sen_config.day_config[j].wind_direction_degree = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "wind_speed");
user_sen_config.day_config[j].wind_speed = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "wind_scale");
user_sen_config.day_config[j].wind_scale = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "humidity");
user_sen_config.day_config[j].humidity = cJSON_Print(item);
cJSON_Delete(daily_root); /*每次調(diào)用cJSON_Parse函數(shù)后,都要釋放內(nèi)存*/
}
/*-------------------------------------------------------------------*/
item = cJSON_GetObjectItem(results_root, "last_update");
user_sen_config.last_update = cJSON_Print(item);
cJSON_Delete(results_root); /*每次調(diào)用cJSON_Parse函數(shù)后,都要釋放內(nèi)存*/
}
cJSON_Delete(root); /*每次調(diào)用cJSON_Parse函數(shù)后,都要釋放內(nèi)存*/
return 0;
}
GUI界面設(shè)計(jì)
在配置完工程所需的LVGL配置后可能會(huì)發(fā)現(xiàn),自己配置的LVGL程序并不能執(zhí)行,而且..AiPi-Open-Kitsaithinker_Ai-M6X_SDKexamples下的lvgl示例也不能正確執(zhí)行,不要懷疑,配置可能是沒問題的。
具體解決方法參考小安派R2工程移植LVGL后不運(yùn)行【暫時(shí)解決】這篇帖子。
GUI設(shè)計(jì)是利用NXP的GUI Guider進(jìn)行設(shè)計(jì)的,這里介紹一下怎么移植文件,當(dāng)程序配置好LVGL組件并能正常執(zhí)行demo后,將GUI工程中的custom和generated文件夾放入自己的工程中,在Cmake.List文件中配置好路徑,可能generated文件夾中的images文件夾中的生成的圖片可能會(huì)報(bào)錯(cuò),只需要將lgvllvgl.h改為lvgl.h即可。
在mian.c中加入頭文件
// lvgl #include "gui_guider.h" #include "events_init.h"
在mian函數(shù)中實(shí)例化對(duì)象
setup_ui(&guider_ui); events_init(&guider_ui);
就可以正常顯示通過GUI Guider設(shè)計(jì)的界面了,我這里是用的FreeRTOS的任務(wù)調(diào)用的lvgl處理函數(shù):
void lvgl_task(void *pvParameters) { while (1) { // LOG_I("lvgl_task is runing...rn"); lv_task_handler(); vTaskDelay(1); // bflb_mtimer_delay_ms(1); } }
下面是用GUI Guider設(shè)計(jì),很簡(jiǎn)單的一個(gè)界面。

產(chǎn)品不足和建議
不足
不知道大家在使用過程中有沒有發(fā)現(xiàn)模塊屏幕的接口和USB供電接口放在了一側(cè),這使得插上屏幕后,Type-C很難插上,即使插上Type-C了,屏幕也會(huì)翹起來。可能會(huì)設(shè)想設(shè)計(jì)的初衷是想讓開發(fā)板折在屏幕的背后,但是這樣做,會(huì)看不見屏幕或者本身插好了下載口,屏幕正對(duì)人,會(huì)很難看到按鍵等。
建議
修改一下Type-C口和屏幕口布局,不方便做單片機(jī)開發(fā)板利用。
最后,歡迎大家來安信可論壇,筆者發(fā)布的原貼下一起交流討論:
原貼地址
【小安派R2測(cè)評(píng)】安信可小安派R2開箱、環(huán)境搭建、性能測(cè)試、天氣時(shí)鐘、不足與建議
【小安派R2測(cè)評(píng)】安信可小安派R2 天氣時(shí)鐘
審核編輯 黃宇
-
Linux
+關(guān)注
關(guān)注
88文章
11781瀏覽量
219229 -
開源硬件
+關(guān)注
關(guān)注
8文章
232瀏覽量
31351 -
開發(fā)板
+關(guān)注
關(guān)注
26文章
6321瀏覽量
118998
發(fā)布評(píng)論請(qǐng)先 登錄
樹莓派5還是香橙派5 Pro??jī)煽顭衢T開發(fā)板的詳細(xì)對(duì)比
【開源FPGA硬件】硬件黑客集結(jié):開源FPGA開發(fā)板測(cè)評(píng)活動(dòng)全網(wǎng)火熱招募中......
硬件加速模塊的時(shí)鐘設(shè)計(jì)
Banana Pi 開源硬件社區(qū) 路由器系列產(chǎn)品視頻 https://www.bpi-shop.com/
基于鴻蒙的輕量級(jí)開發(fā)板 M4-R1 正式登場(chǎng)! #OpenHarmony #開源硬件 #樹莓派
【作品合集】玄鐵Banana Pi BPI-RV2開發(fā)板測(cè)評(píng)
【作品合集】匯思博SEEK100開發(fā)板測(cè)評(píng)
小安派立式桌擺外殼設(shè)計(jì)制作
【小智AI語音開發(fā)板】做個(gè)自己的Moss機(jī)器人?
共譜開源華章 | 匠芯創(chuàng)榮獲“開源生態(tài)戰(zhàn)略合作伙伴”獎(jiǎng)
小智AI正式授權(quán)!安信可小安派語音AI開發(fā)板更新啦
上手體驗(yàn)安信可小安派AI開發(fā)板,如何接入Home Assistant?
AI語音開發(fā)板AiPi-PalChatV1教程:硬件設(shè)計(jì)參考
功德+1,用小安派-Eyes-S1做一個(gè)電子木魚
RISC V 開源芯片項(xiàng)目:OpenTitan 詳細(xì)解讀
【開源硬件】小安派AiPi-Eyes-R2詳細(xì)測(cè)評(píng)+DIY天氣時(shí)鐘
評(píng)論