{"id":367,"date":"2025-08-14T08:06:48","date_gmt":"2025-08-14T08:06:48","guid":{"rendered":"http:\/\/www.amartkh.com\/store\/?p=367"},"modified":"2025-08-14T08:06:51","modified_gmt":"2025-08-14T08:06:51","slug":"rc-car-using-raspberry-pi-5","status":"publish","type":"post","link":"http:\/\/www.amartkh.com\/store\/2025\/08\/14\/rc-car-using-raspberry-pi-5\/","title":{"rendered":"RC Car Using Raspberry Pi 5"},"content":{"rendered":"\n<figure class=\"wp-block-image\"><a href=\"https:\/\/m.youtube.com\/watch?v=g__C5V46Cew&amp;utm_source=chatgpt.com\"><img decoding=\"async\" src=\"https:\/\/images.openai.com\/thumbnails\/url\/gmEKDnicu1mUUVJSUGylr5-al1xUWVCSmqJbkpRnoJdeXJJYkpmsl5yfq5-Zm5ieWmxfaAuUsXL0S7F0Tw7M9Ql0Mo4vSQoo1Y1IzjJOC8sq86xId04yyi4LdUn3CfbIyCt2y4mvKjfLDvcJCYsIjAorLvMvCklWKwYA3BAqNA\" alt=\"m.youtube.com\/watch?v=g_...\"\/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s an image that captures the heart of your project: a Raspberry Pi\u2013powered RC car\u2014built with the Raspberry Pi 5 and ready for a full DIY build and test drive.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Project Overview: RC Car Using Raspberry Pi 5\u2014Full DIY Build + Test Drive<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">What We Know So Far<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">A recent YouTube video titled <strong>\u201cRC Car Using Raspberry Pi 5 | Full DIY Build + Test Drive\u201d<\/strong> showcases a functional build using an 8 GB Pi 5. It highlights improved speed and responsiveness thanks to the newer board (<a href=\"https:\/\/www.youtube.com\/watch?v=g__C5V46Cew&amp;utm_source=chatgpt.com\">YouTube<\/a>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Though the video provides a dynamic demonstration, you&#8217;ll likely need additional sources or breakdowns to guide through your own build\u2014such as wiring diagrams, code walkthroughs, and parts lists. Let\u2019s explore what&#8217;s typically involved in such a build:<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">Typical Components &amp; Setup<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Chassis &amp; Drive System<\/strong><br>A standard RC car chassis with steering servo and ESC (Electronic Speed Controller) forms the foundation. You\u2019ll need to interface these with the Pi\u2019s GPIO pins\u2014often using a PWM-capable HAT or driver board (<a href=\"https:\/\/forums.raspberrypi.com\/viewtopic.php?t=320137&amp;utm_source=chatgpt.com\">forums.raspberrypi.com<\/a>, <a href=\"https:\/\/community.element14.com\/challenges-projects\/project14\/hardwarehacking\/b\/blog\/posts\/modifying-a-rc-toy-truck-using-a-raspberry-pi?utm_source=chatgpt.com\">element14 Community<\/a>).<\/li>\n\n\n\n<li><strong>Motor Control<\/strong><br>L298N or PCA9685 motor driver modules are commonly used. The driver receives PWM signals from the Pi to control steering and throttle (<a href=\"https:\/\/www.instructables.com\/Remote-Controlled-Car-Using-Raspberry-Pi\/?utm_source=chatgpt.com\">Instructables<\/a>, <a href=\"https:\/\/www.techwithsach.com\/post\/build-a-self-driving-rc-car-using-raspberry-pi-and-machine-learning-using-google-colab?utm_source=chatgpt.com\">techwithsach.com<\/a>).<\/li>\n\n\n\n<li><strong>Power Supply<\/strong><br>Use a battery pack suitable for the Pi and motors. Many builders opt for separate power sources\u20145 V for the Pi, and 12 V or higher for motors via the ESC or driver board (<a href=\"https:\/\/plainenglish.io\/blog\/pi-diary-making-my-own-rc-car-using-raspberry-pi-e767559d82?utm_source=chatgpt.com\">plainenglish.io<\/a>, <a href=\"https:\/\/www.instructables.com\/Remote-Controlled-Car-Using-Raspberry-Pi\/?utm_source=chatgpt.com\">Instructables<\/a>).<\/li>\n\n\n\n<li><strong>Camera &amp; Control Interface<\/strong><br>A Pi Camera or USB webcam streams live video to a web interface. Control inputs can be handled via keyboard (WASD), game controllers, or custom scripts\u2014often using frameworks like Flask or pygame (<a href=\"https:\/\/www.instructables.com\/Raspberry-Pi-Remote-Controlled-Car-1\/?utm_source=chatgpt.com\">Instructables<\/a>, <a href=\"https:\/\/www.reddit.com\/r\/raspberry_pi\/comments\/m153jg\/weve_made_an_internet_controlled_rc_car_using\/?utm_source=chatgpt.com\">Reddit<\/a>, <a href=\"https:\/\/www.techwithsach.com\/post\/build-a-self-driving-rc-car-using-raspberry-pi-and-machine-learning-using-google-colab?utm_source=chatgpt.com\">techwithsach.com<\/a>).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">Overview: Core Steps to Build<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Prepare the Chassis<\/strong><br>Secure the motors, wheels, servo, and mount points. Ensure the ESC and steering servo are accessible for wiring.<\/li>\n\n\n\n<li><strong>Wire and Test Motor Drivers<\/strong><br>Connect the steering and throttle PWM signals to the Pi via a driver board. Test with basic PWM scripts to ensure proper movement.<\/li>\n\n\n\n<li><strong>Set Up Power<\/strong><br>Supply stable power to both the Pi and motors, ensuring voltage compatibility and current capacity.<\/li>\n\n\n\n<li><strong>Add the Camera &amp; Stream Video<\/strong><br>Mount the camera to the chassis and set up a streaming server or lightweight web interface to view what the car sees.<\/li>\n\n\n\n<li><strong>Control Logic &amp; Code<\/strong><br>Implement control logic\u2014whether manual via keyboard\/controller or immersive via a web dashboard. Tools like Flask or pygame are popular options (<a href=\"https:\/\/www.techwithsach.com\/post\/build-a-self-driving-rc-car-using-raspberry-pi-and-machine-learning-using-google-colab?utm_source=chatgpt.com\">techwithsach.com<\/a>, <a href=\"https:\/\/www.instructables.com\/Raspberry-Pi-Remote-Controlled-Car-1\/?utm_source=chatgpt.com\">Instructables<\/a>).<\/li>\n\n\n\n<li><strong>Test &amp; Refine<\/strong><br>Conduct test drives, calibrate steering and throttle response, and iterate on control code and latency.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h4 class=\"wp-block-heading\">Inspiration &amp; Extensions<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Autonomous RC Car with Donkey Car<\/strong><br>Platforms like <strong>Donkey Car<\/strong> enable adding self-driving capabilities using machine learning. These use Raspberry Pi, camera modules, throttle\/steering control, and a training workflow\u2014often using Google Colab (<a href=\"https:\/\/www.techwithsach.com\/post\/build-a-self-driving-rc-car-using-raspberry-pi-and-machine-learning-using-google-colab?utm_source=chatgpt.com\">techwithsach.com<\/a>, <a href=\"https:\/\/community.emlid.com\/t\/building-an-autonomous-car-with-rasbperry-pi-and-navio2-running-donkey\/6030?utm_source=chatgpt.com\">Emlid Community Forum<\/a>).<\/li>\n\n\n\n<li><strong>Internet-Controlled Builds<\/strong><br>Some creators use platforms like <strong>Surrogate.tv<\/strong> to host RC cars that anyone can drive remotely through the internet\u2014great for interactive demos (<a href=\"https:\/\/www.reddit.com\/r\/raspberry_pi\/comments\/m153jg\/weve_made_an_internet_controlled_rc_car_using\/?utm_source=chatgpt.com\">Reddit<\/a>).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">How I Can Help You Now<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let me know if you\u2019d like support with any of the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Component selection<\/strong>: Ideal motor drivers, power configurations, or camera modules.<\/li>\n\n\n\n<li><strong>Wiring diagrams<\/strong>: Visual layout of connections between Pi 5, ESC, servo, battery, and camera.<\/li>\n\n\n\n<li><strong>Control code templates<\/strong>: Python scripts for manual keyboard control, or Flask-based streaming + control.<\/li>\n\n\n\n<li><strong>Autonomous options<\/strong>: Guidance on integrating Donkey Car or similar ML-based control.<\/li>\n\n\n\n<li><strong>Remote access setup<\/strong>: How to control your car over Wi-Fi or the internet.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Awesome \u2014 let\u2019s add an <strong>AI Autopilot<\/strong> that does camera-based obstacle avoidance, while keeping <strong>manual override<\/strong> from your <strong>gamepad<\/strong> and <strong>web sliders<\/strong>. If you touch the sticks or the web UI, <strong>manual instantly takes over<\/strong>; if you stop touching for a moment, <strong>autopilot resumes<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Below you\u2019ll get:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Updated <code>index.html<\/code> (adds Autopilot toggle + status)<\/li>\n\n\n\n<li>Single-file <code>app.py<\/code> (Flask + camera stream + PCA9685 + gamepad + autopilot thread)<\/li>\n\n\n\n<li>Two autopilot modes:\n<ol class=\"wp-block-list\">\n<li><strong>Lite (default):<\/strong> classical vision (edges + motion) \u2014 <em>no extra downloads<\/em><\/li>\n\n\n\n<li><strong>DNN (optional):<\/strong> MobileNet-SSD person\/object awareness \u2014 <em>drop in model files later<\/em><\/li>\n<\/ol>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">1) Install packages<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update\nsudo apt install python3-flask python3-picamera2 python3-pip python3-opencv python3-pygame\npip3 install adafruit-circuitpython-pca9685\n<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Optional (for DNN mode later \u2014 put files in <code>models\/<\/code>):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>models\/MobileNetSSD_deploy.caffemodel<\/code><\/li>\n\n\n\n<li><code>models\/MobileNetSSD_deploy.prototxt<\/code><\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">2) Web UI \u2014 <code>static\/index.html<\/code><\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n  &lt;meta charset=\"utf-8\"&gt;\n  &lt;title&gt;Pi RC Car&lt;\/title&gt;\n  &lt;style&gt;\n    body { font-family: Arial, sans-serif; max-width: 900px; margin: 0 auto; padding: 16px; }\n    img { width: 100%; max-width: 860px; border: 1px solid #ddd; border-radius: 8px; }\n    .row { display:flex; gap:16px; flex-wrap:wrap; margin-top:12px;}\n    .card { flex:1; min-width:260px; border:1px solid #eee; border-radius:12px; padding:12px; box-shadow:0 2px 10px rgba(0,0,0,0.05);}\n    .label { font-weight:bold; }\n    .slider { width:100%; }\n    .pill { display:inline-block; padding:4px 10px; border-radius:999px; background:#efefef; margin-left:6px;}\n    button { padding:8px 12px; border-radius:10px; border:1px solid #ddd; cursor:pointer; }\n    .on { background:#d9f8df; border-color:#9ae6a3; }\n    .danger { background:#ffe3e3; border-color:#ffbdbd; }\n  &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;h1&gt;Raspberry Pi 5 RC Car&lt;\/h1&gt;\n  &lt;img src=\"{{ url_for('video_feed') }}\" \/&gt;\n\n  &lt;div class=\"row\"&gt;\n    &lt;div class=\"card\"&gt;\n      &lt;div class=\"label\"&gt;Steering&lt;\/div&gt;\n      &lt;input id=\"steering\" class=\"slider\" type=\"range\" min=\"60\" max=\"120\" value=\"90\"&gt;\n      &lt;div&gt;&lt;span&gt;Angle:&lt;\/span&gt; &lt;span id=\"steerVal\" class=\"pill\"&gt;90&lt;\/span&gt;&lt;\/div&gt;\n    &lt;\/div&gt;\n    &lt;div class=\"card\"&gt;\n      &lt;div class=\"label\"&gt;Throttle&lt;\/div&gt;\n      &lt;input id=\"throttle\" class=\"slider\" type=\"range\" min=\"60\" max=\"120\" value=\"90\"&gt;\n      &lt;div&gt;&lt;span&gt;Angle:&lt;\/span&gt; &lt;span id=\"throtVal\" class=\"pill\"&gt;90&lt;\/span&gt;&lt;\/div&gt;\n    &lt;\/div&gt;\n    &lt;div class=\"card\"&gt;\n      &lt;div class=\"label\"&gt;Actions&lt;\/div&gt;\n      &lt;button onclick=\"stopCar()\" class=\"danger\"&gt;Stop&lt;\/button&gt;\n      &lt;button id=\"apBtn\" onclick=\"toggleAP()\"&gt;Autopilot: OFF&lt;\/button&gt;\n      &lt;div style=\"margin-top:8px;\"&gt;\n        &lt;span class=\"label\"&gt;Mode:&lt;\/span&gt;\n        &lt;select id=\"apMode\" onchange=\"setMode(this.value)\"&gt;\n          &lt;option value=\"lite\"&gt;Lite (Edges\/Motion)&lt;\/option&gt;\n          &lt;option value=\"dnn\"&gt;DNN (MobileNet-SSD)&lt;\/option&gt;\n        &lt;\/select&gt;\n      &lt;\/div&gt;\n      &lt;div style=\"margin-top:8px;\"&gt;\n        &lt;span class=\"label\"&gt;Status:&lt;\/span&gt;\n        &lt;span id=\"apStatus\" class=\"pill\"&gt;idle&lt;\/span&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n\n  &lt;script&gt;\n    const send = (p, v) =&gt; fetch(`\/${p}\/${v}`);\n    const post = (p, body={}) =&gt; fetch(`\/${p}`, {method:'POST', headers:{'Content-Type':'application\/json'}, body:JSON.stringify(body)});\n\n    const s = document.getElementById('steering');\n    const t = document.getElementById('throttle');\n    const steerVal = document.getElementById('steerVal');\n    const throtVal = document.getElementById('throtVal');\n    const apBtn = document.getElementById('apBtn');\n    const apStatus = document.getElementById('apStatus');\n    const apMode = document.getElementById('apMode');\n\n    s.oninput = e =&gt; { steerVal.textContent = e.target.value; send('steering', e.target.value); };\n    t.oninput = e =&gt; { throtVal.textContent = e.target.value; send('throttle', e.target.value); };\n\n    function stopCar() {\n      send('throttle', 90); send('steering', 90);\n      s.value = 90; t.value = 90; steerVal.textContent='90'; throtVal.textContent='90';\n    }\n\n    async function toggleAP() {\n      const r = await post('autopilot\/toggle');\n      const j = await r.json();\n      apBtn.textContent = `Autopilot: ${j.enabled ? 'ON' : 'OFF'}`;\n      apBtn.className = j.enabled ? 'on' : '';\n    }\n\n    async function setMode(m) {\n      const r = await post('autopilot\/mode', {mode:m});\n      const j = await r.json();\n      apStatus.textContent = `mode: ${j.mode}`;\n    }\n\n    \/\/ Poll autopilot status every 1s\n    async function poll() {\n      try {\n        const r = await fetch('\/autopilot\/status');\n        const j = await r.json();\n        apBtn.textContent = `Autopilot: ${j.enabled ? 'ON' : 'OFF'}`;\n        apBtn.className = j.enabled ? 'on' : '';\n        apMode.value = j.mode;\n        apStatus.textContent = j.state;\n      } catch(e) {}\n      setTimeout(poll, 1000);\n    }\n    poll();\n  &lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">3) Server \u2014 <code>app.py<\/code><\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>from flask import Flask, render_template, Response, request, jsonify\nfrom adafruit_servokit import ServoKit\nfrom picamera2 import Picamera2\nimport cv2, time, threading, pygame, numpy as np\nimport os\n\napp = Flask(__name__, static_folder=\"static\", template_folder=\"static\")\n\n# === Servo \/ ESC ===\nkit = ServoKit(channels=16)\nSTEERING_CENTER = 90\nTHROTTLE_STOP   = 90\nkit.servo&#91;0].angle = STEERING_CENTER\nkit.servo&#91;1].angle = THROTTLE_STOP\n\n# Limits\nSTEER_MIN, STEER_MAX = 60, 120\nTHROT_MIN, THROT_MAX = 60, 120\n\n# Manual override logic\nlast_manual_time = time.time()\nMANUAL_TIMEOUT_S = 1.0   # if no manual input for 1s, autopilot may act\n\ndef clamp(v, lo, hi): return max(lo, min(hi, v))\n\ndef set_steering(angle):\n    global last_manual_time\n    kit.servo&#91;0].angle = clamp(int(angle), STEER_MIN, STEER_MAX)\n    last_manual_time = time.time()\n\ndef set_throttle(angle):\n    global last_manual_time\n    kit.servo&#91;1].angle = clamp(int(angle), THROT_MIN, THROT_MAX)\n    last_manual_time = time.time()\n\n# === Camera ===\ncamera = Picamera2()\ncamera.configure(camera.create_video_configuration(main={\"size\": (640, 480)}))\ncamera.start()\n\nframe_lock = threading.Lock()\nlatest_frame = None\n\ndef cam_loop():\n    global latest_frame\n    while True:\n        frame = camera.capture_array()\n        with frame_lock:\n            latest_frame = frame\n\nthreading.Thread(target=cam_loop, daemon=True).start()\n\ndef gen_frames():\n    while True:\n        with frame_lock:\n            frame = latest_frame.copy() if latest_frame is not None else None\n        if frame is None:\n            time.sleep(0.01); continue\n        _, buffer = cv2.imencode('.jpg', frame)\n        yield (b'--frame\\r\\nContent-Type: image\/jpeg\\r\\n\\r\\n' + buffer.tobytes() + b'\\r\\n')\n\n@app.route('\/')\ndef index(): return render_template('index.html')\n\n@app.route('\/video_feed')\ndef video_feed(): return Response(gen_frames(), mimetype='multipart\/x-mixed-replace; boundary=frame')\n\n@app.route('\/steering\/&lt;int:angle&gt;')\ndef http_steer(angle): set_steering(angle); return (\"\", 204)\n\n@app.route('\/throttle\/&lt;int:angle&gt;')\ndef http_throt(angle): set_throttle(angle); return (\"\", 204)\n\n# === Autopilot state ===\nap_enabled = False\nap_mode    = \"lite\"   # \"lite\" or \"dnn\"\nap_state   = \"idle\"\n\n@app.route('\/autopilot\/toggle', methods=&#91;'POST'])\ndef ap_toggle():\n    global ap_enabled\n    ap_enabled = not ap_enabled\n    return jsonify({\"enabled\": ap_enabled})\n\n@app.route('\/autopilot\/mode', methods=&#91;'POST'])\ndef ap_set_mode():\n    global ap_mode\n    ap_mode = request.json.get(\"mode\",\"lite\")\n    return jsonify({\"mode\": ap_mode})\n\n@app.route('\/autopilot\/status')\ndef ap_status():\n    return jsonify({\"enabled\": ap_enabled, \"mode\": ap_mode, \"state\": ap_state})\n\n# === Gamepad thread ===\ndef gamepad_loop():\n    global last_manual_time\n    pygame.init()\n    pygame.joystick.init()\n    if pygame.joystick.get_count() == 0:\n        print(\"No gamepad found. (Autopilot and web control still work.)\")\n        return\n    js = pygame.joystick.Joystick(0); js.init()\n    print(f\"Gamepad connected: {js.get_name()}\")\n    while True:\n        pygame.event.pump()\n        steer_axis = js.get_axis(0)      # left stick X\n        throttle_axis = -js.get_axis(1)  # left stick Y (invert)\n        if abs(steer_axis) &gt; 0.05 or abs(throttle_axis) &gt; 0.05:\n            # Apply manual input and refresh override timer\n            s_angle = STEERING_CENTER + steer_axis * 30\n            t_angle = THROTTLE_STOP + throttle_axis * 30\n            kit.servo&#91;0].angle = clamp(int(s_angle), STEER_MIN, STEER_MAX)\n            kit.servo&#91;1].angle = clamp(int(t_angle), THROT_MIN, THROT_MAX)\n            last_manual_time = time.time()\n        time.sleep(0.03)\n\nthreading.Thread(target=gamepad_loop, daemon=True).start()\n\n# === Autopilot helpers ===\n\n# Lite mode: edge+motion occupancy left\/center\/right\ndef lite_nav(frame):\n    \"\"\"\n    Returns (steer_delta_degrees, throttle_angle) where positive steer_delta turns right.\n    Simple strategy:\n      - Edge map + motion map to estimate obstacle density L\/C\/R.\n      - Prefer region with least density; slow if center is crowded.\n    \"\"\"\n    h, w = frame.shape&#91;:2]\n    roi = frame&#91;int(h*0.45):h, :]  # use lower half\n    gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)\n    edges = cv2.Canny(gray, 60, 150)\n\n    # Simple motion (frame differencing) \u2014 keep a tiny ring buffer\n    if not hasattr(lite_nav, \"prev\"):\n        lite_nav.prev = gray\n    diff = cv2.absdiff(gray, lite_nav.prev)\n    lite_nav.prev = gray\n    _, motion = cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY)\n\n    # Combine signals\n    occ = cv2.addWeighted(edges, 0.7, motion, 0.3, 0)\n    thirds = np.array_split(occ, 3, axis=1)\n    dens = &#91;cv2.countNonZero(t) for t in thirds]  # &#91;L, C, R]\n\n    L, C, R = dens\n    # Steering: aim for least dense side\n    target = np.argmin(dens)  # 0=L,1=C,2=R\n    steer_delta = {0: -20, 1: 0, 2: 20}&#91;target]\n\n    # Throttle: slow if center crowded\n    crowd = C \/ (occ.shape&#91;0]*occ.shape&#91;1]\/3)\n    if crowd &gt; 0.12:  # heuristic\n        throttle = THROTTLE_STOP + 5   # creep\n    else:\n        throttle = THROTTLE_STOP + 15  # cruise\n\n    return steer_delta, clamp(int(throttle), THROT_MIN, THROT_MAX)\n\n# DNN mode: optional MobileNet-SSD person\/obstacle awareness\nnet = None\ndef ensure_dnn():\n    global net\n    if net is not None: return True\n    proto = \"models\/MobileNetSSD_deploy.prototxt\"\n    model = \"models\/MobileNetSSD_deploy.caffemodel\"\n    if not (os.path.exists(proto) and os.path.exists(model)):\n        return False\n    net = cv2.dnn.readNetFromCaffe(proto, model)\n    return True\n\ndef dnn_nav(frame):\n    \"\"\"\n    Detect common objects; if a large box is centered\/near bottom, reduce speed and steer away.\n    \"\"\"\n    h, w = frame.shape&#91;:2]\n    blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 0.007843, (300,300), 127.5)\n    net.setInput(blob)\n    dets = net.forward()\n\n    Lpen = Cpen = Rpen = 0.0\n    for i in range(dets.shape&#91;2]):\n        conf = dets&#91;0,0,i,2]\n        if conf &lt; 0.5: continue\n        box = dets&#91;0,0,i,3:7] * np.array(&#91;w,h,w,h])\n        x1,y1,x2,y2 = box.astype(int)\n        area = (x2-x1)*(y2-y1)\n        # weight near lower center more (potential path)\n        ymid = (y1+y2)\/2 \/ h\n        weight = area \/ (w*h) * (0.5 + ymid)  # bigger\/closer = higher weight\n        xm = (x1+x2)\/2\n        if xm &lt; w\/3: Lpen += weight\n        elif xm &lt; 2*w\/3: Cpen += weight\n        else: Rpen += weight\n\n    # steer to lowest penalty\n    dens = &#91;Lpen, Cpen, Rpen]\n    target = int(np.argmin(dens))\n    steer_delta = {0:-20, 1:0, 2:20}&#91;target]\n\n    # throttle: slower if center penalty high\n    throttle = THROTTLE_STOP + (8 if Cpen &gt; 0.015 else 18)\n    return steer_delta, clamp(int(throttle), THROT_MIN, THROT_MAX)\n\n# === Autopilot loop ===\ndef autopilot_loop():\n    global ap_state, last_manual_time\n    while True:\n        time.sleep(0.03)\n        if not ap_enabled:\n            ap_state = \"off\"\n            continue\n        with frame_lock:\n            frame = latest_frame.copy() if latest_frame is not None else None\n        if frame is None:\n            ap_state = \"waiting_camera\"; continue\n\n        # Manual override check\n        if time.time() - last_manual_time &lt; MANUAL_TIMEOUT_S:\n            ap_state = \"manual_override\"\n            continue\n\n        try:\n            if ap_mode == \"dnn\" and ensure_dnn():\n                ap_state = \"autopilot_dnn\"\n                steer_delta, throttle = dnn_nav(frame)\n            else:\n                ap_state = \"autopilot_lite\"\n                steer_delta, throttle = lite_nav(frame)\n\n            # Apply command\n            current_steer = kit.servo&#91;0].angle or STEERING_CENTER\n            new_steer = clamp(int(current_steer + steer_delta), STEER_MIN, STEER_MAX)\n            kit.servo&#91;0].angle = new_steer\n            kit.servo&#91;1].angle = throttle\n\n        except Exception as e:\n            ap_state = f\"error:{type(e).__name__}\"\n\nthreading.Thread(target=autopilot_loop, daemon=True).start()\n\nif __name__ == '__main__':\n    # TIP: for lower latency on LAN, consider threaded server like waitress or gunicorn\n    app.run(host='0.0.0.0', port=5000, debug=False)\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How the hybrid control works<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Manual inputs (gamepad or web sliders)<\/strong> update servos immediately and set a timestamp.<\/li>\n\n\n\n<li><strong>Autopilot<\/strong> only acts if there\u2019s been <strong>no manual input for 1 second<\/strong> (configurable via <code>MANUAL_TIMEOUT_S<\/code>).<\/li>\n\n\n\n<li><strong>Lite mode<\/strong> uses edges+motion on the road area to choose <strong>Left \/ Center \/ Right<\/strong> with least \u201ccrowding,\u201d and adjusts speed.<\/li>\n\n\n\n<li><strong>DNN mode (optional)<\/strong> uses MobileNet-SSD to estimate obstacle density L\/C\/R (more aware of \u201cthings\u201d like people\/signs) and steers away.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Safety &amp; tuning tips<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Start with wheels off the ground; verify <strong>directions<\/strong> and <strong>neutral<\/strong> at <code>90<\/code>.<\/li>\n\n\n\n<li>Tune ranges:\n<ul class=\"wp-block-list\">\n<li>Steering throw: change <code>\u00b130<\/code> in <code>gamepad_loop<\/code> and <code>steer_delta<\/code> values.<\/li>\n\n\n\n<li>Speed: tweak <code>THROTTLE_STOP + {5..20}<\/code> in nav functions.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>If your ESC requires <strong>arming<\/strong> (neutral 1\u20132s), add a short delay at boot keeping throttle at <code>90<\/code>.<\/li>\n\n\n\n<li>For DNN mode, copy model files into <code>models\/<\/code> and switch the UI to <strong>DNN<\/strong>.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Want me to bundle this into a <strong>ready-to-run zip<\/strong> (folders + files) or add <strong>on-screen HUD overlays<\/strong> (FPS, mode, detections) to the video stream?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">All packed up! Grab your ready-to-run project bundle:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"sandbox:\/mnt\/data\/rc_car_ai_bundle.zip\">Download the ZIP<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What you\u2019re getting<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>app.py<\/code> \u2014 Flask server with web UI, <strong>gamepad control<\/strong>, <strong>autopilot<\/strong>, and <strong>HUD overlay<\/strong> (FPS + AP state\/mode).<\/li>\n\n\n\n<li><code>static\/index.html<\/code> \u2014 Web controls (sliders + Autopilot toggle + mode selector).<\/li>\n\n\n\n<li><code>models\/<\/code> \u2014 Placeholder folder for optional MobileNet-SSD files (for DNN mode).<\/li>\n\n\n\n<li><code>requirements.txt<\/code> &amp; <code>README.md<\/code> \u2014 Install + run instructions.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Quick start<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>unzip rc_car_ai_bundle.zip\ncd rc_car_ai\nsudo apt update\nsudo apt install -y python3-flask python3-picamera2 python3-opencv python3-pygame python3-pip\npip3 install -r requirements.txt\npython3 app.py\n# open http:\/\/&lt;PI_IP&gt;:5000\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Want me to add a <code>systemd<\/code> service so it auto-starts on boot, or tailor the PWM ranges for your exact ESC\/servo?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here\u2019s an image that captures the heart of your project: a Raspberry Pi\u2013powered RC car\u2014built with the Raspberry Pi 5 and ready for a full DIY build and test drive. Project Overview: RC Car Using&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1],"tags":[],"class_list":["post-367","post","type-post","status-publish","format-standard","hentry","category-projects"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/www.amartkh.com\/store\/wp-json\/wp\/v2\/posts\/367","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.amartkh.com\/store\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.amartkh.com\/store\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.amartkh.com\/store\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.amartkh.com\/store\/wp-json\/wp\/v2\/comments?post=367"}],"version-history":[{"count":1,"href":"http:\/\/www.amartkh.com\/store\/wp-json\/wp\/v2\/posts\/367\/revisions"}],"predecessor-version":[{"id":368,"href":"http:\/\/www.amartkh.com\/store\/wp-json\/wp\/v2\/posts\/367\/revisions\/368"}],"wp:attachment":[{"href":"http:\/\/www.amartkh.com\/store\/wp-json\/wp\/v2\/media?parent=367"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.amartkh.com\/store\/wp-json\/wp\/v2\/categories?post=367"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.amartkh.com\/store\/wp-json\/wp\/v2\/tags?post=367"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}