ورکشاپ آموزشی - آیسی مدار
رفتن به محتوا

دستیار هوش مصنوعی پوشیدنی (AI Pin) با دوربین و اتصال به Gemini

رباتیک و هوشمندسازی
۰ نظر
۲۵ نفر
کد ۴۲۹۳

دستیارهای صوتی و گجت‌های هوش مصنوعی پوشیدنی این روزها حسابی سروصدا کردن. تصور کن یه دوربین کوچیک روی لباست نصب شده که می‌تونه ببینه، فکر کنه و دقیقا مثل جارویس (Jarvis) به سؤالاتت جواب بده! تو این پروژه از آیسی‌مدار قراره یه گجت پوشیدنی هوش مصنوعی یا همون AI Pin بسازیم که دقیقا همین کار رو انجام می‌ده.

برای این کار از برد فوق‌العاده جمع‌وجور XIAO ESP32S3 SENSE استفاده می‌کنیم که هم وای‌فای داره و هم به یه دوربین مجهز شده. این دستگاه با استفاده از ربات تلگرام فرمان‌ها رو از تو می‌گیره، عکس محیط رو ثبت می‌کنه و اون رو به هوش مصنوعی قدرتمند گوگل (Gemini API) می‌فرسته تا یه جواب هوشمندانه و دقیق تحویلت بده.

همه این امکانات قراره با یه باتری کوچیک شارژی روشن بمونن تا دستگاه کاملا پرتابل باشه. پس وسایلت رو آماده کن تا با هم یه قدم بزرگ به سمت ساخت گجت‌های هوشمند آینده برداریم.

قطعات موردنیاز

  • برد Seeed Studio XIAO ESP32S3 SENSE (نسخه دوربین‌دار)
  • باتری لیتیوم‌پلیمر 3.7 ولت (400 میلی‌آمپر ساعت)
  • کلید کشویی کوچیک
  • کارتن، ورق اکریلیک یا فوم برد برای ساخت بدنه
  • چسب حرارتی
  • کاتر
  • هویه و وسایل لحیم‌کاری
  • نرم‌افزار Arduino IDE
مرحله ۱

تنظیمات نرم‌افزار آردوینو و ساخت ربات تلگرام

راه‌اندازی پکیج ESP32 در آردوینو:

  1. نرم‌افزار Arduino IDE رو باز کن.
  2. برو به مسیر File و بعد گزینه Preferences رو انتخاب کن.
  3. توی بخش Additional Board Manager URLs، این لینک رو پیست کن:
TXT
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  1. روی دکمه OK کلیک کن.
  2. حالا برو به Tools و از قسمت Board، گزینه Board Manager رو بزن.
  3. کلمه ESP32 رو سرچ کن و پکیجش رو نصب کن.

نصب کتابخونه‌های مورد نیاز:

  1. مسیر Sketch > Include Library > Manage Libraries رو طی کن.
  2. کتابخونه UniversalTelegramBot.h رو جستجو کن.
  3. پیداش که کردی، نصبش کن.

ساخت ربات تلگرامی:

  1. اپلیکیشن تلگرام رو رو گوشیت باز کن.
  2. آیدی BotFather@ (ربات رسمی تلگرام برای ساخت ربات) رو سرچ کن.
  3. چت رو استارت بزن و دستور /newbot رو براش بفرست.
  4. یه اسم و یه آیدی منحصربه‌فرد برای رباتت انتخاب کن.
  5. بات‌فادر بهت یه توکن (Token) می‌ده. این توکن همون کلید ارتباطی ماست؛ کپیش کن و یه جا نگهش دار تا بعدا تو کدها ازش استفاده کنیم.
مرحله ۲

کدنویسی اولیه برای ارتباط با تلگرام

تو این مرحله یه کد ساده می‌نویسیم تا مطمئن بشیم برد می‌تونه پیام‌های تلگرام رو بخونه و بهشون جواب‌های ازپیش‌تعیین‌شده بده.

کدهای تست ارتباط تلگرام:

