如何使用esp32从零制作一个ROS2的teleop遥控器(cmd_vel)

本文介绍了如何使用ESP32通过Arduino接口连接硬件,并利用Micro XRCE-DDS-Agent将读取的模拟信号转换为速度指令,远程控制Turtlesim。首先,详细说明了ESP32与Arduino端口的映射,然后展示了配置Micro XRCE-DDS-Agent的步骤,包括启动Agent和设置波特率。最后,给出了用于发布速度的ROS2代码,实现了从ESP32读取A0和A6口的模拟值并转化为Turtlesim的线速度和角速度。

使用课程所用镜像,硬件连线如下图所示:

使用io口34和36,对应的arduino端口如下列表:

static const uint8_t A0 = 36;
static const uint8_t A3 = 39;
static const uint8_t A4 = 32;
static const uint8_t A5 = 33;
static const uint8_t A6 = 34;
static const uint8_t A7 = 35;
static const uint8_t A10 = 4;
static const uint8_t A11 = 0;
static const uint8_t A12 = 2;
static const uint8_t A13 = 15;
static const uint8_t A14 = 13;
static const uint8_t A15 = 12;
static const uint8_t A16 = 14;
static const uint8_t A17 = 27;
static const uint8_t A18 = 25;
static const uint8_t A19 = 26;

分别是A0和A6,测试一下,是否ok。

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // print out the value you read:
  Serial.println(sensorValue);
  delay(1);        // delay in between reads for stability
}

分别测一下A0和A6是否正常。

 

 参考如下两篇:

​​​​​​esp32(ROS2foxy)从字符串发布到速度发布turtlesim_zhangrelay的专栏-优快云博客

esp32➡遥控篇➡turtlesim➡mobot➡turtlebot3_zhangrelay的专栏-优快云博客

然后尝试写出如下代码:

#include <ros2arduino.h>
 
#include <WiFi.h>
#include <WiFiUdp.h>
#define SSID       "***"
#define SSID_PW    "***"
#define AGENT_IP   "***"
#define AGENT_PORT 2021 //AGENT port number
 
#define PUBLISH_FREQUENCY 2 //hz

int linx_mid = 0;
int angz_mid = 0;

int sensorlinx = 0;
int sensorangz = 0;
 
void publishVel(geometry_msgs::Twist* vel, void* arg)
{
  (void)(arg);
  static int cnt = 0;
  vel->linear.x = (sensorlinx-linx_mid)/1024.0;  //线速度
  vel->angular.z = (sensorangz-angz_mid)/1024.0; //角速度
  cnt++;
}
 
class VelPub : public ros2::Node
{
public:
  VelPub()
  : Node("esp32_cmdvel")
  {
    ros2::Publisher<geometry_msgs::Twist>* publisher_ = this->createPublisher<geometry_msgs::Twist>("turtle1/cmd_vel");
    this->createWallFreq(PUBLISH_FREQUENCY, (ros2::CallbackFunc)publishVel, nullptr, publisher_);
  }
};
 
WiFiUDP udp;
 
void setup() 
{
  WiFi.begin(SSID, SSID_PW);
  while(WiFi.status() != WL_CONNECTED);
 
  ros2::init(&udp, AGENT_IP, AGENT_PORT);
  linx_mid = analogRead(A6);
  angz_mid = analogRead(A0);
}
 
void loop() 
{
  
  sensorlinx = analogRead(A6);
  sensorangz = analogRead(A0);
  static VelPub VelNode;
  
  ros2::spin(&VelNode);
}

需要配置Micro-XRCE-DDS-Agent-1.3.0,在home文件下中新建ros/RobCode文件夹,并将编译好文件放入其中。

如果直接运行tool下工具会报错。需要安装此库。复制后即完成安装,如果不行,使用sudo make install。

正常后如下所示:

 先输入q退出,然后再输入如下命令行:

./MicroXRCEAgent udp4 --port 2021

完成配置。打开turtlesim。即可用esp32进行遥控。


