mirror of
				https://github.com/alexandrebobkov/ESP-Nodes.git
				synced 2025-10-31 23:24:35 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1581 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			1581 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | |
| <html data-content_root="./" lang="en">
 | |
|  <head>
 | |
|   <meta charset="utf-8"/>
 | |
|   <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
 | |
|   <meta content="width=device-width, initial-scale=1" name="viewport"/>
 | |
|   <title>
 | |
|    Byte Rider 06-2025 documentation
 | |
|   </title>
 | |
|   <link href="_static/pygments.css?v=d75fae25" rel="stylesheet" type="text/css"/>
 | |
|   <link href="_static/main.css?v=c1e0a6fc" rel="stylesheet" type="text/css"/>
 | |
|   <script src="_static/documentation_options.js?v=84c8e5cb">
 | |
|   </script>
 | |
|   <script src="_static/doctools.js?v=9bcbadda">
 | |
|   </script>
 | |
|   <script src="_static/sphinx_highlight.js?v=dc90522c">
 | |
|   </script>
 | |
|   <link href="genindex.html" rel="index" title="Index"/>
 | |
|   <link href="search.html" rel="search" title="Search"/>
 | |
|  </head>
 | |
|  <body>
 | |
|   <article class="dont-break" id="cover">
 | |
|    <div class="container">
 | |
|     <!-- Logo -->
 | |
|     <div class="logo">
 | |
|      <p>
 | |
|      </p>
 | |
|     </div>
 | |
|     <!-- Cover middle -->
 | |
|     <div class="cover-middle">
 | |
|      <div class="title">
 | |
|       <h1 class="title-cover">
 | |
|        Byte Rider
 | |
|       </h1>
 | |
|       <p class="subtitle-cover">
 | |
|        Version
 | |
|       </p>
 | |
|       <span class="meta">
 | |
|       </span>
 | |
|      </div>
 | |
|      <!--
 | |
|       <div class="client-logo">
 | |
|         <img src="../data/logo_.png" alt="Logotipo">
 | |
|       </div>
 | |
|       -->
 | |
|     </div>
 | |
|     <!-- Footer -->
 | |
|     <div class="cover-footer">
 | |
|      <p>
 | |
|      </p>
 | |
|     </div>
 | |
|    </div>
 | |
|   </article>
 | |
|   <div aria-label="Main" class="sphinxsidebar" role="navigation">
 | |
|    <div class="sphinxsidebarwrapper">
 | |
|     <div>
 | |
|      <h3>
 | |
|       <a href="#">
 | |
|        Table of Contents
 | |
|       </a>
 | |
|      </h3>
 | |
|      <ul>
 | |
|       <li class="toctree-l1">
 | |
|        <a class="reference internal" href="#overview">
 | |
|         1. OVERVIEW
 | |
|        </a>
 | |
|        <ul>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#abstract">
 | |
|           1.1. ABSTRACT
 | |
|          </a>
 | |
|         </li>
 | |
|        </ul>
 | |
|       </li>
 | |
|       <li class="toctree-l1">
 | |
|        <a class="reference internal" href="#how-does-it-work">
 | |
|         2. HOW DOES IT WORK?
 | |
|        </a>
 | |
|        <ul>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#reserved-pins-gpios">
 | |
|           2.1. Reserved Pins & GPIOs
 | |
|          </a>
 | |
|          <ul>
 | |
|           <li class="toctree-l3">
 | |
|            <a class="reference internal" href="#reading-the-joystick-x-and-y-axis">
 | |
|             2.1.1. Reading the Joystick x- and y- axis
 | |
|            </a>
 | |
|           </li>
 | |
|           <li class="toctree-l3">
 | |
|            <a class="reference internal" href="#controlling-the-direction-and-speed">
 | |
|             2.1.2. Controlling the Direction and Speed
 | |
|            </a>
 | |
|           </li>
 | |
|          </ul>
 | |
|         </li>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#fusion-of-software-with-hardware">
 | |
|           2.2. Fusion of Software with Hardware
 | |
|          </a>
 | |
|         </li>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#schematic">
 | |
|           2.3. Schematic
 | |
|          </a>
 | |
|         </li>
 | |
|        </ul>
 | |
|       </li>
 | |
|       <li class="toctree-l1">
 | |
|        <a class="reference internal" href="#data-structs">
 | |
|         3. DATA STRUCTS
 | |
|        </a>
 | |
|        <ul>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#data-payload">
 | |
|           3.1. Data Payload
 | |
|          </a>
 | |
|          <ul>
 | |
|           <li class="toctree-l3">
 | |
|            <a class="reference internal" href="#why-use-attribute-packed">
 | |
|             3.1.1. Why use __attribute((packed))?
 | |
|            </a>
 | |
|           </li>
 | |
|          </ul>
 | |
|         </li>
 | |
|        </ul>
 | |
|       </li>
 | |
|       <li class="toctree-l1">
 | |
|        <a class="reference internal" href="#transmitter">
 | |
|         4. TRANSMITTER
 | |
|        </a>
 | |
|        <ul>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#configuration-variables">
 | |
|           4.1. Configuration Variables
 | |
|          </a>
 | |
|         </li>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#reading-joystick-x-and-y-axis-values">
 | |
|           4.2. Reading Joystick x- and y- Axis Values
 | |
|          </a>
 | |
|         </li>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#sending-ecapsulating-data">
 | |
|           4.3. Sending & Ecapsulating Data
 | |
|          </a>
 | |
|         </li>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#main-function">
 | |
|           4.4. Main Function
 | |
|          </a>
 | |
|         </li>
 | |
|        </ul>
 | |
|       </li>
 | |
|       <li class="toctree-l1">
 | |
|        <a class="reference internal" href="#receiver">
 | |
|         5. RECEIVER
 | |
|        </a>
 | |
|        <ul>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#configuration-variables">
 | |
|           5.1. Configuration Variables
 | |
|          </a>
 | |
|         </li>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#receiving-extracting-data">
 | |
|           5.2. Receiving & Extracting Data
 | |
|          </a>
 | |
|         </li>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#main-function">
 | |
|           5.3. Main Function
 | |
|          </a>
 | |
|         </li>
 | |
|        </ul>
 | |
|       </li>
 | |
|       <li class="toctree-l1">
 | |
|        <a class="reference internal" href="#work-in-progress-walk-through">
 | |
|         6. WORK-IN-PROGRESS WALK THROUGH
 | |
|        </a>
 | |
|        <ul>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#finished-work">
 | |
|           6.1. Finished Work
 | |
|          </a>
 | |
|         </li>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#chassis">
 | |
|           6.2. Chassis
 | |
|          </a>
 | |
|         </li>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#wiring">
 | |
|           6.3. Wiring
 | |
|          </a>
 | |
|         </li>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#motor-wires-harness">
 | |
|           6.4. Motor Wires Harness
 | |
|          </a>
 | |
|         </li>
 | |
|        </ul>
 | |
|       </li>
 | |
|       <li class="toctree-l1">
 | |
|        <a class="reference internal" href="#references">
 | |
|         7. REFERENCES
 | |
|        </a>
 | |
|        <ul>
 | |
|         <li class="toctree-l2">
 | |
|          <a class="reference internal" href="#github">
 | |
|           7.1. GitHub
 | |
|          </a>
 | |
|         </li>
 | |
|        </ul>
 | |
|       </li>
 | |
|      </ul>
 | |
|     </div>
 | |
|    </div>
 | |
|   </div>
 | |
|   <div class="document">
 | |
|    <div class="documentwrapper">
 | |
|     <div class="bodywrapper">
 | |
|      <div class="body" role="main">
 | |
|       <section id="byterider-highlights">
 | |
|        <h1>
 | |
|         ByteRider Highlights
 | |
|         <a class="headerlink" href="#byterider-highlights" title="Link to this heading">
 | |
|          ¶
 | |
|         </a>
 | |
|        </h1>
 | |
|        <img alt="_images/ESP-IDF_Robot.jpg" src="_images/ESP-IDF_Robot.jpg"/>
 | |