Arduino
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
// ============ Replace these with your details ============
const char* ssid = "WIFI_NAME";
const char* password = "WIFI_PASSWORD";
const char* botToken = "TELEGRAM_BOT_TOKEN"; // Your Telegram Bot Token
// ========================================================
// Setup secure WiFi client for HTTPS
WiFiClientSecure netClient;
UniversalTelegramBot bot(botToken, netClient);
unsigned long lastCheckTime = 0;
const unsigned long checkInterval = 1000;
void setup() {
Serial.begin(115200);
// Wi-Fi connect
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected.");
netClient.setInsecure();
Serial.println("Telegram Bot started.");
}
void loop() {
// Periodically check for new messages
if (millis() - lastCheckTime >= checkInterval) {
checkTelegramBot();
lastCheckTime = millis();
}
}
void checkTelegramBot() {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
Serial.print("Received: "); Serial.println(text);
if (text == "/ask") {
String response = "Hello, bro!";
bot.sendMessage(chat_id, response, "");
Serial.println("Sent reply: Hello, bro!");
}
}
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
}

برد رو با یه کابل تایپ‌سی به سیستم وصل کن. از منوی Tools مطمئن شو که برد XIAO ESP32S3 و پورت درست رو انتخاب کردی. حالا دکمه آپلود رو بزن تا برنامه‌ریزی شروع بشه.

تحلیل بخش‌های مهم کد:

1. تنظیمات وای‌فای و توکن ربات:

JavaScript
const char* ssid = "WIFI_NAME";
const char* password = "WIFI_PASSWORD";
const char* botToken = "TELEGRAM_BOT_TOKEN";

نام و رمز اینترنت خودت رو باید اینجا وارد کنی. متغیر botToken هم همون رمزیه که از بات‌فادر گرفتی. 2.

بررسی پیام‌های جدید:

Arduino
void checkTelegramBot() {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
Serial.print("Received: "); Serial.println(text);
if (text == "/ask") {
String response = "Hello, bro!";
bot.sendMessage(chat_id, response, "");
Serial.println("Sent reply: Hello, bro!");
}
}
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
}

دستور `(...)bot.getUpdates` پیام‌های دریافتی جدید رو چک می‌کنه و حلقه `(while (numNewMessages` تا وقتی پیام خونده‌نشده‌ای باشه، تکرار می‌شه. حالا اگه تو ربات بنویسی ask/، ربات اینطوری جواب می‌ده:

TXT
Hello, bro!

و همزمان یه پیام تأیید هم تو سریال مانیتور برات می‌نویسه.

مرحله ۳

نکاتی برای ساخت حرفه‌ای گجت پوشیدنی

وقتی داری روی یه پروژه پوشیدنی مثل همین AI Pin کار می‌کنی، وزن قطعات، تمیزی اتصالات و ایمنی باتری خیلی مهمه. چون این گجت قراره به لباس وصل بشه، باید مطمئن باشی هیچ اتصالی‌ای تو مدار وجود نداره.

استفاده از بردهای آماده خیلی خوبه، اما اگه بخوای این گجت رو به یه محصول واقعی و خیلی کوچیک‌تر تبدیل کنی، باید براش یه برد مدار چاپی (PCB) اختصاصی طراحی کنی تا همه قطعات به صورت SMD روش سوار بشن.

همچنین طراحی یه قاب مهندسی‌شده با دستگاه‌های CNC یا پرینت سه‌بعدی رزینی می‌تونه ظاهر دستگاه رو از حالت یه پروژه دانش‌آموزی به یه محصول شیک تغییر بده.

  1. استفاده از شفت‌های مینیاتوری: اگه بخوای مکانیسم‌هایی مثل درپوش لنز بسازی، این قطعات خیلی به دردت می‌خورن.
  2. قاب‌های آلومینیومی: با استفاده از دستگاه‌های CNC می‌تونی یه کیس آلومینیومی فوق‌العاده مقاوم و سبک برای گجتت بسازی تا هم شیک باشه و هم حرارت پردازنده رو دفع کنه.

پس موقع مونتاژ حتما حواست به فشردگی و نظم قطعات باشه تا نتیجه کار حسابی تمیز دربیاد.

مرحله ۴

اضافه کردن هوش مصنوعی Gemini به پروژه

