ESP 32 camera 小车

一、ESP32‑CAM 端完整代码(Arduino)

 
cpp
 
运行
 
 
 
 
#include "esp_camera.h"
#include <WiFi.h>
#include <WebServer.h>

// 电机驱动引脚(L298N / L9110)
#define IN1 12
#define IN2 13
#define IN3 14
#define IN4 15

WebServer server(80);

// WIFI 设置
const char* ssid     = "你的WiFi名称";
const char* password = "你的WiFi密码";

// 摄像头引脚(ESP32‑CAM 固定)
#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

void initCamera() {
  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_QVGA;
  config.jpeg_quality = 12;
  config.fb_count = 1;
  esp_camera_init(&config);
}

void carForward() {
  digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
  server.send(200, "text/plain", "forward");
}

void carBackward() {
  digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH);
  digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH);
  server.send(200, "text/plain", "backward");
}

void carLeft() {
  digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
  server.send(200, "text/plain", "left");
}

void carRight() {
  digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH);
  server.send(200, "text/plain", "right");
}

void carStop() {
  digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
  server.send(200, "text/plain", "stop");
}

void stream() {
  WiFiClient client = server.client();
  String header = "HTTP/1.1 200 OK\r\nContent-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n";
  client.print(header);

  while (client.connected()) {
    camera_fb_t *fb = esp_camera_fb_get();
    if (!fb) break;

    client.print("--frame\r\n");
    client.print("Content-Type: image/jpeg\r\nContent-Length: ");
    client.print(fb->len);
    client.print("\r\n\r\n");
    client.write(fb->buf, fb->len);
    esp_camera_fb_return(fb);
    delay(30);
  }
}

void setup() {
  Serial.begin(115200);

  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  carStop();

  initCamera();

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi 已连接");
  Serial.println("IP 地址: ");
  Serial.println(WiFi.localIP());

  server.on("/forward", carForward);
  server.on("/backward", carBackward);
  server.on("/left", carLeft);
  server.on("/right", carRight);
  server.on("/stop", carStop);
  server.on("/stream", stream);

  server.begin();
}

void loop() {
  server.handleClient();
}
 
 

 

二、安卓 APP 完整源码(Android Studio)

 

1. AndroidManifest.xml

 
xml
 
 
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.esp32camcar">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ESP32CamCar">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
 
 

2. activity_main.xml

 
xml
 
 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center_horizontal"
    android:padding="16dp">

    <ImageView
        android:id="@+id/iv_stream"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:scaleType="fitCenter"
        android:background="#000"/>

    <EditText
        android:id="@+id/et_ip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="ESP32 IP"
        android:text="192.168.4.1"/>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="center"
        android:layout_marginTop="20dp">

        <Button
            android:id="@+id/btn_forward"
            android:layout_width="100dp"
            android:layout_height="60dp"
            android:text="前进"/>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/btn_left"
                android:layout_width="100dp"
                android:layout_height="60dp"
                android:text="左转"/>

            <Button
                android:id="@+id/btn_stop"
                android:layout_width="100dp"
                android:layout_height="60dp"
                android:text="停止"/>

            <Button
                android:id="@+id/btn_right"
                android:layout_width="100dp"
                android:layout_height="60dp"
                android:text="右转"/>
        </LinearLayout>

        <Button
            android:id="@+id/btn_backward"
            android:layout_width="100dp"
            android:layout_height="60dp"
            android:text="后退"/>
    </LinearLayout>

</LinearLayout>
 
 

3. MainActivity.java

 
java
 
运行
 
 
 
 
package com.example.esp32camcar;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;

import androidx.appcompat.app.AppCompatActivity;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity {

    private ImageView iv_stream;
    private EditText et_ip;
    private Handler handler = new Handler(Looper.getMainLooper());

    private final String PATH_FORWARD = "/forward";
    private final String PATH_BACKWARD = "/backward";
    private final String PATH_LEFT = "/left";
    private final String PATH_RIGHT = "/right";
    private final String PATH_STOP = "/stop";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        iv_stream = findViewById(R.id.iv_stream);
        et_ip = findViewById(R.id.et_ip);

        Button btn_forward = findViewById(R.id.btn_forward);
        Button btn_backward = findViewById(R.id.btn_backward);
        Button btn_left = findViewById(R.id.btn_left);
        Button btn_right = findViewById(R.id.btn_right);
        Button btn_stop = findViewById(R.id.btn_stop);

        startStream();

        btn_forward.setOnClickListener(v -> sendCmd(PATH_FORWARD));
        btn_backward.setOnClickListener(v -> sendCmd(PATH_BACKWARD));
        btn_left.setOnClickListener(v -> sendCmd(PATH_LEFT));
        btn_right.setOnClickListener(v -> sendCmd(PATH_RIGHT));
        btn_stop.setOnClickListener(v -> sendCmd(PATH_STOP));
    }

    private void sendCmd(final String path) {
        new Thread(() -> {
            try {
                String ip = et_ip.getText().toString().trim();
                URL url = new URL("http://" + ip + path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(1000);
                conn.getResponseCode();
                conn.disconnect();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    private void startStream() {
        new Thread(() -> {
            while (true) {
                try {
                    String ip = et_ip.getText().toString().trim();
                    URL url = new URL("http://" + ip + "/stream");
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    InputStream is = conn.getInputStream();
                    Bitmap bitmap = BitmapFactory.decodeStream(is);

                    handler.post(() -> iv_stream.setImageBitmap(bitmap));

                    is.close();
                    conn.disconnect();
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                    try { Thread.sleep(500); } catch (InterruptedException ie) {}
                }
            }
        }).start();
    }
}
 
 

 

三、使用步骤

 
  1. ESP32 代码里改 WiFi 名称和密码。
  2. 上传后看串口监视器,拿到 ESP32 IP。
  3. 安卓 APP 里输入这个 IP。
  4. 即可实时视频 + 遥控小车。
posted @ 2026-03-12 13:09  多多和羊羊  阅读(3)  评论(0)    收藏  举报