|        <div class="toctree-wrapper compound">
 | |
|         <span id="document-intro">
 | |
|         </span>
 | |
|         <section id="overview">
 | |
|          <h2>
 | |
|           OVERVIEW
 | |
|           <a class="headerlink" href="#overview" title="Link to this heading">
 | |
|            ¶
 | |
|           </a>
 | |
|          </h2>
 | |
|          <p>
 | |
|           At the heart of this project is ESP32-C3 IoT Link, which enables a customizable remote-controlled car to respond to real-time
 | |
| control inputs, handle speed adjustments, directional changes, and even extend features like measuring system telemetry values
 | |
| such as voltage, current, temperature, etc. The foundational setup uses ESP-NOW for transmitter and receiver devices,
 | |
| allowing you to control the car’s behaviour wirelessly. While the design and physical appearance of the RC car can vary wildly
 | |
| depending on your creativity and available hardware, the control system remains the same. To facilitate wireless communication
 | |
| between devices, the system employs IoT Link powered by ESP-NOW, which is a lightweight and connection-free protocol ideal for fast,
 | |
| low-latency data transmission between ESP32 microcontrollers.
 | |
|          </p>
 | |
|          <p>
 | |
|           The control values are sent wirelessly to the remotely controlled car using the ESP-NOW protocol. ESP-NOW enables fast and efficient
 | |
| communication between ESP32 devices without the need for a Wi-Fi router, network, or pairing. The provided tutorial demonstrates a
 | |
| functional setup where a transmitter encapsulates and sends data to a receiver to define the car’s speed and direction, forming the
 | |
| core communication loop. While the baseline implementation focuses on movement, additional features like lights, sensors, or
 | |
| telemetry can easily be integrated by expanding the source code. This modular design gives you the freedom to customize both the
 | |
| appearance and behaviour of your RC car, resulting in endless creative possibilities.
 | |
|          </p>
 | |
|          <section id="abstract">
 | |
|           <h3>
 | |
|            ABSTRACT
 | |
|            <a class="headerlink" href="#abstract" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <p>
 | |
|            To enable real-time remote operation of the RC car, the system translates joystick x- and y- axis inputs into PWM (Pulse Width Modulation) signals that control the DC motors.
 | |
| These PWM values are stored in a predefined data structure, which is then transmitted wirelessly using ESP-NOW — a low-latency, connectionless
 | |
| communication protocol developed by Espressif. Both the transmitter and receiver modules are based on ESP32-C3 microcontrollers.
 | |
|           </p>
 | |
|           <p>
 | |
|            On the transmitter side, the joystick’s X and Y coordinates are continuously monitored and converted into PWM parameters. These values are packed into the
 | |
| data structure and sent via ESP-NOW to the receiver.
 | |
|           </p>
 | |
|           <p>
 | |
|            The receiver module listens for incoming ESP-NOW packets, extracts the PWM control data, and applies it directly to the DC motors. This communication flow
 | |
| allows the RC car to respond instantly to user input, managing speed and direction without any physical connection between the devices.
 | |
|           </p>
 | |
|          </section>
 | |
|         </section>
 | |
|         <span id="document-overview">
 | |
|         </span>
 | |
|         <section id="how-does-it-work">
 | |
|          <h2>
 | |
|           HOW DOES IT WORK?
 | |
|           <a class="headerlink" href="#how-does-it-work" title="Link to this heading">
 | |
|            ¶
 | |
|           </a>
 | |
|          </h2>
 | |
|          <p>
 | |
|           The bitByteRider RC car is powered by ESP32-C3 bitBoard. The Schematic and KiCAd PCB board files are available
 | |
| on
 | |
|           <a class="reference external" href="https://github.com/alexandrebobkov/ESP32-C3_Breadboard-Adapter">
 | |
|            GitHub
 | |
|           </a>
 | |
|           :
 | |
|           <a class="reference external" href="https://github.com/alexandrebobkov/ESP32-C3_Breadboard-Adapter">
 | |
|            https://github.com/alexandrebobkov/ESP32-C3_Breadboard-Adapter
 | |
|           </a>
 | |
|          </p>
 | |
|          <p>
 | |
|           The bitByteRider RC car operates using two main units: the
 | |
|           <em>
 | |
|            transmitter
 | |
|           </em>
 | |
|           , which reads and sends the joystick’s X and Y values, and
 | |
| the
 | |
|           <em>
 | |
|            receiver
 | |
|           </em>
 | |
|           , which interprets these values and converts them into PWM signals to control the DC motors. Both units communicate
 | |
| via
 | |
|           <strong>
 | |
|            ESP-NOW
 | |
|           </strong>
 | |
|           , a low-latency, connectionless wireless protocol that requires no Wi-Fi network or pairing.
 | |
|          </p>
 | |
|          <p>
 | |
|           In addition to enabling real-time control, using ESP-NOW introduces key networking concepts such as
 | |
|           <strong>
 | |
|            data encapsulation
 | |
|           </strong>
 | |
|           and
 | |
| structured communication. By using data structures to group control variables, you gain hands-on experience with how information
 | |
| is packaged and transmitted, laying the groundwork for understanding the fundamentals of network communication in embedded systems.
 | |
|          </p>
 | |
|          <p>
 | |
|           The joystick used in the bitByteRider RC car remote unit outputs analog voltages ranging from 0V to 3.3V on both the x- and y-axes,
 | |
| depending on the position of the joystick. These voltage levels are read by the ESP32-C3’s ADC (Analog-to-Digital Converter) inputs.
 | |
|          </p>
 | |
|          <p>
 | |
|           When the joystick is in its neutral (centred) position, the ADC inputs on the ESP32-C3 receive approximately 1.65V on both axes.
 | |
| This midpoint voltage is interpreted and interpolated into a PWM (Pulse Width Modulation) value of 0, indicating no movement or
 | |
| motor activity.
 | |
|          </p>
 | |
|          <p>
 | |
|           As the joystick is pushed to its maximum positions along the x- and y-axis, the voltage increases up to 3.3V. This maximum voltage
 | |
| is interpolated to a PWM value of 1024, which corresponds to a 100% duty cycle on the receiver side, resulting in full-speed
 | |
| operation of the DC motors.
 | |
|          </p>
 | |
|          <p>
 | |
|           To transmit control data, the X and Y axis values are encapsulated in a C struct, along with the receiver’s
 | |
|           <strong>
 | |
|            MAC
 | |
|           </strong>
 | |
|           address, and sent
 | |
| wirelessly using ESP-NOW. This protocol enables low-latency, connectionless communication between the transmitter and receiver
 | |
| without requiring a Wi-Fi network or pairing.
 | |
|          </p>
 | |
|          <p>
 | |
|           Upon reception, the RC car’s receiver decapsulates the data, extracts the joystick values, and interpolates them into PWM
 | |
| signals. These signals are then used to control the rotation speeds of the DC motors, enabling smooth and responsive remote control.
 | |
|          </p>
 | |
|          <p>
 | |
|           This process not only facilitates real-time control but also introduces you to key networking concepts such as data
 | |
| encapsulation, data structs, and the fundamentals of wireless data transmission in embedded systems.
 | |
|          </p>
 | |
|          <div class="admonition-what-is-encapsulation admonition">
 | |
|           <p class="admonition-title">
 | |
|            What is encapsulation?
 | |
|           </p>
 | |
|           <p>
 | |
|            Encapsulation refers to the process of organizing and packaging data into a structured format before it is transmitted between
 | |
| devices. This is a fundamental concept in networking and communication protocols, including those used in IoT systems.
 | |
|           </p>
 | |
|          </div>
 | |
|          <section id="reserved-pins-gpios">
 | |
|           <h3>
 | |
|            Reserved Pins & GPIOs
 | |
|            <a class="headerlink" href="#reserved-pins-gpios" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <p>
 | |
|            The following table summarizes GPIOs and pins reserved for operations purposes.
 | |
|           </p>
 | |
|           <p>
 | |
|            The GPIO numbers correspond to those on the ESP32-C3 WROOM microcontroller. The Pin number corresponds to the pin on the Breadboard and Power adapter development board.
 | |