تو این مرحله می‌خوایم کدهای قبلی رو ارتقا بدیم تا ربات بتونه به جای جواب‌های ثابت، از هوش مصنوعی برای جواب دادن استفاده کنه. برای این کار باید یه کلید API از سرویس Gemini گوگل بگیریم:

  1. مرورگر رو باز کن و به آدرس aistudio.google.com برو.
  2. روی دکمه Create API key کلیک کن.
  3. سیستم بهت یه کلید جدید می‌ده. کپیش کن تا تو مرحله بعد ازش استفاده کنیم.

کدها با قابلیت ارتباط با هوش مصنوعی:

Arduino
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
// ==== CONFIG ====
const char* ssid = "WIFI_NAME";
const char* password = "WIFI_PASSWORD";
const char* botToken = "TELEGRAM_BOT_TOKEN"; // Your Telegram Bot Token
const char* GEMINI_API_KEY = "GEMINI_API_KEY"; // Gemini API Key
// ================
// Telegram bot client
WiFiClientSecure netClient;
UniversalTelegramBot bot(botToken, netClient);
unsigned long lastCheckTime = 0;
const unsigned long checkInterval = 1000;
bool waitingForQuery = false;
String callGeminiAPI(String userPrompt) {
WiFiClientSecure client;
client.setInsecure();
if (!client.connect("generativelanguage.googleapis.com", 443)) {
Serial.println("❌ Gemini API connection failed");
return "Error: Could not connect to Gemini API";
}
// Create JSON payload
String payload = "{";
payload += "\"contents\":[{\"role\":\"user\",\"parts\":[{\"text\":\"" + userPrompt + "\"}]}],";
payload += "\"generationConfig\":{\"thinkingConfig\":{\"thinkingBudget\":-1}},";
payload += "\"tools\":[{\"googleSearch\":{}}]";
payload += "}";
// Send POST request
String url = "/v1beta/models/gemini-2.5-flash:generateContent?key=" + String(GEMINI_API_KEY);
client.println("POST " + url + " HTTP/1.1");
client.println("Host: generativelanguage.googleapis.com");
client.println("Content-Type: application/json");
client.println("Content-Length: " + String(payload.length()));
client.println("Connection: close");
client.println();
client.print(payload);
while (client.connected() && !client.available()) delay(10);
String response;
while (client.available()) {
response += client.readString();
}
Serial.println("📩 Raw Gemini Response:");
Serial.println(response);
int jsonStart = response.indexOf("\r\n\r\n");
if (jsonStart == -1) return "Error: No JSON found";
String chunkedBody = response.substring(jsonStart + 4);
String jsonBody;
int pos = 0;
while (pos < chunkedBody.length()) {
int crlf = chunkedBody.indexOf("\r\n", pos);
if (crlf == -1) break;
String sizeStr = chunkedBody.substring(pos, crlf);
int chunkSize = strtol(sizeStr.c_str(), NULL, 16);
if (chunkSize == 0) break;
jsonBody += chunkedBody.substring(crlf + 2, crlf + 2 + chunkSize);
pos = crlf + 2 + chunkSize + 2;
}
StaticJsonDocument<4096> doc;
DeserializationError error = deserializeJson(doc, jsonBody);
if (error) {
Serial.println("❌ JSON parse failed: " + String(error.c_str()));
return "Error: Could not parse JSON";
}
if (doc["candidates"][0]["content"]["parts"][0]["text"].is<String>()) {
return doc["candidates"][0]["content"]["parts"][0]["text"].as<String>();
}
return "Error: No text found";
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n✅ WiFi connected!");
netClient.setInsecure();
}
void loop() {
if (millis() - lastCheckTime >= checkInterval) {
checkTelegramBot();
lastCheckTime = millis();
}
}
void checkTelegramBot() {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
Serial.print("📨 Received: ");
Serial.println(text);
if (text == "/ask") {
bot.sendMessage(chat_id, "Send me your query", "");
waitingForQuery = true; // set state
}
else if (waitingForQuery) {
waitingForQuery = false; // reset state
bot.sendMessage(chat_id, "⏳ Thinking...", "");
String geminiResponse = callGeminiAPI(text);
bot.sendMessage(chat_id, geminiResponse, "");
}
}
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
}

