I am trying to control a Servo in c ++ using the libgpiod library.
My problem is in defining the 50Hz pwm pulse on the pin that the servo is connected to.
The servo signal cable is connected to pin 33 which corresponds to GPIO 13 (pwm1).
#define ESC_PIN 13
Then I get the chip that controls the line and configure its operation as well as add a description
this-> output_chip = gpiod_chip_open_by_number (0);
this-> esc_line = gpiod_chip_get_line (output_chip, esc_pin);
gpiod_line_request_output (esc_line, "Esc", GPIOD_LINE_ACTIVE_STATE_HIGH);
With the following lines of code I can control the state of the pin but I don't know how to define a pwm pulse without using the sleep function
gpiod_line_set_value (this-> esc_line, 1);
std :: this_thread :: sleep_for (std :: chrono :: milliseconds (2));
gpiod_line_set_value (this-> esc_line, 0);
std :: this_thread :: sleep_for (std :: chrono :: milliseconds (18));
main.cpp (trimmed code)
#include "Telecommunications.h"
#include "Gps.h"
#include "Esc.h"
#include <thread>
#include <atomic>
#include <csignal>
#define ESC_PIN 13
// I'm not a fan of globals but with this way we can catch signals and close files accordingly
Telecommunications g_antenna;
Esc g_esc;
// creating signal handler to close gps, GPIO & I2C
void ctl_c(int s){
printf("Ending threads\n");
g_antenna.stop = true;
// g_gps.stop = true;
g_esc.stop = true;
sleep(2); // let the threads end the loops and finally exit
printf("Bye!\n");
exit(s);
}
int main(int argc, char** argv)
{
// initialize sensors variables
std::atomic<int> height = 0, X = 0, Y = 0, Z = 0;
std::atomic<double> latitude = 0.0, longitude = 0.0, altitude = 0.0, speed = 0.0;
// initialize actuators variables
std::atomic<int> engine = 0, rudder = 0, elevator = 0, ailerons = 0;
// initialize Telecommunications with Reciver
g_antenna.init(&height, &latitude, &longitude, &altitude, &speed, &X, &Y, &Z, &engine, &rudder, &elevator, &ailerons);
// initialize sensors
Gps g_gps; // = new Gps(&latitude, &longitude, &altitude, &speed);
g_gps.init(&latitude, &longitude, &altitude, &speed);
// initialize actuators
g_esc.init(&engine, ESC_PIN);
// read signal events so we can terminate the threads and close the files
signal(SIGINT, ctl_c);
signal(SIGKILL, ctl_c);
signal(SIGSTOP, ctl_c);
// never stop the program
while (true){
try{
// launching telecommunications && joining main thread
std::thread t_antenna(&Telecommunications::run, &g_antenna);
// launching sensors && joining main thread
// std::thread t_gps(&Gps::run, &g_gps);
// launching actuators && joining main thread
std::thread t_engine(&Esc::run, &g_esc);
t_antenna.join();
// t_gps.join();
t_engine.join();
} catch (const std::exception &e){ // catch any exception
// log the exceptions on the DB
printf("Exception on main: %s", e.what());
continue;
}
}
// we do no expect to end the loop until a Ctl+C is send and the function ctl_c will exit()
return 0;
}
Esc.h
//
// Created by X on 17/12/2020.
//
#ifndef ROHA_ESC_H
#define ROHA_ESC_H
#include <gpiod.h>
#include <atomic>
#include <chrono>
class Esc {
public:
bool stop = false;
explicit Esc(std::atomic<int> *engine_ptr, int esc_pin){
this->init(engine_ptr, esc_pin);
}
Esc() = default;
void init(std::atomic<int> *engine_ptr, int esc_pin){
this->engine = engine_ptr;
this->output_chip = gpiod_chip_open_by_number(0);
this->esc_line = gpiod_chip_get_line(output_chip, esc_pin);
// request the ESC pin, set a description and define it as ACTIVE_STATE_HIGH
gpiod_line_request_output(esc_line, "Esc", GPIOD_LINE_ACTIVE_STATE_HIGH);
// write ZERO signal to pin
gpiod_line_set_value(esc_line, 0);
}
void run(){
while (!this->stop){
try {
// read telecomunications is writing values between 0 and 180
int speed = this->engine->load();
if (speed < 0) speed = 0;
if (speed > 180) speed = 180;
// pending, map values to the expected HIGH state ms
// aproach
gpiod_line_set_value(esc_line, 1);
std::this_thread::sleep_for(std::chrono::milliseconds(1));
gpiod_line_set_value(esc_line, 0);
std::this_thread::sleep_for(std::chrono::milliseconds(19));
} catch (const std::exception &e){
printf("Error on Esc: %s\n", e.what());
continue;
}
}
this->close_gpio();
printf("Ending Thread! Esc\n");
}
private:
std::atomic<int> *engine {};
struct gpiod_chip *output_chip{};
struct gpiod_line *esc_line{};
void close_gpio(){
gpiod_line_release(this->esc_line);
gpiod_chip_close(this->output_chip);
}
};
#endif //ROHA_ESC_H
This program is for learning C ++ to control electronics from a rpi. Any improvement or bad practice that you see in the code will be appreciated if you comment it