|           </p>
 | |
|           <section id="reading-the-joystick-x-and-y-axis">
 | |
|            <h4>
 | |
|             Reading the Joystick x- and y- axis
 | |
|             <a class="headerlink" href="#reading-the-joystick-x-and-y-axis" title="Link to this heading">
 | |
|              ¶
 | |
|             </a>
 | |
|            </h4>
 | |
|            <p>
 | |
|             To determine the position of the Joystick, the BitRider RC car uses ADC to measure voltage on two GPIOs connected to the joystick
 | |
| x- and y- axis potentionometers (
 | |
|             <strong>
 | |
|              GPIO0
 | |
|             </strong>
 | |
|             and
 | |
|             <strong>
 | |
|              GPIO1
 | |
|             </strong>
 | |
|             ).
 | |
|            </p>
 | |
|           </section>
 | |
|           <section id="controlling-the-direction-and-speed">
 | |
|            <h4>
 | |
|             Controlling the Direction and Speed
 | |
|             <a class="headerlink" href="#controlling-the-direction-and-speed" title="Link to this heading">
 | |
|              ¶
 | |
|             </a>
 | |
|            </h4>
 | |
|            <p>
 | |
|             To set any desired speed of BiteRider RC car, the
 | |
|             <em>
 | |
|              ESP32-C3 Breadboard Adapter DevBoard
 | |
|             </em>
 | |
|             uses PWM to control the rotation speed
 | |
| of DR motors. Similarly, to set the direction of the RC car, the rotation speed of corresponding DC motors is changed as required.
 | |
|            </p>
 | |
|            <p>
 | |
|             Due to the design and limited number of available GPIOs, the
 | |
|             <em>
 | |
|              ESP32-C3 Breadboard DevBoard
 | |
|             </em>
 | |
|             can control rotation speed and direction
 | |
| of DC motors in pairs only (i.e. left and right side). Consequently, this means that the four PWM channels used for controlling the
 | |
| direction of the RC car.
 | |
|            </p>
 | |
|            <p>
 | |
|             Based on this constraint, the RC car can only move front, back, and turn/rotate left and right. Any other movements are not
 | |
| possible (i.e. diagonal or sideways).
 | |
|            </p>
 | |
|            <table class="docutils align-default">
 | |
|             <tbody>
 | |
|              <tr class="row-odd">
 | |
|               <td>
 | |
|                <p>
 | |
|                 PWM of DC Motors
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Direction
 | |
|                </p>
 | |
|               </td>
 | |
|              </tr>
 | |
|              <tr class="row-even">
 | |
|               <td>
 | |
|                <p>
 | |
|                 PWM(left) = PWM(right)
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Straight
 | |
|                </p>
 | |
|               </td>
 | |
|              </tr>
 | |
|              <tr class="row-odd">
 | |
|               <td>
 | |
|                <p>
 | |
|                 PWM(left) > PWM(right)
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Left
 | |
|                </p>
 | |
|               </td>
 | |
|              </tr>
 | |
|              <tr class="row-even">
 | |
|               <td>
 | |
|                <p>
 | |
|                 PWM(left) < PWM(right)
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Right
 | |
|                </p>
 | |
|               </td>
 | |
|              </tr>
 | |
|             </tbody>
 | |
|            </table>
 | |
|            <div class="admonition-what-is-pwm admonition">
 | |
|             <p class="admonition-title">
 | |
|              What is PWM?
 | |
|             </p>
 | |
|             <p>
 | |
|              <strong>
 | |
|               PWM
 | |
|              </strong>
 | |
|              stands for Pulse Width Modulation. It is a technique used to simulate analog voltage levels using discrete digital signals. It works by
 | |
| rapidly switching a digital GPIO pin between HIGH (on) and LOW (off) states at a fixed frequency (often, at base frequency of 5 kHz).
 | |
| The duty cycle—the percentage of time the signal is HIGH in one cycle determines the effective voltage delivered to a device.
 | |
| A higher duty cycle increases the motor speed, and a lower duty cycle decreases the motor speed. This allows for fine-grained speed control
 | |
| without needing analog voltage regulators.
 | |
|             </p>
 | |
|            </div>
 | |
|            <p>
 | |
|             A pair of PWM channels are used per DC motor for defining their rotation speed and direction on each side.
 | |
| In particular,
 | |
|             <strong>
 | |
|              GPIO6
 | |
|             </strong>
 | |
|             and
 | |
|             <strong>
 | |
|              GPIO5
 | |
|             </strong>
 | |
|             provide PWM to the left- and right- side DC motors to rotate in a
 | |
|             <strong>
 | |
|              clockwise
 | |
|             </strong>
 | |
|             direction.
 | |
| Similarly,
 | |
|             <strong>
 | |
|              GPIO4
 | |
|             </strong>
 | |
|             and
 | |
|             <strong>
 | |
|              GPIO7
 | |
|             </strong>
 | |
|             provide PWM to the left- and right- side DC motors to rotate in a
 | |
|             <strong>
 | |
|              counter-clockwise
 | |
|             </strong>
 | |
|             direction.
 | |
| Changing PWM on each channel determines the speed and direction of the RC car.
 | |
|            </p>
 | |
|            <p>
 | |
|             The table below summarizes the GPIO pins used for PWM to control the direction of the DC motors in the remote-controlled car.
 | |
|            </p>
 | |
|            <table class="docutils align-default">
 | |
|             <thead>
 | |
|              <tr class="row-odd">
 | |
|               <th class="head">
 | |
|                <p>
 | |
|                 GPIOs
 | |
|                </p>
 | |
|               </th>
 | |
|               <th class="head">
 | |
|                <p>
 | |
|                 State
 | |
|                </p>
 | |
|               </th>
 | |
|               <th class="head">
 | |
|                <p>
 | |
|                 Description
 | |
|                </p>
 | |
|               </th>
 | |
|               <th class="head">
 | |
|                <p>
 | |
|                 Function
 | |
|                </p>
 | |
|               </th>
 | |
|              </tr>
 | |
|             </thead>
 | |
|             <tbody>
 | |
|              <tr class="row-even">
 | |
|               <td>
 | |
|                <p>
 | |
|                 GPIO6,
 | |
| GPIO4
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 PWM
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Left & Right DC Motors spin
 | |
| clockwise
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Forward
 | |
|                </p>
 | |
|               </td>
 | |
|              </tr>
 | |
|              <tr class="row-odd">
 | |
|               <td>
 | |
|                <p>
 | |
|                 GPIO5,
 | |
| GPIO7
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 PWM
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Left & Right DC Motors spin
 | |
| counterclockwise
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Reverse
 | |
|                </p>
 | |
|               </td>
 | |
|              </tr>
 | |
|              <tr class="row-even">
 | |
|               <td>
 | |
|                <p>
 | |
|                 GPIO6,
 | |
| GPIO7
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 PWM
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Left DC Motors spin clockwise.
 | |
| Right DC Motors spin counterclockwise
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Left
 | |
|                </p>
 | |
|               </td>
 | |
|              </tr>
 | |
|              <tr class="row-odd">
 | |
|               <td>
 | |
|                <p>
 | |
|                 GPIO4,
 | |
| GPIO5
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 PWM
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Left DC Motors spin counterclockwise.
 | |
| Right DC Motors spin clockwise
 | |
|                </p>
 | |
|               </td>
 | |
|               <td>
 | |
|                <p>
 | |
|                 Right
 | |
|                </p>
 | |
|               </td>
 | |
|              </tr>
 | |
|             </tbody>
 | |
|            </table>
 | |
|            <p>
 | |
|             The following images illustrate various PWM duty cycles registered by oscilloscope (duty cycles 0%, 48% and 91%, resp.).
 | |
|            </p>
 | |
|            <figure class="align-default" id="id1">
 | |
|             <img alt="_images/ESP-IDF_Robot_PWM_Duty-0.bmp" src="_images/ESP-IDF_Robot_PWM_Duty-0.bmp"/>
 | |
|             <figcaption>
 | |
|              <p>
 | |