این کد رو جایگزین کدهای قبلی کن، کلید API خودت رو توش قرار بده و آپلودش کن.

تحلیل بخش‌های هوش مصنوعی:

1. متغیر مربوط به کلید اتصال:

JavaScript
const char* GEMINI_API_KEY = "GEMINI_API_KEY";

اینجا باید همون کلیدی که از Google AI Studio گرفتی رو وارد کنی.

TXT
String callGeminiAPI(String userPrompt) {
WiFiClientSecure client;
client.setInsecure();
if (!client.connect("generativelanguage.googleapis.com", 443)) {
return "Error: Could not connect to Gemini API";
}
  1. به صورت امن با سرورهای API گوگل ارتباط برقرار می‌کنه.
  2. اگه اینترنت مشکل داشته باشه، ارور می‌ده.

3. ساخت بسته اطلاعاتی (Payload):

TXT
String payload = "{";
payload += "\"contents\":[{\"role\":\"user\",\"parts\":[{\"text\":\"" + userPrompt + "\"}]}],";
payload += "\"generationConfig\":{\"thinkingConfig\":{\"thinkingBudget\":-1}},";
payload += "\"tools\":[{\"googleSearch\":{}}]";
payload += "}";
  1. این قسمت فرمت JSON داره تا گوگل بتونه راحت بخوندش.
  2. متن پیام تو (userPrompt) رو داخل این بسته قرار می‌ده.
  3. یه سری تنظیمات مثل سرچ گوگل رو هم می‌تونی اینجا بهش اضافه کنی.

4. ارسال درخواست:

TXT
String url = "/v1beta/models/gemini-2.5-flash:generateContent?key=" + String(GEMINI_API_KEY);
client.println("POST " + url + " HTTP/1.1");
...
client.print(payload);

یه درخواست POST با پروتکل HTTPS می‌سازه و دیتا رو می‌فرسته برای هوش مصنوعی.

مرحله ۵

راه‌اندازی دوربین و تبدیل فرمت عکس

هدف این مرحله اینه که وقتی به ربات پیام می‌دیم، بتونه با دوربینش یه عکس از محیط بگیره، اون رو به فرمت متنی (Base64) تبدیل کنه و یه تیکه‌اش رو برای تأیید برامون بفرسته.

فعال کردن حافظه خارجی (PSRAM):

چون عکس گرفتن و پردازش تصویر حافظه زیادی می‌خواد، باید PSRAM برد رو قبل از آپلود فعال کنی:

  1. از منوی نرم‌افزار برو به بخش Tools.
  2. گزینه PSRAM رو پیدا کن.
  3. اون رو روی حالت Enabled قرار بده.

✅ این کار باعث می‌شه برد ESP32 برای پردازش عکس‌ها و ارتباط با Gemini به مشکل کمبود رم نخوره.

کد راه‌اندازی دوربین:

Arduino
#include "esp_camera.h"
#include <WiFi.h>
#include "base64.h"
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
// Pin definitions for XIAO ESP32S3 Sense
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 10
#define SIOD_GPIO_NUM 40
#define SIOC_GPIO_NUM 39
#define Y9_GPIO_NUM 48
#define Y8_GPIO_NUM 11
#define Y7_GPIO_NUM 12
#define Y6_GPIO_NUM 14
#define Y5_GPIO_NUM 16
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 17
#define Y2_GPIO_NUM 15
#define VSYNC_GPIO_NUM 38
#define HREF_GPIO_NUM 47
#define PCLK_GPIO_NUM 13
// ============ Replace these with your details ============
const char* ssid = "WIFI_NAME";
const char* password = "WIFI_PASSWORD";
const char* botToken = "TELEGRAM_BOT_TOKEN"; // Your Telegram Bot Token
// ========================================================
WiFiClientSecure netClient;
UniversalTelegramBot bot(botToken, netClient);
unsigned long lastCheckTime = 0;
const unsigned long checkInterval = 1000;
String handleCapture() {
camera_fb_t * fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
return "Camera capture failed!";
}
// Convert image to base64
String base64String = base64::encode(fb->buf, fb->len);
// Return the frame buffer
esp_camera_fb_return(fb);
// Send base64 string
return (base64String);
}
void setup() {
Serial.begin(115200);
Serial.println();
// Camera configuration
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_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.frame_size = FRAMESIZE_SVGA;
config.pixel_format = PIXFORMAT_JPEG;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;
if(psramFound()){
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
config.frame_size = FRAMESIZE_VGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
// Initialize camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
// Wi-Fi connect
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected.");
netClient.setInsecure();
Serial.println("Telegram Bot started.");
}
void checkTelegramBot() {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
Serial.print("Received: "); Serial.println(text);
if (text == "/ask") {
String response = handleCapture();
Serial.println(response);
response = response.substring(0, min((int)response.length(), 50));
bot.sendMessage(chat_id, response, "");
Serial.println("Sent reply (first 50 chars of base64)");
}
}
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
}
void loop() {
if (millis() - lastCheckTime >= checkInterval) {
checkTelegramBot();
lastCheckTime = millis();
}
}

