5841|1

655

帖子

30

TA的资源

版主

楼主
 

40“万里”树莓派小车——ROS学习(C语言编程控制小乌龟) [复制链接]

本帖最后由 lb8820265 于 2022-11-1 14:52 编辑

        前面介绍了运行“turtle_teleop_key”节点,然后通过键盘来控制小乌龟。要自己编写代码来控制小乌龟,可以先学习“turtle_teleop_key”节点是怎么编写的。

官方源码

         ROS安装后“turtle_teleop_key”节点就已经是二进制文件了,无法看到源码,如下图。

     不过在官方github仓库中可以看到源码,该源码中有很多C++和Python的例子供参考,下载下来,解压缩,在如下位置中就可以看到cpp源码。

      “turtle_teleop_key.cpp”全部源码如下。

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <signal.h>
#include <stdio.h>
#ifndef _WIN32
# include <termios.h>
# include <unistd.h>
#else
# include <windows.h>
#endif
#define KEYCODE_RIGHT 0x43
#define KEYCODE_LEFT 0x44
#define KEYCODE_UP 0x41
#define KEYCODE_DOWN 0x42
#define KEYCODE_B 0x62
#define KEYCODE_C 0x63
#define KEYCODE_D 0x64
#define KEYCODE_E 0x65
#define KEYCODE_F 0x66
#define KEYCODE_G 0x67
#define KEYCODE_Q 0x71
#define KEYCODE_R 0x72
#define KEYCODE_T 0x74
#define KEYCODE_V 0x76
class KeyboardReader
{
public:
  KeyboardReader()
#ifndef _WIN32
    : kfd(0)
#endif
  {
#ifndef _WIN32
    // get the console in raw mode
    tcgetattr(kfd, &cooked);
    struct termios raw;
    memcpy(&raw, &cooked, sizeof(struct termios));
    raw.c_lflag &=~ (ICANON | ECHO);
    // Setting a new line, then end of file
    raw.c_cc[VEOL] = 1;
    raw.c_cc[VEOF] = 2;
    tcsetattr(kfd, TCSANOW, &raw);
#endif
  }
  void readOne(char * c)
  {
#ifndef _WIN32
    int rc = read(kfd, c, 1);
    if (rc < 0)
    {
      throw std::runtime_error("read failed");
    }
#else
    for(;;)
    {
      HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
      INPUT_RECORD buffer;
      DWORD events;
      PeekConsoleInput(handle, &buffer, 1, &events);
      if(events > 0)
      {
        ReadConsoleInput(handle, &buffer, 1, &events);
        if (buffer.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)
        {
          *c = KEYCODE_LEFT;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == VK_UP)
        {
          *c = KEYCODE_UP;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)
        {
          *c = KEYCODE_RIGHT;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == VK_DOWN)
        {
          *c = KEYCODE_DOWN;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == 0x42)
        {
          *c = KEYCODE_B;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == 0x43)
        {
          *c = KEYCODE_C;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == 0x44)
        {
          *c = KEYCODE_D;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == 0x45)
        {
          *c = KEYCODE_E;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == 0x46)
        {
          *c = KEYCODE_F;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == 0x47)
        {
          *c = KEYCODE_G;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == 0x51)
        {
          *c = KEYCODE_Q;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == 0x52)
        {
          *c = KEYCODE_R;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == 0x54)
        {
          *c = KEYCODE_T;
          return;
        }
        else if (buffer.Event.KeyEvent.wVirtualKeyCode == 0x56)
        {
          *c = KEYCODE_V;
          return;
        }
      }
    }
#endif
  }
  void shutdown()
  {
#ifndef _WIN32
    tcsetattr(kfd, TCSANOW, &cooked);
#endif
  }
private:
#ifndef _WIN32
  int kfd;
  struct termios cooked;
#endif
};
KeyboardReader input;
class TeleopTurtle
{
public:
  TeleopTurtle();
  void keyLoop();
private:
  ros::NodeHandle nh_;
  double linear_, angular_, l_scale_, a_scale_;
  ros::Publisher twist_pub_;
};
TeleopTurtle::TeleopTurtle():
  linear_(0),
  angular_(0),
  l_scale_(2.0),
  a_scale_(2.0)
{
  nh_.param("scale_angular", a_scale_, a_scale_);
  nh_.param("scale_linear", l_scale_, l_scale_);
  twist_pub_ = nh_.advertise<geometry_msgs::Twist>("turtle1/cmd_vel", 1);
}
void quit(int sig)
{
  (void)sig;
  input.shutdown();
  ros::shutdown();
  exit(0);
}
int main(int argc, char** argv)
{
  ros::init(argc, argv, "teleop_turtle");
  TeleopTurtle teleop_turtle;
  signal(SIGINT,quit);
  teleop_turtle.keyLoop();
  quit(0);
  return(0);
}
void TeleopTurtle::keyLoop()
{
  char c;
  bool dirty=false;
  puts("Reading from keyboard");
  puts("---------------------------");
  puts("Use arrow keys to move the turtle. 'q' to quit.");
  for(;;)
  {
    // get the next event from the keyboard  
    try
    {
      input.readOne(&c);
    }
    catch (const std::runtime_error &)
    {
      perror("read():");
      return;
    }
    linear_=angular_=0;
    ROS_DEBUG("value: 0x%02X\n", c);
    switch(c)
    {
      case KEYCODE_LEFT:
        ROS_DEBUG("LEFT");
        angular_ = 1.0;
        dirty = true;
        break;
      case KEYCODE_RIGHT:
        ROS_DEBUG("RIGHT");
        angular_ = -1.0;
        dirty = true;
        break;
      case KEYCODE_UP:
        ROS_DEBUG("UP");
        linear_ = 1.0;
        dirty = true;
        break;
      case KEYCODE_DOWN:
        ROS_DEBUG("DOWN");
        linear_ = -1.0;
        dirty = true;
        break;
      case KEYCODE_Q:
        ROS_DEBUG("quit");
        return;
    }
    geometry_msgs::Twist twist;
    twist.angular.z = a_scale_*angular_;
    twist.linear.x = l_scale_*linear_;
    if(dirty ==true)
    {
      twist_pub_.publish(twist);    
      dirty=false;
    }
  }
  return;
}

     代码写的很复杂,主要的思路是获取键盘按下键位,然后发送一次数据给小乌龟节点。