|               <span class="caption-text">
 | |
|                DC Motor PWM duty cycle 0%
 | |
|               </span>
 | |
|               <a class="headerlink" href="#id1" title="Link to this image">
 | |
|                ¶
 | |
|               </a>
 | |
|              </p>
 | |
|             </figcaption>
 | |
|            </figure>
 | |
|            <figure class="align-default" id="id2">
 | |
|             <img alt="_images/ESP-IDF_Robot_PWM_Duty-50.bmp" src="_images/ESP-IDF_Robot_PWM_Duty-50.bmp"/>
 | |
|             <figcaption>
 | |
|              <p>
 | |
|               <span class="caption-text">
 | |
|                DC Motor PWM duty cycle 47.6%
 | |
|               </span>
 | |
|               <a class="headerlink" href="#id2" title="Link to this image">
 | |
|                ¶
 | |
|               </a>
 | |
|              </p>
 | |
|             </figcaption>
 | |
|            </figure>
 | |
|            <figure class="align-default" id="id3">
 | |
|             <img alt="_images/ESP-IDF_Robot_PWM_Duty-95.bmp" src="_images/ESP-IDF_Robot_PWM_Duty-95.bmp"/>
 | |
|             <figcaption>
 | |
|              <p>
 | |
|               <span class="caption-text">
 | |
|                DC Motor PWM duty cycle 90.8%
 | |
|               </span>
 | |
|               <a class="headerlink" href="#id3" title="Link to this image">
 | |
|                ¶
 | |
|               </a>
 | |
|              </p>
 | |
|             </figcaption>
 | |
|            </figure>
 | |
|            <br/>
 | |
|            <br/>
 | |
|            <br/>
 | |
|            <br/>
 | |
|           </section>
 | |
|          </section>
 | |
|          <section id="fusion-of-software-with-hardware">
 | |
|           <h3>
 | |
|            Fusion of Software with Hardware
 | |
|            <a class="headerlink" href="#fusion-of-software-with-hardware" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <p>
 | |
|            On one hand, we have the hardware designed so that the joystic x- and y- axis, and DC motors are wired to the proper GPIOs on the
 | |
| ESP32-C3 WROOM microcontroller. On the other hand, we have the software that reads the joystick x- and y- axis, sends the data
 | |
| to the receiver device, and converts that to PWM values on the receiver device.
 | |
|           </p>
 | |
|           <p>
 | |
|            In essense, the direction and speed of the bitByte Rider car is controlled by the two variables. On the remote controller device,
 | |
| the joystic x- and y- axis values are sent to the receiver device in a raw format (i.e. analog voltages, “as-is”). On the receover
 | |
| device, these two values are converted to the two PWM values; one for each pair of DC motors on left and right side.
 | |
|           </p>
 | |
|           <p>
 | |
|            When the joystick is pushed forward, the X-axis voltage remains at 1.65V (neutral), while the Y-axis voltage rises to 3.3V. The
 | |
| receiver on the RC car interprets this input and generates 100% PWM duty cycle signals on both sides, driving the car forward at
 | |
| full speed.
 | |
|           </p>
 | |
|           <p>
 | |
|            Similarly, when the joystick is pushed fully to the left or right, the X-axis voltage shifts while the Y-axis remains neutral. For a
 | |
| left turn, the receiver translates the signal into 100% PWM on the left-side motors and 0% on the right-side motors, causing the car
 | |
| to pivot. The opposite occurs for a right turn, with 100% PWM on the right and 0% on the left, enabling precise directional control.
 | |
|           </p>
 | |
|           <p>
 | |
|            The table below summarizes the reserved GPIOs. These GPIOs are hard-wired to the corresponding components, and hard-coded in the
 | |
| corresponding functions. For example, the GPIOs 0 and 1 are hard-wired to the joystick x- and y- axis, respectively; and, hard-coded
 | |
| to read analog values and store them in the corresponding x- and y- variables.
 | |
|           </p>
 | |
|           <table class="docutils align-default">
 | |
|            <thead>
 | |
|             <tr class="row-odd">
 | |
|              <th class="head">
 | |
|               <p>
 | |
|                GPIO
 | |
|               </p>
 | |
|              </th>
 | |
|              <th class="head">
 | |
|               <p>
 | |
|                Pin
 | |
|               </p>
 | |
|              </th>
 | |
|              <th class="head">
 | |
|               <p>
 | |
|                Function
 | |
|               </p>
 | |
|              </th>
 | |
|              <th class="head">
 | |
|               <p>
 | |
|                Notes
 | |
|               </p>
 | |
|              </th>
 | |
|             </tr>
 | |
|            </thead>
 | |
|            <tbody>
 | |
|             <tr class="row-even">
 | |
|              <td>
 | |
|               <p>
 | |
|                0
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                16
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                Joystick x-axis
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                ADC1_CH0
 | |
|               </p>
 | |
|              </td>
 | |
|             </tr>
 | |
|             <tr class="row-odd">
 | |
|              <td>
 | |
|               <p>
 | |
|                1
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                15
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                Joystick y-axis
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                ADC1_CH1
 | |
|               </p>
 | |
|              </td>
 | |
|             </tr>
 | |
|             <tr class="row-even">
 | |
|              <td>
 | |
|               <p>
 | |
|                8
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                5
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                Joystick push button
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                NC
 | |
|               </p>
 | |
|              </td>
 | |
|             </tr>
 | |
|             <tr class="row-odd">
 | |
|              <td>
 | |
|               <p>
 | |
|                6
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                4
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                PWM for clockwise rotation of left-side motors
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                LEDC_CHANNEL_1
 | |
|               </p>
 | |
|              </td>
 | |
|             </tr>
 | |
|             <tr class="row-even">
 | |
|              <td>
 | |
|               <p>
 | |
|                5
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                3
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                PWM for clockwise rotation of right-side motors
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                LEDC_CHANNEL_0
 | |
|               </p>
 | |
|              </td>
 | |
|             </tr>
 | |
|             <tr class="row-odd">
 | |
|              <td>
 | |
|               <p>
 | |
|                4
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                2
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                PWM for counter-clockwise rotation of right-side motors
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                LEDC_CHANNEL_2
 | |
|               </p>
 | |
|              </td>
 | |
|             </tr>
 | |
|             <tr class="row-even">
 | |
|              <td>
 | |
|               <p>
 | |
|                7
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                6
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                PWM for counter-clockwise rotation of left-side motors
 | |
|               </p>
 | |
|              </td>
 | |
|              <td>
 | |
|               <p>
 | |
|                LEDC_CHANNEL_3
 | |
|               </p>
 | |
|              </td>
 | |
|             </tr>
 | |
|            </tbody>
 | |
|           </table>
 | |
|           <p>
 | |
|            The struct used to store motor PWM values is shown below. While the bitByteRider RC car can be effectively controlled using
 | |
| just two PWM signals—one for each side—the structure is designed to hold four values, allowing room for future enhancements. This
 | |
| forward-thinking design supports potential upgrades such as improved maneuverability, individual wheel control, or advanced driving
 | |
| modes, making the system more adaptable and scalable for future development.
 | |
|           </p>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="k">struct</span><span class="w"> </span><span class="nc">motors_rpm</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor1_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor2_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor3_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor4_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="p">};</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|           <p>
 | |
|            On the transmitter device, the PWM values for the DC motors are sent to the receiver using the following function. The variable
 | |
|            <strong>
 | |
|             receiver_mac
 | |
|            </strong>
 | |
|            stores the MAC address of the receiver device (ESP32-C3 bitBoard on the RC car).
 | |
|           </p>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="c1">// Function to send data to the receiver</span>
 | |
| <span class="kt">void</span><span class="w"> </span><span class="nf">sendData</span><span class="w"> </span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">    </span><span class="n">sensors_data_t</span><span class="w"> </span><span class="n">buffer</span><span class="p">;</span><span class="w">              </span><span class="c1">// Declare data struct</span>
 | |
| 
 | |