آپلود و تست سیستم

  1. برد رو وصل کن و دکمه Upload رو بزن.
  2. وقتی تموم شد، سریال مانیتور رو باز کن (باودریت روی 115200 باشه).
  3. پیام‌ها رو بخون تا مطمئن بشی به وای‌فای وصل شده و دوربین بدون ارور کار می‌کنه.
مرحله ۶

ترکیب نهایی کدها (دوربین + هوش مصنوعی)

وقتشه که همه این تکه‌ها رو به هم وصل کنیم. این کد جدید، دوربین و هوش مصنوعی رو با هم ترکیب می‌کنه. روند کار این‌طوریه که تو یه سؤال تو تلگرام می‌پرسی.

بعدش برد یه عکس می‌گیره، اون رو به فرمت Base64 تبدیل می‌کنه و همراه با متن سؤالت می‌فرسته به سرورهای Gemini. هوش مصنوعی هم عکس رو تحلیل می‌کنه، سؤالت رو می‌خونه و یه جواب خیلی دقیق برات پس می‌فرسته.

کدهای نهایی پروژه:

Arduino
#include "esp_camera.h"
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <base64.h>
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
// Pin definitions for XIAO ESP32S3 Sense
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 10
#define SIOD_GPIO_NUM 40
#define SIOC_GPIO_NUM 39
#define Y9_GPIO_NUM 48
#define Y8_GPIO_NUM 11
#define Y7_GPIO_NUM 12
#define Y6_GPIO_NUM 14
#define Y5_GPIO_NUM 16
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 17
#define Y2_GPIO_NUM 15
#define VSYNC_GPIO_NUM 38
#define HREF_GPIO_NUM 47
#define PCLK_GPIO_NUM 13
// ==== CONFIG ====
const char* ssid = "WIFI_NAME";
const char* password = "WIFI_PASSWORD";
const char* botToken = "TELEGRAM_BOT_TOKEN"; // Your Telegram Bot Token
const char* GEMINI_API_KEY = "GEMINI_API_KEY"; // Gemini API Key
// ================
WiFiClientSecure netClient;
UniversalTelegramBot bot(botToken, netClient);
unsigned long lastCheckTime = 0;
const unsigned long checkInterval = 1000;
bool waitingForQuery = false;
// Function to handle image capture and return base64 string
String handleCapture() {
camera_fb_t* fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
return "Camera capture failed!";
}
String base64String = base64::encode(fb->buf, fb->len);
esp_camera_fb_return(fb);
return (base64String);
}
String callGeminiAPI(String userPrompt, String image) {
WiFiClientSecure client;
client.setInsecure();
Serial.println("prompt: "+ userPrompt + "\nimage:"+ image);
if (!client.connect("generativelanguage.googleapis.com", 443)) {
Serial.println("❌ Gemini API connection failed");
return "Error: Could not connect to Gemini API";
}
// Create JSON payload
String payload = "{";
payload += "\"contents\":[{" "\"role\":\"user\"," "\"parts\":[{" "\"inlineData\":{" "\"mimeType\":\"image/jpeg\"," "\"data\":\"" + image + "\"" "}}," "{" "\"text\":\"" + userPrompt + "\"" "}" "]" "}]," "\"generationConfig\":{\"thinkingConfig\":{\"thinkingBudget\":-1}}," "\"tools\":[{\"googleSearch\":{}}]" "}";
// Send POST request
String url = "/v1beta/models/gemini-2.5-flash:generateContent?key=" + String(GEMINI_API_KEY);
client.println("POST " + url + " HTTP/1.1");
client.println("Host: generativelanguage.googleapis.com");
client.println("Content-Type: application/json");
client.println("Content-Length: " + String(payload.length()));
client.println("Connection: close");
client.println();
client.print(payload);
Serial.println("\n\nPayload length" + String(payload.length()));
Serial.println("\n\nPayload" + payload);
while (client.connected() && !client.available()) delay(10);
String response;
while (client.available()) {
response += client.readString();
}
Serial.println("📩 Raw Gemini Response:");
Serial.println(response);
int jsonStart = response.indexOf("\r\n\r\n");
if (jsonStart == -1) return "Error: No JSON found";
String chunkedBody = response.substring(jsonStart + 4);
String jsonBody;
int pos = 0;
while (pos < chunkedBody.length()) {
int crlf = chunkedBody.indexOf("\r\n", pos);
if (crlf == -1) break;
String sizeStr = chunkedBody.substring(pos, crlf);
int chunkSize = strtol(sizeStr.c_str(), NULL, 16);
if (chunkSize == 0) break;
jsonBody += chunkedBody.substring(crlf + 2, crlf + 2 + chunkSize);
pos = crlf + 2 + chunkSize + 2;
}
StaticJsonDocument<4096> doc;
DeserializationError error = deserializeJson(doc, jsonBody);
if (error) {
Serial.println("❌ JSON parse failed: " + String(error.c_str()));
return "Error: Could not parse JSON";
}
if (doc["candidates"][0]["content"]["parts"][0]["text"].is<String>()) {
return doc["candidates"][0]["content"]["parts"][0]["text"].as<String>();
}
return "Error: No text found";
}
void setup() {
Serial.begin(115200);
Serial.println();
// Camera configuration
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_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.frame_size = FRAMESIZE_QVGA;
config.pixel_format = PIXFORMAT_JPEG;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;
if (psramFound()) {
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
config.frame_size = FRAMESIZE_VGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
// Initialize camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n✅ WiFi connected!");
netClient.setInsecure();
Serial.println("Telegram Bot started.");
}
void loop() {
if (millis() - lastCheckTime >= checkInterval) {
checkTelegramBot();
lastCheckTime = millis();
}
}
void checkTelegramBot() {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
Serial.print("📨 Received: ");
Serial.println(text);
if (text == "/help") {
String helpMsg = "🤖 Available commands:\n\n";
helpMsg += "/help - Know about all commands\n";
helpMsg += "/about - Know about the bot\n";
helpMsg += "/subscribe - Subscribe to our YouTube channel\n";
helpMsg += "/ask - Ask a question with AI\n";
bot.sendMessage(chat_id, helpMsg, "");
} else if (text == "/about") {
String aboutMsg = "ℹ️ I am an XIAO ESP32S3-powered Telegram Bot! 🚀\n";
aboutMsg += "I can answer your queries using AI and also share resources.";
bot.sendMessage(chat_id, aboutMsg, "");
} else if (text == "/subscribe") {
String subMsg = "🎥 Support us by subscribing to our YouTube channel:\n";
subMsg += "👉 https://www.youtube.com/@roboatticLab";
bot.sendMessage(chat_id, subMsg, "");
} else if (text == "/ask") {
bot.sendMessage(chat_id, "✍️ Send me your query", "");
waitingForQuery = true;
} else if (waitingForQuery) {
waitingForQuery = false;
bot.sendMessage(chat_id, "⏳ Thinking...", "");
String image = handleCapture();
Serial.println(image);
String geminiResponse = callGeminiAPI(text, image);
bot.sendMessage(chat_id, geminiResponse, "");
}
}
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
}