ROS2中订阅 `/cmd_vel_nav` 话题,通常需要创建一个Python或C++节点来实现。以下分别给出Python和C++的示例代码。 ### Python实现 ```python import rclpy from rclpy.node import Node from geometry_msgs.msg import Twist class CmdVelNavSubscriber(Node): def __init__(self): super().__init__('cmd_vel_nav_subscriber') self.subscription = self.create_subscription( Twist, '/cmd_vel_nav', self.listener_callback, 10) self.subscription # prevent unused variable warning def listener_callback(self, msg): self.get_logger().info('Received linear.x: "%s"' % msg.linear.x) self.get_logger().info('Received angular.z: "%s"' % msg.angular.z) def main(args=None): rclpy.init(args=args) cmd_vel_nav_subscriber = CmdVelNavSubscriber() rclpy.spin(cmd_vel_nav_subscriber) cmd_vel_nav_subscriber.destroy_node() rclpy.shutdown() if __name__ == '__main__': main() ``` ### C++实现 ```cpp #include <rclcpp/rclcpp.hpp> #include <geometry_msgs/msg/twist.hpp> class CmdVelNavSubscriber : public rclcpp::Node { public: CmdVelNavSubscriber() : Node("cmd_vel_nav_subscriber") { subscription_ = this->create_subscription<geometry_msgs::msg::Twist>( "/cmd_vel_nav", 10, std::bind(&CmdVelNavSubscriber::topic_callback, this, std::placeholders::_1)); } private: void topic_callback(const geometry_msgs::msg::Twist::SharedPtr msg) const { RCLCPP_INFO(this->get_logger(), "Received linear.x: '%f'", msg->linear.x); RCLCPP_INFO(this->get_logger(), "Received angular.z: '%f'", msg->angular.z); } rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr subscription_; }; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); auto node = std::make_shared<CmdVelNavSubscriber>(); rclcpp::spin(node); rclcpp::shutdown(); return 0; } ``` ### 代码解释 #### Python代码 1. 导入必要的库,包括 `rclpy` 用于ROS2的Python客户端库,`Node` 用于创建节点,`Twist` 是 `/cmd_vel_nav` 话题的消息类型。 2. 创建一个继承自 `Node` 的类 `CmdVelNavSubscriber`,在构造函数中创建一个订阅者,订阅 `/cmd_vel_nav` 话题,并指定回调函数 `listener_callback`。 3. 在 `listener_callback` 函数中,打印接收到的线速度和角速度信息。 4. 在 `main` 函数中,初始化ROS2,创建节点,进入循环等待消息,最后销毁节点并关闭ROS2。 #### C++代码 1. 包含必要的头文件,包括 `rclcpp` 用于ROS2的C++客户端库,`Twist` 是 `/cmd_vel_nav` 话题的消息类型。 2. 创建一个继承自 `rclcpp::Node` 的类 `CmdVelNavSubscriber`,在构造函数中创建一个订阅者,订阅 `/cmd_vel_nav` 话题,并指定回调函数 `topic_callback`。 3. 在 `topic_callback` 函数中,打印接收到的线速度和角速度信息。 4. 在 `main` 函数中,初始化ROS2,创建节点,进入循环等待消息,最后关闭ROS2。 ### 编译和运行 #### Python 将上述Python代码保存为一个 `.py` 文件,例如 `cmd_vel_nav_subscriber.py`,并赋予执行权限: ```bash chmod +x cmd_vel_nav_subscriber.py ``` 然后在终端中运行: ```bash ros2 run <package_name> cmd_vel_nav_subscriber.py ``` #### C++ 将上述C++代码保存为一个 `.cpp` 文件,例如 `cmd_vel_nav_subscriber.cpp`,并在 `CMakeLists.txt` 中添加以下内容: ```cmake add_executable(cmd_vel_nav_subscriber src/cmd_vel_nav_subscriber.cpp) ament_target_dependencies(cmd_vel_nav_subscriber rclcpp geometry_msgs) install(TARGETS cmd_vel_nav_subscriber DESTINATION lib/${PROJECT_NAME} ) ``` 然后在工作空间根目录下编译: ```bash colcon build --packages-select <package_name> ``` 最后在终端中运行: ```bash ros2 run <package_name> cmd_vel_nav_subscriber ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangrelay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值