| <span class="w">    </span><span class="n">buffer</span><span class="p">.</span><span class="n">crc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">buffer</span><span class="p">.</span><span class="n">x_axis</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">buffer</span><span class="p">.</span><span class="n">y_axis</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">buffer</span><span class="p">.</span><span class="n">nav_bttn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">buffer</span><span class="p">.</span><span class="n">motor1_rpm_pwm</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">buffer</span><span class="p">.</span><span class="n">motor2_rpm_pwm</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">buffer</span><span class="p">.</span><span class="n">motor3_rpm_pwm</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">buffer</span><span class="p">.</span><span class="n">motor4_rpm_pwm</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
 | |
| 
 | |
| <span class="w">    </span><span class="c1">// Display brief summary of data being sent.</span>
 | |
| <span class="w">    </span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span><span class="w"> </span><span class="s">"Joystick (x,y) position ( 0x%04X, 0x%04X )"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">uint8_t</span><span class="p">)</span><span class="n">buffer</span><span class="p">.</span><span class="n">x_axis</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">uint8_t</span><span class="p">)</span><span class="n">buffer</span><span class="p">.</span><span class="n">y_axis</span><span class="p">);</span>
 | |
| <span class="w">    </span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span><span class="w"> </span><span class="s">"pwm 1, pwm 2 [ 0x%04X, 0x%04X ]"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">uint8_t</span><span class="p">)</span><span class="n">buffer</span><span class="p">.</span><span class="n">pwm</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">uint8_t</span><span class="p">)</span><span class="n">buffer</span><span class="p">.</span><span class="n">pwm</span><span class="p">);</span>
 | |
| <span class="w">    </span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span><span class="w"> </span><span class="s">"pwm 3, pwm 4 [ 0x%04X, 0x%04X ]"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">uint8_t</span><span class="p">)</span><span class="n">buffer</span><span class="p">.</span><span class="n">pwm</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">uint8_t</span><span class="p">)</span><span class="n">buffer</span><span class="p">.</span><span class="n">pwm</span><span class="p">);</span>
 | |
| 
 | |
| <span class="w">    </span><span class="c1">// Call ESP-NOW function to send data (MAC address of receiver, pointer to the memory holding data & data length)</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">esp_now_send</span><span class="p">(</span><span class="n">receiver_mac</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">buffer</span><span class="p">));</span>
 | |
| 
 | |
| <span class="w">    </span><span class="c1">// If status is NOT OK, display error message and error code (in hexadecimal).</span>
 | |
| <span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">result</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">        </span><span class="n">ESP_LOGE</span><span class="p">(</span><span class="s">"ESP-NOW"</span><span class="p">,</span><span class="w"> </span><span class="s">"Error sending data! Error code: 0x%04X"</span><span class="p">,</span><span class="w"> </span><span class="n">result</span><span class="p">);</span>
 | |
| <span class="w">        </span><span class="n">deletePeer</span><span class="p">();</span>
 | |
| <span class="w">    </span><span class="p">}</span>
 | |
| <span class="w">    </span><span class="k">else</span>
 | |
| <span class="w">        </span><span class="n">ESP_LOGW</span><span class="p">(</span><span class="s">"ESP-NOW"</span><span class="p">,</span><span class="w"> </span><span class="s">"Data was sent."</span><span class="p">);</span>
 | |
| <span class="p">}</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|           <p>
 | |
|            This function is invoked by a dedicated FreeRTOS task every 100 milliseconds, ensuring consistent and timely transmission of
 | |
| control data to the receiver device. By leveraging FreeRTOS’s precise task scheduling, the system maintains low-latency
 | |
| communication and predictable behaviour, critical for real-time control in embedded applications.
 | |
|           </p>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="c1">// Continous, periodic task that sends data.</span>
 | |
| <span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">rc_send_data_task</span><span class="w"> </span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">arg</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| 
 | |
| <span class="w">    </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="nb">true</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">esp_now_is_peer_exist</span><span class="p">(</span><span class="n">receiver_mac</span><span class="p">))</span>
 | |
| <span class="w">            </span><span class="n">sendData</span><span class="p">();</span>
 | |
| <span class="w">        </span><span class="n">vTaskDelay</span><span class="w"> </span><span class="p">(</span><span class="mi">100</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">portTICK_PERIOD_MS</span><span class="p">);</span>
 | |
| <span class="w">    </span><span class="p">}</span>
 | |
| <span class="p">}</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|           <p>
 | |
|            As data is being sent, the function onDataSent() is called to check & display the status of the data transmission.
 | |
|           </p>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="c1">// Call-back for the event when data is being sent</span>
 | |
| <span class="kt">void</span><span class="w"> </span><span class="nf">onDataSent</span><span class="w"> </span><span class="p">(</span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">mac_addr</span><span class="p">,</span><span class="w"> </span><span class="n">esp_now_send_status_t</span><span class="w"> </span><span class="n">status</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">    </span><span class="n">ESP_LOGW</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span><span class="w"> </span><span class="s">"Packet send status: 0x%04X"</span><span class="p">,</span><span class="w"> </span><span class="n">status</span><span class="p">);</span>
 | |
| <span class="p">}</span>
 | |
| 
 | |
| <span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|           <p>
 | |
|            On the receiver device, the data is saved in the variables by the call-back function onDataReceived().
 | |
|           </p>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="c1">// Call-back for the event when data is being received</span>
 | |
| <span class="kt">void</span><span class="w"> </span><span class="nf">onDataReceived</span><span class="w"> </span><span class="p">(</span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">mac_addr</span><span class="p">,</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">data_len</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| 
 | |
| <span class="w">    </span><span class="n">buf</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">sensors_data_t</span><span class="o">*</span><span class="p">)</span><span class="n">data</span><span class="p">;</span><span class="w">                            </span><span class="c1">// Allocate memory for buffer to store data being received</span>
 | |
| <span class="w">    </span><span class="n">ESP_LOGW</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span><span class="w"> </span><span class="s">"Data was received"</span><span class="p">);</span>
 | |
| <span class="w">    </span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span><span class="w"> </span><span class="s">"x-axis: 0x%04x"</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="o">-></span><span class="n">x_axis</span><span class="p">);</span>
 | |
| <span class="w">    </span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span><span class="w"> </span><span class="s">"x-axis: 0x%04x"</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="o">-></span><span class="n">y_axis</span><span class="p">);</span>
 | |
| <span class="w">    </span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span><span class="w"> </span><span class="s">"PWM 1: 0x%04x"</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="o">-></span><span class="n">motor1_rpm_pwm</span><span class="p">);</span>
 | |
| <span class="p">}</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|          </section>
 | |
|          <section id="schematic">
 | |
|           <h3>
 | |
|            Schematic
 | |
|            <a class="headerlink" href="#schematic" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <img alt="_images/ESP-IDF_Robot_schematic.png" src="_images/ESP-IDF_Robot_schematic.png"/>
 | |
|          </section>
 | |
|         </section>
 | |
|         <span id="document-data">
 | |
|         </span>
 | |
|         <section id="data-structs">
 | |
|          <h2>
 | |
|           DATA STRUCTS
 | |
|           <a class="headerlink" href="#data-structs" title="Link to this heading">
 | |
|            ¶
 | |
|           </a>
 | |
|          </h2>
 | |
|          <p>
 | |
|           The struct serves as the data payload for sending control signals from the transmitting device to the receiver using ESP-NOW.
 | |
| In addition, it may contain additional data such as telemetry, battery status, etc. The
 | |
|           <em>
 | |
|            sensors_data_t
 | |
|           </em>
 | |
|           struct encapsulates all control commands and sensor states
 | |
| relevant to the vehicle’s operation. It’s intended to be sent from a transmitting device (like a remote control) to a receiver
 | |
| (such as a microcontroller on board of the vehicle).
 | |
|          </p>
 | |
|          <div class="highlight-c notranslate">
 | |
|           <div class="highlight">
 | |
|            <pre><span></span><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w">         </span><span class="n">x_axis</span><span class="p">;</span><span class="w">             </span><span class="c1">// Joystick x-position</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w">         </span><span class="n">y_axis</span><span class="p">;</span><span class="w">             </span><span class="c1">// Joystick y-position</span>
 | |