代码编写
    下面参考上述代码,写一个简化版的控制小乌龟节点代码。工程创建可以参考,ROS学习(VSCode实现Hello world),主要步骤如下:

1. 建立工作空间

     将工程建立在桌面“Example”文件夹中,进入在该文件,然后新建“ROS”文件夹和“src”子文件夹,并编译,最后输入“code .”用VSCode打开。

2. 添加Package包与依赖

    设置包名“turtle_teleop”,添加依赖“roscpp rospy std_msgs geometry_msgs turtlesim”

3. 编写代码

     新建文件“turtle_teleop.cpp”,代码如下

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
int main(int argc, char **argv)
{
    ros::init(argc, argv, "velocity_publisher");
    ros::NodeHandle n;
     ros::Publisher turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10);
       ros::Rate loop_rate(10);
    int count = 0;
    while (ros::ok())
    {
          geometry_msgs::Twist vel_msg;
        vel_msg.linear.x = 0.5;
        vel_msg.angular.z = 0.2;
        turtle_vel_pub.publish(vel_msg);
        ROS_INFO("Publsh turtle velocity command[%0.2f m/s, %0.2f rad/s]",
        vel_msg.linear.x, vel_msg.angular.z);
        loop_rate.sleep();
    }
    return 0;
}

     上述代码的核心就是信息的发布,可以参考官网的教程“编写简单的发布者和订阅者(C++)

     之后是配置文件和编译,这里省略。

效果演示

1. 启动内核

    在VSCode界面按下“Ctrl+Shift+P”,输入

ROS:Start

    或者在终端中输入“roscore”也可以启动ros内核。

2. 运行“turtlesim_node”节点

    打开一个新终端,输入,打开小乌龟界面,

rosrun turtlesim turtlesim_node

3. 运行

     在VSCode界面按下“Ctrl+Shift+P”打开命令窗口,输入“ROS:Run a ROS executable”,回车后输入包名“turtle_teleop”回车后输入执行文件名“turtle_teleop_node”,就可以看到代码在控制小乌龟旋转运动。

参考

ROS知识:用你自己的程序控制小乌龟_无水先生的博客-CSDN博客_ros小乌龟

问题

     如何远程控制小乌龟呢?

源码

    GitHub:https://github.com/wanli-car/ROS_Examples

    Gitee:https://gitee.com/wanli-car/ROS_Examples

此帖出自创意市集论坛

最新回复

万里”树莓派小车——ROS学习(C语言编程控制小乌龟) 感谢版主大老的分享!   详情 回复 发表于 2022-11-5 07:33
点赞 关注
个人签名QQ:252669569
 
 

回复
举报

7048

帖子

11

TA的资源

版主

沙发
 

万里”树莓派小车——ROS学习(C语言编程控制小乌龟)

感谢版主大老的分享!

此帖出自创意市集论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表