This library communicates with PWM servos.
Pulse Width Modulation (PWM) is a protocol for receivers to send commands to servos. Each servo is sent a high pulse with the width of the pulse dictating the commanded position. Traditionally, PWM commands are sent at a 50 Hz interval with pulse widths varying between 1000 us and 2000 us. Some servos and Electronic Speed Controllers (ESCs) support higher frequencies, which typically requires a shorter pulse width range. PWM is the most common protocol for sending servo and ESC commands, but they require a PWM capable pin for each servo being controlled.
CMake is used to build this library, which is exported as a library target called pwm. The header is added as:
#include "pwm/pwm.h"
Note that you'll need CMake version 3.13 or above; it is recommended to build and install CMake from source, directions are located in the CMake GitLab repository.
The library can be also be compiled stand-alone using the CMake idiom of creating a build directory and then, from within that directory issuing:
cmake .. -DMCU=MK66FX1M0
make
This will build the library and example executable called pwm_example. The example executable source file is located at examples/pwm_example.cc. This code is built and tested on AARCH64 and AMD64 systems running Linux and on AMD64 systems running the Windows Subsystem for Linux (WSL). The arm-none-eabi toolchain must be installed in your Linux environment.
Notice that the cmake command includes a define specifying the microcontroller the code is being compiled for. This is required to correctly configure the code, CPU frequency, and compile/linker options. The available MCUs are:
- MK20DX128
- MK20DX256
- MK64FX512
- MK66FX1M0
- MKL26Z64
These are known to work with the same packages used in Teensy products. Also switching the MK66FX1M0 or MK64FX512 from BGA to LQFP packages is known to work well. Swapping packages of other chips is probably fine, as long as it's only a package change.
The pwm_example target creates an executable for communicating with PWM servos. This target also has a _hex for creating the hex file and a _upload to upload the software to the microcontroller.
The PWM object for sending commands to servos is within the namespace actuators.
Pwm(std::array<int, N> pins) Creates a Pwm object. This is a templated class with the number of PWM pins as a template parameter. The PWM pin numbers are passed as an array to the constructor.
/* Assings pins 21, 22, 23, 2, 3, 4, 5, 6, to the Pwm object for controlling PWM servos */
actuators::Pwm<8> pwm({21, 22, 23, 2, 3, 4, 5, 6});
void Begin() Initializes the PWM pins.
pwm.Begin();
void frequency_hz(float val) Enables changing the update frequency for the PWM commands. By default, this frequency is 50 Hz. Check with your servo or ESC manufacturer for supported frequencies.
pwm.frequency_hz(333);
float frequency_hz() Returns the current update frequency.
std::cout << pwm.frequency_hz() << std::endl;
void Write() Writes the PWM commands. Commands are generated by hardware timers within the microcontroller and will be sent to the servos at the specified update frequency. Write only needs to be called when the servo commands have been updated. There may be up to a one frame delay between issuing the Write command and the updated PWM pulse being sent to the servo.
pwm.Write();
void tx_channels(const std::array<uint16_t, N> &val) Sets the channel data to be transmitted. Note that the length of the array should be the same as the number of pins.
pwm.tx_channels(pwm_tx_data);
std::array<uint16_t, N> tx_channels() Returns the array of channel data to be transmitted. Note that the length of the returned array is the same as the number of pins.
std::array<uint16_t, 8> pwm_tx_data = pwm.tx_channels();