این کد رو تو آردوینو آپلود کن و ببین گجتت چطور جادو می‌کنه!

مرحله ۷

اتصال باتری و پرتابل کردن دستگاه

برای اینکه بتونی این گجت رو مثل یه گیره به لباست وصل کنی و همه‌جا ببریش، باید کابل رو حذف کنیم. برای این کار به یه باتری لیتیومی 3.7 ولت و یه کلید روشن/خاموش نیاز داریم.

نحوه سیم‌کشی باتری و کلید:

  1. سیم منفی باتری رو مستقیم به پایه GND روی برد XIAO لحیم کن.
  2. سیم مثبت باتری رو به یکی از پایه‌های کلید کشویی وصل کن.
  3. از اون یکی پایه کلید، یه سیم بکش و به پایه 3V3 (یا VIN) برد لحیم کن.

مدیریت شارژ روی این برد از پیش طراحی شده. برد XIAO خودش مدار محافظ و شارژر باتری لیتیومی داره و از طریق همون پورت تایپ‌سی باتری رو پر می‌کنه. وضعیت چراغ‌های شارژ هم به این صورته:

  1. چراغ ال‌ای‌دی قرمز نشون‌دهنده وضعیت شارژه.
  2. وصل کردن کابل بدون باتری: چراغ قرمز روشن می‌شه و بعد از 30 ثانیه خاموش می‌شه.
  3. باتری در حال شارژ: چراغ قرمز چشمک می‌زنه تا نشون بده جریان داره وارد باتری می‌شه.
  4. باتری کاملا پر شده: چراغ قرمز خاموش می‌شه.
