Dron - IvanCS-Chenfu/Gazebo GitHub Wiki
En esta página se explicará al completo como se ha programado un dron con inteligencia artificial
Todos los parámetros del diseño del dron se encontrarán en el archivo dron.yaml.
En este archivo se dirán las dimensiones del dron
carcasa:
peso_base: 1.0 # kg
peso_brazos: 0.1 # kg (por brazo)
peso_motor: 0.05 # kg (por motor)
longitud_brazo: 0.2 # metros
altura_base: 0.05 # metros
radio_motor: 0.02 # metros
Características de las hélices
helices:
radio_helice: 0.05 # metros
coeficiente_fuerza: 1.1 # N·s²/m⁴
coeficiente_par: 0.01 # N·m·s²/m⁴
sentido_giro: # 1 = CW, -1 = CCW (alternado)
- 1
- -1
- 1
- -1
Finalmente características del plugin del motor para cambiar de la señal PWM
con la que se alimenta a velocidad angular del mismo.
plugin:
intensidad_ruido: 0.02 # fuerza aleatoria ±N
coeficiente_pwm_w: 0.05 # rad/s por unidad de PWM
frecuencia_actualizacion: 100 # Hz
max_pwm: 255 # valor PWM máximo absoluto
En un principio se intentó acceder a los parámetros del .yaml
para la creación del URDF. Sin embargo, por ahora no está implementada dicha opción
El archivo quadcopter.xacro tiene, a parte del link
de la base, una macro la cual pone tanto los 4 brazos como los 4 motores.
Se llaman de la siguiente forma
<xacro:arm_with_motor name="front" parent="base_link" dx="0" dy="0.2" yaw="0"/>
<xacro:arm_with_motor name="back" parent="base_link" dx="0" dy="-0.2" yaw="0"/>
<xacro:arm_with_motor name="left" parent="base_link" dx="-0.2" dy="0" yaw="1.5708"/>
<xacro:arm_with_motor name="right" parent="base_link" dx="0.2" dy="0" yaw="1.5708"/>
Esto crea los brazos, los motores, y las juntas correspondientes. El dron se verá así
Finalmente se implementa el plugin.
<gazebo>
<plugin name="quadcopter_plugin" filename="libquadcopter_plugin.so">
<ros_topic>/pwm_signals</ros_topic>
</plugin>
</gazebo>
En este plugin introducimos un valor de PWM
el cual se transformará mediante perámetros del .yaml
en las fuerzas y en los torques producidos por los motores.
#include "my_quadracopter/quadcopter_plugin.hpp"
Incluye el header del plugin, donde está definida la clase QuadcopterPlugin
.
#include <ament_index_cpp/get_package_share_directory.hpp>
Permite obtener la ruta de instalación del paquete ROS (my_quadracopter
) para localizar el archivo YAML.
#include <yaml-cpp/yaml.h>
Incluye la librería para leer y parsear archivos .yaml
(usado para los parámetros del dron).
#include <ignition/math/Vector3.hh>
Define vectores 3D para aplicar fuerzas y torques.
using namespace gazebo;
Usa el espacio de nombres gazebo
para no escribir gazebo::
todo el tiempo.
QuadcopterPlugin::QuadcopterPlugin() : links_initialized_(false) {}
Constructor de la clase. Inicializa links_initialized_
a false (se usará más tarde para saber si los links del dron ya se han localizado en el modelo).
void gazebo::QuadcopterPlugin::Load(gazebo::physics::ModelPtr _model, sdf::ElementPtr _sdf)
Función llamada automáticamente por Gazebo al cargar el plugin.
_model
: el modelo del dron en el mundo.
_sdf
: parámetros del plugin desde el archivo .sdf
.
model_ = _model;
Guarda el puntero al modelo para usarlo luego (acceder a los links del dron, etc).
if (!rclcpp::ok()) {
rclcpp::init(0, nullptr);
}
Inicializa ROS2 si aún no ha sido inicializado.
ros_node_ = rclcpp::Node::make_shared("quadcopter_plugin_node");
Crea un nodo ROS2 llamado quadcopter_plugin_node
para poder suscribirse a tópicos.
auto yaml_path = ament_index_cpp::get_package_share_directory("my_quadracopter") + "/config/dron.yaml";
Construye la ruta absoluta al archivo de configuración dron.yaml
.
auto config = YAML::LoadFile(yaml_path);
Carga el archivo .yaml
.
coef_pwm_w_ = config["plugin"]["coeficiente_pwm_w"].as<double>();
coef_force_ = config["helices"]["coeficiente_fuerza"].as<double>();
coef_torque_ = config["helices"]["coeficiente_par"].as<double>();
radius_ = config["helices"]["radio_helice"].as<double>();
Lee los parámetros desde el .yaml
y los guarda en atributos de clase.
motor_links_ = { "front_motor", "back_motor", "left_motor", "right_motor" };
Define los nombres de los motores (los links
que representan hélices).
pwm_values_.resize(4, 0);
Inicializa el vector de señales PWM
con cuatro valores en cero.
std::string topic = "/pwm_signals";
if (_sdf->HasElement("ros_topic")) {
topic = _sdf->Get<std::string>("ros_topic");
}
Define el tópico por defecto /pwm_signals
, pero permite sobreescribirlo desde el .sdf
.
sub_ = ros_node_->create_subscription<std_msgs::msg::Int32MultiArray>(
topic, 10, std::bind(&QuadcopterPlugin::OnRosMsg, this, std::placeholders::_1)
);
Se suscribe al tópico para recibir mensajes PWM
como un Int32MultiArray
.
std::thread([node = ros_node_]() { rclcpp::spin(node); }).detach();
Lanza el nodo ROS en un hilo separado para que pueda escuchar mensajes mientras Gazebo corre.
gazebo::event::Events::ConnectWorldUpdateBegin(
std::bind(&QuadcopterPlugin::ApplyForces, this));
Registra una función callback ApplyForces
que se ejecutará en cada ciclo de simulación.
void QuadcopterPlugin::OnRosMsg(const std_msgs::msg::Int32MultiArray::SharedPtr msg)
{
pwm_values_ = msg->data;
ApplyForces();
}
Al recibir un mensaje PWM
, guarda los valores y llama a ApplyForces
inmediatamente para aplicarlos.
void gazebo::QuadcopterPlugin::ApplyForces()
Método llamado en cada ciclo de simulación para aplicar fuerza/torque en cada motor.
if (!model_) return;
Evita errores si el modelo aún no está cargado.
if (!links_initialized_) {
links_.clear();
Si aún no se encontraron los links
motores, intenta localizarlos.
for (const auto& name : motor_links_) {
auto link = model_->GetLink(name);
if (!link) return;
links_.push_back(link);
}
links_initialized_ = true;
}
Busca cada link
motor por su nombre. Si falta alguno, sale y lo intentará de nuevo en el siguiente ciclo.
for (size_t i = 0; i < pwm_values_.size() && i < links_.size(); ++i) {
Itera sobre cada motor (y valor PWM
recibido).
double w = coef_pwm_w_ * pwm_values_[i];
double thrust = coef_force_ * w * w * radius_ * radius_;
double torque_z = coef_torque_ * w;
Convierte el PWM
a velocidad angular w
, y luego calcula fuerza y torque.
links_[i]->AddRelativeForce({0, 0, thrust});
links_[i]->AddRelativeTorque({0, 0, torque_z});
Aplica fuerza y torque en el eje Z en el sistema local del link (por eso se usa AddRelativeForce
).
GZ_REGISTER_MODEL_PLUGIN(QuadcopterPlugin)
Macro de Gazebo para registrar el plugin y permitir que sea cargado desde un archivo SDF
o URDF
.
Para comprobar si todo está correcto se ha realizado el nodo prueba.cpp Este nodo eleva y desciende el valor de PWM según las teclas pulsadas en la terminal.