| <span class="w">    </span><span class="kt">bool</span><span class="w">        </span><span class="n">nav_bttn</span><span class="p">;</span><span class="w">           </span><span class="c1">// Joystick push button</span>
 | |
| <span class="w">    </span><span class="kt">bool</span><span class="w">        </span><span class="n">led</span><span class="p">;</span><span class="w">                </span><span class="c1">// LED ON/OFF state</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor1_rpm_pwm</span><span class="p">;</span><span class="w">     </span><span class="c1">// PWMs for 4 DC motors</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor2_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor3_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor4_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="p">}</span><span class="w"> </span><span class="n">__attribute__</span><span class="p">((</span><span class="n">packed</span><span class="p">))</span><span class="w"> </span><span class="n">sensors_data_t</span><span class="p">;</span>
 | |
| </pre>
 | |
|           </div>
 | |
|          </div>
 | |
|          <div class="highlight-c notranslate">
 | |
|           <div class="highlight">
 | |
|            <pre><span></span><span class="k">struct</span><span class="w"> </span><span class="nc">motors_rpm</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor1_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor2_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor3_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor4_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="p">};</span>
 | |
| </pre>
 | |
|           </div>
 | |
|          </div>
 | |
|          <p>
 | |
|           When used with communication protocols like ESP-NOW, this struct is
 | |
|           <strong>
 | |
|            encoded
 | |
|           </strong>
 | |
|           into a byte stream, then
 | |
|           <strong>
 | |
|            transmitted
 | |
|           </strong>
 | |
|           at regular intervals or in response to user input, and finally
 | |
|           <strong>
 | |
|            decoded
 | |
|           </strong>
 | |
|           on the receiving end to control hardware.
 | |
|          </p>
 | |
|          <div class="admonition-what-is-struct admonition">
 | |
|           <p class="admonition-title">
 | |
|            What is struct?
 | |
|           </p>
 | |
|           <p>
 | |
|            In C programming, a struct (short for structure) is a user-defined data type that lets you group multiple variables of different types together under a
 | |
| single name. It’s like a container that holds related information — perfect for organizing data that logically belongs together. Structs are especially
 | |
| powerful in systems programming, embedded projects, and when dealing with raw binary data — like parsing sensor input or transmitting control packets over
 | |
| ESP-NOW.
 | |
|           </p>
 | |
|          </div>
 | |
|          <section id="data-payload">
 | |
|           <h3>
 | |
|            Data Payload
 | |
|            <a class="headerlink" href="#data-payload" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <p>
 | |
|            <em>
 | |
|             x_axis
 | |
|            </em>
 | |
|            and
 | |
|            <em>
 | |
|             y_axis
 | |
|            </em>
 | |
|            fields capture analog input from a joystick, determining direction and speed.
 | |
|            <em>
 | |
|             nav_bttn
 | |
|            </em>
 | |
|            represents a joystick push-button.
 | |
|           </p>
 | |
|           <p>
 | |
|            <em>
 | |
|             led
 | |
|            </em>
 | |
|            allows the transmitter to toggle an onboard LED and is used for status indication (e.g. pairing, battery warning, etc).
 | |
|           </p>
 | |
|           <p>
 | |
|            <em>
 | |
|             motor1_rpm_pwm
 | |
|            </em>
 | |
|            to
 | |
|            <em>
 | |
|             motor4_rpm_pwm
 | |
|            </em>
 | |
|            provide individual PWM signals to four DC motors.
 | |
| This enables fine-grained speed control, supports differential drive configurations, and even allows for maneuvering in multi-directional platforms like omni-wheel robots.
 | |
|           </p>
 | |
|           <section id="why-use-attribute-packed">
 | |
|            <h4>
 | |
|             Why use __attribute((packed))?
 | |
|             <a class="headerlink" href="#why-use-attribute-packed" title="Link to this heading">
 | |
|              ¶
 | |
|             </a>
 | |
|            </h4>
 | |
|            <p>
 | |
|             ESP-NOW uses fixed-size data packets (up to 250 bytes). The
 | |
|             <em>
 | |
|              __attribute__((packed))
 | |
|             </em>
 | |
|             removes compiler-added padding for precise byte alignment.
 | |
|            </p>
 | |
|            <p>
 | |
|             As
 | |
|             <em>
 | |
|              packed
 | |
|             </em>
 | |
|             attribute tells the compiler not to add any padding between fields in memory, this makes the struct:
 | |
|            </p>
 | |
|            <blockquote>
 | |
|             <div>
 | |
|              <ul class="simple">
 | |
|               <li>
 | |
|                <p>
 | |
|                 Compact
 | |
|                </p>
 | |
|               </li>
 | |
|               <li>
 | |
|                <p>
 | |
|                 Predictable for serialization over protocols like UART or ESP-NOW
 | |
|                </p>
 | |
|               </li>
 | |
|               <li>
 | |
|                <p>
 | |
|                 Ideal for low-latency transmission in embedded systems
 | |
|                </p>
 | |
|               </li>
 | |
|              </ul>
 | |
|             </div>
 | |
|            </blockquote>
 | |
|            <p>
 | |
|             This ensures the receiver interprets the exact byte layout you expect, minimizing bandwidth and maximizing compatibility across platforms.
 | |
|            </p>
 | |
|           </section>
 | |
|          </section>
 | |
|         </section>
 | |
|         <span id="document-transmitter">
 | |
|         </span>
 | |
|         <section id="transmitter">
 | |
|          <h2>
 | |
|           TRANSMITTER
 | |
|           <a class="headerlink" href="#transmitter" title="Link to this heading">
 | |
|            ¶
 | |
|           </a>
 | |
|          </h2>
 | |
|          <section id="configuration-variables">
 | |
|           <h3>
 | |
|            Configuration Variables
 | |
|            <a class="headerlink" href="#configuration-variables" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">receiver_mac</span><span class="p">[</span><span class="n">ESP_NOW_ETH_ALEN</span><span class="p">]</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mh">0xe4</span><span class="p">,</span><span class="w"> </span><span class="mh">0xb0</span><span class="p">,</span><span class="w"> </span><span class="mh">0x63</span><span class="p">,</span><span class="w"> </span><span class="mh">0x17</span><span class="p">,</span><span class="w"> </span><span class="mh">0x9e</span><span class="p">,</span><span class="w"> </span><span class="mh">0x44</span><span class="p">};</span>
 | |
| 
 | |
| <span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w">         </span><span class="n">x_axis</span><span class="p">;</span><span class="w">             </span><span class="c1">// Joystick x-position</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w">         </span><span class="n">y_axis</span><span class="p">;</span><span class="w">             </span><span class="c1">// Joystick y-position</span>
 | |
| <span class="w">    </span><span class="kt">bool</span><span class="w">        </span><span class="n">nav_btn</span><span class="p">;</span><span class="w">            </span><span class="c1">// Joystick push button</span>
 | |
| <span class="w">    </span><span class="kt">bool</span><span class="w">        </span><span class="n">led</span><span class="p">;</span><span class="w">                </span><span class="c1">// LED ON/OFF state</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor1_rpm_pwm</span><span class="p">;</span><span class="w">     </span><span class="c1">// PWMs for each DC motor</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor2_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor3_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor4_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="p">}</span><span class="w"> </span><span class="n">__attribute__</span><span class="p">((</span><span class="n">packed</span><span class="p">))</span><span class="w"> </span><span class="n">sensors_data_t</span><span class="p">;</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|          </section>
 | |
|          <section id="reading-joystick-x-and-y-axis-values">
 | |
|           <h3>
 | |
|            Reading Joystick x- and y- Axis Values
 | |
|            <a class="headerlink" href="#reading-joystick-x-and-y-axis-values" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|          </section>
 | |
|          <section id="sending-ecapsulating-data">
 | |
|           <h3>
 | |
|            Sending & Ecapsulating Data
 | |
|            <a class="headerlink" href="#sending-ecapsulating-data" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">sendData</span><span class="w"> </span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| 
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| 
 | |