مرحله ۸

ساخت کیس و قاب گجت

برای ساخت قاب این گجت می‌تونی از کارتن‌های ضخیم، فوم‌برد یا ورق‌های اکریلیک استفاده کنی؛ همه‌چیز به سلیقه و امکانات خودت بستگی داره. یه فایل الگو هم طراحی شده که می‌تونی پرینتش بگیری و قطعات رو دقیقا از روی اون برش بدی. با کمک چسب حرارتی تمام قطعات بدنه رو سرهم کن و حواست باشه یه سوراخ کوچیک برای لنز دوربین در نظر بگیری.

مرحله ۹

نتیجه‌گیری و راه‌اندازی دستیار هوشمند

بهت تبریک می‌گم! تو الان یه دستیار هوشمند پوشیدنی و واقعی ساختی که می‌تونه ببینه و با هوش مصنوعی قدرتمند گوگل به سؤالاتت جواب بده. حالا کافیه این AI Pin رو روی لباست نصب کنی، تو تلگرام بهش پیام بدی و ازش بپرسی چیزی که روبه‌روش هست چیه، تا در کسری از ثانیه جواب رو برات بفرسته.

اگه تو مراحل ساخت، راه‌اندازی ربات تلگرام یا گرفتن کلید API از گوگل به مشکلی خوردی، حتما تو بخش نظرات همین پست برامون بنویس تا با هم حلش کنیم. راستی، اگه ایده‌ای برای اضافه کردن امکانات دیگه (مثل پخش صدای ربات) به این گجت داری، خیلی خوشحال می‌شیم تو کامنت‌ها بهمون بگی.

ما تو تیم آیسی‌مدار عاشق این پروژه‌های خلاقانه و پیشرفته هستیم و تا آخر مسیر ساخت کنارت می‌مونیم. دمت گرم که همراه ما بودی.

فایل‌های پیوست

PDF AI PIN CUTOUT.pdf
JSON package_esp32_index.json

تو میتونی اولین سازنده باشی!

اگه پروژه رو ساختی به اشتراک بزار و اعتبار هدیه بگیر

این آموزش با استانداردهای اختصاصی آیسی‌مدار بازنویسی و بهینه‌سازی شده و تمامی حقوق انتشار آن متعلق به این مجموعه است و در صورت کپی یا بازنشر پیگرد قانونی خواهد داشت.

آموزش‌های مشابه

گفتگو‌های کاربران

هنوز نظری ثبت نشده؛ تو شروع کن!