CyberBrick Receiver Shield (X11) - rotorman/CyberBrick_ESPNOW GitHub Wiki

By inspecting the original CyberBrick MicroPython code and the info provided at the CyberBrick Quick reference, I was able to extract the full ESP32-C3 pin-mapping (GPIO 0 to 21) for the receiver side X11 shield.

CyberBrick receiver shield CyberBrick Controller Core

The X11 shield has the following mapping to the CyberBrick core ESP32-C3 GPIO pins:

In addition (from https://makerworld.com/en/cyberbrick/api-doc/cyberbrick_core/quickref.html#pins-and-gpio ):

  • GPIO Pins 18 & 19 are used for REPL USB D- and D+ respectively
  • GPIO Pins 12 to 17 are used for connecting the embedded flash

In the original CyberBrick core MicroPython code, the PWM output is controlled via MicroPython.timer0 at 50 Hz PWM frequency and has only 20 steps (various output duty cycles) per movement direction (20 steps forward, 20 steps backwards plus off, thus 41 various steps/options per motor channel).

Timer0 is initialized to run at 1 kHz and the duty cycle is generated in software code in Timer0 callback: https://github.com/CyberBrick-Official/CyberBrick_Controller_Core/blob/b5fc07d44d65143cfef1164ae6234099fcb11d62/src/app_rc/app/control.py#L602-L605 -> https://github.com/CyberBrick-Official/CyberBrick_Controller_Core/blob/b5fc07d44d65143cfef1164ae6234099fcb11d62/src/app_rc/app/control.py#L1013-L1014 -> https://github.com/CyberBrick-Official/CyberBrick_Controller_Core/blob/b5fc07d44d65143cfef1164ae6234099fcb11d62/src/app_rc/bbl/motors.py#L74-L113 -> https://github.com/CyberBrick-Official/CyberBrick_Controller_Core/blob/b5fc07d44d65143cfef1164ae6234099fcb11d62/src/app_rc/bbl/motors.py#L15

My guess is, that CyberBrick developers opted for Timer0 based solution for the PWM, and NOT the much simpler and better machine.pwm option that is available for ESP32-C3, as ESP32-C3 can have a maximum of 6 PWM outputs, as also written in the quick reference. The HTD8811 dual brushed motor controller, as used on the X11 receiver shield, needs two pins per motor. With 4 servo outputs, this would sum up to a total of 8 PWM channels needed, which is more than ESP32-C3 on the CyberBrick core can do in hardware. Even though it would be possible to drive one motor from the hardware PWM, the other motor would then still need a different solution. Likely, to have both motors behave similarly, a decision was made to drive both from Timer0 software PWM routing.

20 steps per direction is pretty coarse when compared with typical todays RC toys, where typically 9 to 12 bits per proportional channel are used (512 to 4096 steps over both movement directions combined). Also most todays motor controllers run at higher PWM frequencies, typically between 1 and 30 kHz, whereas indeed there are higher switching losses at higher frequencies. Higher frequencies cause less vibration, especially on smaller motors with not so much inertia weight.

Servo outputs on the other hand do use machine.pwm. As the code implements PWM.duty(), instead of PWM.duty_u16(), only 10 bit resolution (instead of full 16 bit) can be utilized with the original CyberBrick MicroPython code for the full duty cycle (for more see here).

In set_angle() mode, this evaluates to values 25 to 127 in full 1024 step range for the full 20ms PWM period, which results in 25/1024 * 20=0.49ms to 127/1024 * 20=2.48ms servo pulse range for the 0 to 180 degree input value.

In set_speed() mode (76.8-51.2)/1024 * 20=0.5ms to (51.2+76.8)/1024 * 20=2.5ms servo pulse is used.

The resolution in set_angle() mode is 127-25=102 steps or 1.77°, which is not great, especially for steering a model. In set_speed() mode the resolution is 201 steps (integers from -100 to +100).

Do note that the proportional input from the remote control is 12-bit (4096 steps).

1Both brushed motor outputs are controlled via Heroic HTD8811 that uses two pins per motor. The speed value is converted into these two outputs in code in: https://github.com/CyberBrick-Official/CyberBrick_Controller_Core/blob/b5fc07d44d65143cfef1164ae6234099fcb11d62/src/app_rc/bbl/motors.py#L308-L327 (alternatively see Heroic HTD8811 datasheet page 8 for this info).

⚠️ **GitHub.com Fallback** ⚠️