| <span class="w">    </span><span class="n">buffer</span><span class="p">.</span><span class="n">x_axis</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x_axis</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">buffer</span><span class="p">.</span><span class="n">y_axis</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">y_axis</span><span class="p">;</span>
 | |
| 
 | |
| <span class="w">    </span><span class="c1">// Call ESP-NOW function to send data (MAC address of receiver, pointer to the memory holding data & data length)</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">esp_now_send</span><span class="p">((</span><span class="kt">uint8_t</span><span class="o">*</span><span class="p">)</span><span class="n">receiver_mac</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">buffer</span><span class="p">));</span>
 | |
| 
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="p">}</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|          </section>
 | |
|          <section id="main-function">
 | |
|           <h3>
 | |
|            Main Function
 | |
|            <a class="headerlink" href="#main-function" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">"freertos/FreeRTOS.h"</span>
 | |
| <span class="cp">#include</span><span class="w"> </span><span class="cpf">"nvs_flash.h"</span>
 | |
| <span class="cp">#include</span><span class="w"> </span><span class="cpf">"esp_err.h"</span>
 | |
| 
 | |
| <span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| 
 | |
| <span class="kt">void</span><span class="w"> </span><span class="n">app_main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| 
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| 
 | |
| <span class="w">    </span><span class="c1">// Initialize internal temperature sensor</span>
 | |
| <span class="w">    </span><span class="n">chip_sensor_init</span><span class="p">();</span>
 | |
| 
 | |
| <span class="w">    </span><span class="c1">// Initialize NVS</span>
 | |
| <span class="w">    </span><span class="n">esp_err_t</span><span class="w"> </span><span class="n">ret</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nvs_flash_init</span><span class="p">();</span>
 | |
| <span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">ret</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">ESP_ERR_NVS_NO_FREE_PAGES</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">ret</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">ESP_ERR_NVS_NEW_VERSION_FOUND</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">        </span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="w"> </span><span class="n">nvs_flash_erase</span><span class="p">()</span><span class="w"> </span><span class="p">);</span>
 | |
| <span class="w">        </span><span class="n">ret</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nvs_flash_init</span><span class="p">();</span>
 | |
| <span class="w">    </span><span class="p">}</span>
 | |
| <span class="w">    </span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="w"> </span><span class="n">ret</span><span class="w"> </span><span class="p">);</span>
 | |
| <span class="w">    </span><span class="n">wifi_init</span><span class="p">();</span>
 | |
| <span class="w">    </span><span class="n">joystick_adc_init</span><span class="p">();</span>
 | |
| <span class="w">    </span><span class="n">transmission_init</span><span class="p">();</span>
 | |
| <span class="w">    </span><span class="n">system_led_init</span><span class="p">();</span>
 | |
| 
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="p">}</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|          </section>
 | |
|         </section>
 | |
|         <span id="document-receiver">
 | |
|         </span>
 | |
|         <section id="receiver">
 | |
|          <h2>
 | |
|           RECEIVER
 | |
|           <a class="headerlink" href="#receiver" title="Link to this heading">
 | |
|            ¶
 | |
|           </a>
 | |
|          </h2>
 | |
|          <section id="configuration-variables">
 | |
|           <h3>
 | |
|            Configuration Variables
 | |
|            <a class="headerlink" href="#configuration-variables" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">transmitter_mac</span><span class="p">[</span><span class="n">ESP_NOW_ETH_ALEN</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mh">0x9C</span><span class="p">,</span><span class="w"> </span><span class="mh">0x9E</span><span class="p">,</span><span class="w"> </span><span class="mh">0x6E</span><span class="p">,</span><span class="w"> </span><span class="mh">0x14</span><span class="p">,</span><span class="w"> </span><span class="mh">0xB5</span><span class="p">,</span><span class="w"> </span><span class="mh">0x54</span><span class="p">};</span>
 | |
| 
 | |
| <span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w">         </span><span class="n">x_axis</span><span class="p">;</span><span class="w">             </span><span class="c1">// Joystick x-position</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w">         </span><span class="n">y_axis</span><span class="p">;</span><span class="w">             </span><span class="c1">// Joystick y-position</span>
 | |
| <span class="w">    </span><span class="kt">bool</span><span class="w">        </span><span class="n">nav_bttn</span><span class="p">;</span><span class="w">           </span><span class="c1">// Joystick push button</span>
 | |
| <span class="w">    </span><span class="kt">bool</span><span class="w">        </span><span class="n">led</span><span class="p">;</span><span class="w">                </span><span class="c1">// LED ON/OFF state</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor1_rpm_pwm</span><span class="p">;</span><span class="w">     </span><span class="c1">// PWMs for 4 DC motors</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor2_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor3_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">uint8_t</span><span class="w">     </span><span class="n">motor4_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="p">}</span><span class="w"> </span><span class="n">__attribute__</span><span class="p">((</span><span class="n">packed</span><span class="p">))</span><span class="w"> </span><span class="n">sensors_data_t</span><span class="p">;</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="k">struct</span><span class="w"> </span><span class="nc">motors_rpm</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor1_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor2_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor3_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="kt">int</span><span class="w"> </span><span class="n">motor4_rpm_pwm</span><span class="p">;</span>
 | |
| <span class="p">};</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|          </section>
 | |
|          <section id="receiving-extracting-data">
 | |
|           <h3>
 | |
|            Receiving & Extracting Data
 | |
|            <a class="headerlink" href="#receiving-extracting-data" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">onDataReceived</span><span class="w"> </span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">mac_addr</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">data_len</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| 
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| 
 | |
| <span class="w">    </span><span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span><span class="w"> </span><span class="s">"Data received from: %02x:%02x:%02x:%02x:%02x:%02x, len=%d"</span><span class="p">,</span><span class="w"> </span><span class="n">mac_addr</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="w"> </span><span class="n">mac_addr</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span><span class="w"> </span><span class="n">mac_addr</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span><span class="w"> </span><span class="n">mac_addr</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span><span class="w"> </span><span class="n">mac_addr</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span><span class="w"> </span><span class="n">mac_addr</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span><span class="w"> </span><span class="n">data_len</span><span class="p">);</span>
 | |
| <span class="w">    </span><span class="n">memcpy</span><span class="p">(</span><span class="o">&</span><span class="n">buf</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">buf</span><span class="p">));</span>
 | |
| 
 | |
| <span class="w">    </span><span class="n">x_axis</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">buf</span><span class="p">.</span><span class="n">x_axis</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">y_axis</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">buf</span><span class="p">.</span><span class="n">y_axis</span><span class="p">;</span>
 | |
| 
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="p">}</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|          </section>
 | |
|          <section id="main-function">
 | |
|           <h3>
 | |
|            Main Function
 | |
|            <a class="headerlink" href="#main-function" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <div class="highlight-c notranslate">
 | |
|            <div class="highlight">
 | |
|             <pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf"><string.h></span>
 | |
| <span class="cp">#include</span><span class="w"> </span><span class="cpf">"freertos/FreeRTOS.h"</span>
 | |
| <span class="cp">#include</span><span class="w"> </span><span class="cpf">"nvs_flash.h"</span>
 | |
| <span class="cp">#include</span><span class="w"> </span><span class="cpf">"esp_err.h"</span>
 | |
| 
 | |
| <span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| 
 | |
| <span class="kt">void</span><span class="w"> </span><span class="n">app_main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| 
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| 
 | |
| <span class="w">    </span><span class="c1">// Initialize NVS</span>
 | |
| <span class="w">    </span><span class="n">esp_err_t</span><span class="w"> </span><span class="n">ret</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nvs_flash_init</span><span class="p">();</span>
 | |
| <span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">ret</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">ESP_ERR_NVS_NO_FREE_PAGES</span><span class="w"> </span><span class="o">||</span>
 | |
| <span class="w">        </span><span class="n">ret</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">ESP_ERR_NVS_NEW_VERSION_FOUND</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
 | |
| <span class="w">        </span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="w"> </span><span class="n">nvs_flash_erase</span><span class="p">()</span><span class="w"> </span><span class="p">);</span>
 | |
