RC Robot Tutorial

This commit is contained in:
2025-07-21 03:08:12 -04:00
parent 201f974cec
commit f94208f921
6 changed files with 93 additions and 56 deletions

View File

@@ -144,7 +144,9 @@ Similarly, when the joystick is pushed fully to the left or right, the X-axis vo
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.
The table below summarizes the reserved GPIOs.
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.
+------+-----+---------------------------------------------------------+----------------+
| GPIO | Pin | Function | Notes |
@@ -164,7 +166,10 @@ The table below summarizes the reserved GPIOs.
| 7 | 6 | PWM for counter-clockwise rotation of left-side motors | LEDC_CHANNEL_3 |
+------+-----+---------------------------------------------------------+----------------+
The *struct* for storing motors PWM values.
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.
.. code-block:: c
@@ -175,7 +180,8 @@ The *struct* for storing motors PWM values.
int motor4_rpm_pwm;
};
The function for updating motors' PWM values.
On the transmitter`` device, the PWM values for the DC motors are send to the receover using the following function. The variable
**receiver_mac** stores the MAC address of the receiver device (ESP32-C3 bitBoard on the RC car).
.. code-block:: c
@@ -209,26 +215,9 @@ The function for updating motors' PWM values.
ESP_LOGW("ESP-NOW", "Data was sent.");
}
The onDataReceived() and onDataSent() are two call-back functions that get evoked on each corresponding event.
.. code-block:: c
// Call-back for the event when data is being received
void onDataReceived (uint8_t *mac_addr, uint8_t *data, uint8_t data_len) {
buf = (sensors_data_t*)data; // Allocate memory for buffer to store data being received
ESP_LOGW(TAG, "Data was received");
ESP_LOGI(TAG, "x-axis: 0x%04x", buf->x_axis);
ESP_LOGI(TAG, "x-axis: 0x%04x", buf->y_axis);
ESP_LOGI(TAG, "PWM 1: 0x%04x", buf->motor1_rpm_pwm);
}
// Call-back for the event when data is being sent
void onDataSent (uint8_t *mac_addr, esp_now_send_status_t status) {
ESP_LOGW(TAG, "Packet send status: 0x%04X", status);
}
The rc_send_data_task() function runs every 0.1 second to transmit the data to the receiver.
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 behavior—critical for real-time control in embedded applications.
.. code-block:: c
@@ -242,6 +231,35 @@ The rc_send_data_task() function runs every 0.1 second to transmit the data to t
}
}
As data is being sent, the function onDataSent() is called to check & display the status of the data transmission.
.. code-block:: c
// Call-back for the event when data is being sent
void onDataSent (uint8_t *mac_addr, esp_now_send_status_t status) {
ESP_LOGW(TAG, "Packet send status: 0x%04X", status);
}
... ... ...
... ... ...
On the receiver device, the data is saved in the variables by the call-back function onDataReceived().
.. code-block:: c
// Call-back for the event when data is being received
void onDataReceived (uint8_t *mac_addr, uint8_t *data, uint8_t data_len) {
buf = (sensors_data_t*)data; // Allocate memory for buffer to store data being received
ESP_LOGW(TAG, "Data was received");
ESP_LOGI(TAG, "x-axis: 0x%04x", buf->x_axis);
ESP_LOGI(TAG, "x-axis: 0x%04x", buf->y_axis);
ESP_LOGI(TAG, "PWM 1: 0x%04x", buf->motor1_rpm_pwm);
}
The rc_send_data_task() function runs every 0.1 second to transmit the data to the receiver.
Schematic
---------

View File

@@ -184,7 +184,9 @@ 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.</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>
@@ -231,7 +233,10 @@ to pivot. The opposite occurs for a right turn, with 100% PWM on the right and 0
</tr>
</tbody>
</table>
<p>The <em>struct</em> for storing motors PWM values.</p>
<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>
@@ -240,7 +245,8 @@ to pivot. The opposite occurs for a right turn, with 100% PWM on the right and 0
<span class="p">};</span>
</pre></div>
</div>
<p>The function for updating motors PWM values.</p>
<p>On the transmitter`` device, the PWM values for the DC motors are send to the receover 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>
@@ -272,24 +278,9 @@ to pivot. The opposite occurs for a right turn, with 100% PWM on the right and 0
<span class="p">}</span>
</pre></div>
</div>
<p>The onDataReceived() and onDataSent() are two call-back functions that get evoked on each corresponding event.</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">&quot;Data was received&quot;</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">&quot;x-axis: 0x%04x&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="o">-&gt;</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">&quot;x-axis: 0x%04x&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="o">-&gt;</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">&quot;PWM 1: 0x%04x&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="o">-&gt;</span><span class="n">motor1_rpm_pwm</span><span class="p">);</span>
<span class="p">}</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">&quot;Packet send status: 0x%04X&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">status</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The rc_send_data_task() function runs every 0.1 second to transmit the data to the receiver.</p>
<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 FreeRTOSs precise task scheduling, the system maintains low-latency
communication and predictable behavior—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>
@@ -301,6 +292,29 @@ to pivot. The opposite occurs for a right turn, with 100% PWM on the right and 0
<span class="p">}</span>
</pre></div>
</div>
<p>As data is being sent, the function onDataSent() is called to check &amp; 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">&quot;Packet send status: 0x%04X&quot;</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">&quot;Data was received&quot;</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">&quot;x-axis: 0x%04x&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="o">-&gt;</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">&quot;x-axis: 0x%04x&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="o">-&gt;</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">&quot;PWM 1: 0x%04x&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">buf</span><span class="o">-&gt;</span><span class="n">motor1_rpm_pwm</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The rc_send_data_task() function runs every 0.1 second to transmit the data to the receiver.</p>
</section>
<section id="schematic">
<h2><span class="section-number">2.3. </span>Schematic<a class="headerlink" href="#schematic" title="Link to this heading"></a></h2>

File diff suppressed because one or more lines are too long

View File

@@ -215,6 +215,22 @@ On the transmitter`` device, the PWM values for the DC motors are send to the re
ESP_LOGW("ESP-NOW", "Data was sent.");
}
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 behavior—critical for real-time control in embedded applications.
.. code-block:: c
// Continous, periodic task that sends data.
static void rc_send_data_task (void *arg) {
while (true) {
if (esp_now_is_peer_exist(receiver_mac))
sendData();
vTaskDelay (100 / portTICK_PERIOD_MS);
}
}
As data is being sent, the function onDataSent() is called to check & display the status of the data transmission.
.. code-block:: c
@@ -243,17 +259,6 @@ On the receiver device, the data is saved in the variables by the call-back func
The rc_send_data_task() function runs every 0.1 second to transmit the data to the receiver.
.. code-block:: c
// Continous, periodic task that sends data.
static void rc_send_data_task (void *arg) {
while (true) {
if (esp_now_is_peer_exist(receiver_mac))
sendData();
vTaskDelay (100 / portTICK_PERIOD_MS);
}
}
Schematic
---------