| <span class="w">        </span><span class="n">ret</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nvs_flash_init</span><span class="p">();</span>
 | |
| <span class="w">    </span><span class="p">}</span>
 | |
| 
 | |
| <span class="w">    </span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="w"> </span><span class="n">ret</span><span class="w"> </span><span class="p">);</span>
 | |
| <span class="w">    </span><span class="n">wifi_init</span><span class="p">();</span>
 | |
| <span class="w">    </span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">esp_now_init</span><span class="p">());</span>
 | |
| 
 | |
| <span class="w">    </span><span class="n">esp_now_peer_info_t</span><span class="w"> </span><span class="n">transmitterInfo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
 | |
| <span class="w">    </span><span class="n">memcpy</span><span class="p">(</span><span class="n">transmitterInfo</span><span class="p">.</span><span class="n">peer_addr</span><span class="p">,</span><span class="w"> </span><span class="n">transmitter_mac</span><span class="p">,</span><span class="w"> </span><span class="n">ESP_NOW_ETH_ALEN</span><span class="p">);</span>
 | |
| <span class="w">    </span><span class="n">transmitterInfo</span><span class="p">.</span><span class="n">channel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="c1">// Current WiFi channel</span>
 | |
| <span class="w">    </span><span class="n">transmitterInfo</span><span class="p">.</span><span class="n">ifidx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ESP_IF_WIFI_STA</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">transmitterInfo</span><span class="p">.</span><span class="n">encrypt</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">false</span><span class="p">;</span>
 | |
| <span class="w">    </span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">esp_now_add_peer</span><span class="p">(</span><span class="o">&</span><span class="n">transmitterInfo</span><span class="p">));</span>
 | |
| 
 | |
| <span class="w">    </span><span class="n">ESP_ERROR_CHECK</span><span class="p">(</span><span class="n">esp_now_register_recv_cb</span><span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">onDataReceived</span><span class="p">));</span>
 | |
| 
 | |
| <span class="w">    </span><span class="n">system_led_init</span><span class="p">();</span>
 | |
| 
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="w">    </span><span class="p">...</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">...</span>
 | |
| <span class="p">}</span>
 | |
| </pre>
 | |
|            </div>
 | |
|           </div>
 | |
|          </section>
 | |
|         </section>
 | |
|         <span id="document-progress">
 | |
|         </span>
 | |
|         <section id="work-in-progress-walk-through">
 | |
|          <h2>
 | |
|           WORK-IN-PROGRESS WALK THROUGH
 | |
|           <a class="headerlink" href="#work-in-progress-walk-through" title="Link to this heading">
 | |
|            ¶
 | |
|           </a>
 | |
|          </h2>
 | |
|          <section id="finished-work">
 | |
|           <h3>
 | |
|            Finished Work
 | |
|            <a class="headerlink" href="#finished-work" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <img alt="_images/ESP-IDF_Robot.jpg" src="_images/ESP-IDF_Robot.jpg"/>
 | |
|          </section>
 | |
|          <section id="chassis">
 | |
|           <h3>
 | |
|            Chassis
 | |
|            <a class="headerlink" href="#chassis" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <figure class="align-center" id="id1">
 | |
|            <a class="reference internal image-reference" href="_images/chassi-progress_002d.jpg">
 | |
|             <img alt="_images/chassi-progress_002d.jpg" src="_images/chassi-progress_002d.jpg" style="height: 300px;"/>
 | |
|            </a>
 | |
|            <figcaption>
 | |
|             <p>
 | |
|              <span class="caption-text">
 | |
|               Completed chassis with only DC motor controllers installed.
 | |
|              </span>
 | |
|              <a class="headerlink" href="#id1" title="Link to this image">
 | |
|               ¶
 | |
|              </a>
 | |
|             </p>
 | |
|            </figcaption>
 | |
|           </figure>
 | |
|          </section>
 | |
|          <section id="wiring">
 | |
|           <h3>
 | |
|            Wiring
 | |
|            <a class="headerlink" href="#wiring" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <figure class="align-center" id="id2">
 | |
|            <a class="reference internal image-reference" href="_images/chassi-progress_003a.jpg">
 | |
|             <img alt="_images/chassi-progress_003a.jpg" src="_images/chassi-progress_003a.jpg" style="height: 750px;"/>
 | |
|            </a>
 | |
|            <figcaption>
 | |
|             <p>
 | |
|              <span class="caption-text">
 | |
|               Completed wiring.
 | |
|              </span>
 | |
|              <a class="headerlink" href="#id2" title="Link to this image">
 | |
|               ¶
 | |
|              </a>
 | |
|             </p>
 | |
|            </figcaption>
 | |
|           </figure>
 | |
|          </section>
 | |
|          <section id="motor-wires-harness">
 | |
|           <h3>
 | |
|            Motor Wires Harness
 | |
|            <a class="headerlink" href="#motor-wires-harness" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <figure class="align-center" id="id3">
 | |
|            <img alt="_images/motors-wiring-harness-001.jpg" src="_images/motors-wiring-harness-001.jpg"/>
 | |
|            <figcaption>
 | |
|             <p>
 | |
|              <span class="caption-text">
 | |
|               DC Motors wires secured inside harnes.
 | |
|              </span>
 | |
|              <a class="headerlink" href="#id3" title="Link to this image">
 | |
|               ¶
 | |
|              </a>
 | |
|             </p>
 | |
|            </figcaption>
 | |
|           </figure>
 | |
|          </section>
 | |
|         </section>
 | |
|         <span id="document-references">
 | |
|         </span>
 | |
|         <section id="references">
 | |
|          <h2>
 | |
|           REFERENCES
 | |
|           <a class="headerlink" href="#references" title="Link to this heading">
 | |
|            ¶
 | |
|           </a>
 | |
|          </h2>
 | |
|          <section id="github">
 | |
|           <h3>
 | |
|            GitHub
 | |
|            <a class="headerlink" href="#github" title="Link to this heading">
 | |
|             ¶
 | |
|            </a>
 | |
|           </h3>
 | |
|           <p>
 | |
|            Complete source
 | |
|            <a class="reference external" href="https://github.com/alexandrebobkov/ESP-Nodes/blob/main/ESP-IDF_Robot/README.md">
 | |
|             code
 | |
|            </a>
 | |
|            with README.md file:
 | |
|            <a class="reference external" href="https://github.com/alexandrebobkov/ESP-Nodes/blob/main/ESP-IDF_Robot/README.md">
 | |
|             https://github.com/alexandrebobkov/ESP-Nodes/blob/main/ESP-IDF_Robot/README.md
 | |
|            </a>
 | |
|           </p>
 | |
|           <p>
 | |
|            KiCAd
 | |
|            <a class="reference external" href="https://github.com/alexandrebobkov/ESP32-C3_Breadboard-Adapter">
 | |
|             Schematic
 | |
|            </a>
 | |
|            and PCB design:
 | |
|            <a class="reference external" href="https://github.com/alexandrebobkov/ESP32-C3_Breadboard-Adapter">
 | |
|             https://github.com/alexandrebobkov/ESP32-C3_Breadboard-Adapter
 | |
|            </a>
 | |
|           </p>
 | |
|          </section>
 | |
|         </section>
 | |
|        </div>
 | |
|       </section>
 | |
|       <div class="clearer">
 | |
|       </div>
 | |
|      </div>
 | |
|     </div>
 | |
|    </div>
 | |
|    <div class="clearer">
 | |
|    </div>
 | |
|   </div>
 | |
|   <article id="back-cover">
 | |
|    <div class="container">
 | |
|     <div class="back-cover-footer">
 | |
|      <p>
 | |
|       © Copyright 2025, Alexander B.
 | |
|      </p>
 | |
|      <p>
 | |
|       Created using
 | |
|       <a href="http://sphinx-doc.org/">
 | |
|        Sphinx
 | |
|       </a>
 | |
|       8.2.3.
 | |
|      </p>
 | |
|     </div>
 | |
|    </div>
 | |
|   </article>
 | |
|  </body>
 | |
| </html>
 |