自动驾驶系列(十)编写电动车ROS节点(刹车)

一、硬件控制协议

       对于不同的设备,底层的通讯方式都不一致,因此需要根据具体硬件具体分析。本系统 采用了1个CAN盒子控制转向,1路DA控制油门,另外一路DA控制刹车。

1,转向协议

      CAN协议获取当前状态的帧ID是0x322,发送控制指令的ID是0x215。500kbps。

     一条十六进制控制码是 00 31 X1 X2 Y1 00 00 00。

     其中X1*256+X2=控制角度 Y1控制角速度。

2,油门协议

      串口转DA控制模块,设置波特率9600bps。

      一条十六进制控制码是 01 06 00 00 X1 X2 Y1 Y2。

     其中,X1*256+X2控制DA输出电压。空载测试大约 5km/h对应 01 99,10km/h对应 03 33。

     Y1和Y2分别是对前八位数据进行CRC校验后的输出结果。

3,刹车协议

     串口转DA控制模块,设置波特率9600bps。

     启动刹车:01 06 00 00 0c cd 4d 5f。

     取消刹车:01 06 00 00 00 00 89 ca。

二、ROS节点接收速度控制消息

     对于ROS节点的编写规则,可以参考本系列第二讲中推荐的ros基本教程。

    首先创建功能包,实现监听cmd_vel消息,命名为bjtucar:

cd ~/catkin_ws/src
catkin_create_pkg bjtucar std_msgs std_msgs roscpp

 创建节点订阅文件myCar.cpp

cd ~/catkin_ws/src/bjtucar/src/
gedit myCar.cpp

在文件中粘贴以下内容:

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
void cmd_vel_callback(const geometry_msgs::Twist& vel_cmd)
{
    ROS_INFO("I heard: [%f]", vel_cmd.linear.y);
     ROS_INFO("I heard: [%f]", vel_cmd.linear.x);
    std::cout << "Twist Received " << std::endl;
}
int main( int argc, char* argv[] )
{
    ros::init(argc, argv, "myCar" );
    ros::NodeHandle n;
    ros::Subscriber sub = n.subscribe("/turtle1/cmd_vel", 1000, cmd_vel_callback);
    while( n.ok() )
    {
        ros::spin();
    }
    return 1;
}

在CMakeList.txt文件最后增加代码:

add_executable(bjtucar ./src/myCar.cpp)
target_link_libraries(bjtucar ${catkin_LIBRARIES})

重新编译

cd ~/catkin_ws
catkin_make

测试:打开4个终端,分别运行以下节点

启动内核:   roscore

启动仿真乌龟节点: rosrun turtlesim turtlesim_node

启动键盘控制节点: rosrun turtlesim turtle_teleop_key

启动myCar节点: rosrun bjtucar bjtucar

可以通过输入方向键,发送cmd_vel消息,myCar节点监听该消息后打印出来。

 新终端,rqt_graph查看当前节点状态

 三、ROS节点控制刹车

控制油门和刹车,都需要添加串口节点,我们先假设配置油门是串口1,刹车是串口2。首先按照一个串口添加。

3.1添加串口功能

查看串口设备,修改串口名称:ls /dev/tty*。  一般是ttyACM0 或者 ttyUSB0。

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>

#include <serial/serial.h>
serial::Serial ser; //声明串口对象 1
void cmd_vel_callback(const geometry_msgs::Twist& vel_cmd)
{
    ROS_INFO("I heard: [%f]", vel_cmd.linear.y);
     ROS_INFO("I heard: [%f]", vel_cmd.linear.x);
    std::cout << "Twist Received " << std::endl;
}
int main( int argc, char* argv[] )
{
    ros::init(argc,argv,"serial_port");
    //设置串口属性,并打开串口
    ser.setPort("/dev/ttyACM0");
    ser.setBaudrate(9600);
    serial::Timeout to = serial::Timeout::simpleTimeout(100);
    ser.setTimeout(to);
    try
    {
        ser.open();
    }
    catch (serial::IOException& e)
    {
        ROS_ERROR_STREAM("Unable to open port ");
        return -1;
    }
    //检测串口是否已经打开,并给出提示信息
    if(ser.isOpen())
    {
        ROS_INFO_STREAM("Serial Port initialized");
    }
    else
    {
        return -1;
    }

    ros::init(argc, argv, "myCar" );
    ros::NodeHandle n;
    ros::Subscriber sub = n.subscribe("/turtle1/cmd_vel", 1000, cmd_vel_callback);
    while( n.ok() )
    {
        ros::spin();
    }
    return 1;
}

修改CMakeList.txt文件,添加了serial的包依赖。

cmake_minimum_required(VERSION 3.0.2)
project(bjtucar)

find_package(catkin REQUIRED COMPONENTS
  serial
  roscpp
  std_msgs
  std_msgs
)

catkin_package(
)


include_directories(
# include
  ${catkin_INCLUDE_DIRS}
)

add_executable(bjtucar ./src/myCar.cpp)
target_link_libraries(bjtucar ${catkin_LIBRARIES})

安装serial包,再次编译通过。

sudo apt-get install ros-melodic-serial
cd ~/catkin
catkin_make

启动内核节点:roscore

启动myCar节点: rosrun bjtucar bjtucar

修改USB权限: sudo chmod 666 /dev/ttyUSB0
再次运行,成功。

 3.2串口调试工具cutecom

 (1)终端下载命令:sudo apt-get install cutecom 

 (2)通过终端打开软件:sudo cutecom (需要root权限,否则无法打开串口)

 3.3输出控制指令

当键盘按下”↑“时,刹车踏板松开。当键盘按下”↓“时,刹车踩下。

修改myCar.cpp文件内容如下:

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>

#include <serial/serial.h>
serial::Serial ser; //声明串口对象 1

//static unsigned char doBrake[8];	//分配静态存储空间
unsigned char doBrake[8]={0x01, 0x06, 0x00, 0x00, 0x0c, 0xcd, 0x4d, 0x5f};
unsigned char noBrake[8]={0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0xca};

//int doBrake[8]={1, 6, 0, 0, 12, 205, 77, 95};
//int noBrake[8]={1, 6, 0, 0, 0, 0, 137, 202};
void cmd_vel_callback(const geometry_msgs::Twist& vel_cmd)
{
    ROS_INFO("I heard: [%f]", vel_cmd.linear.y);
     ROS_INFO("I heard: [%f]", vel_cmd.linear.x);
    std::cout << "Twist Received " << std::endl;

    if(vel_cmd.linear.x>0)
        ser.write(noBrake,8);
    else if(vel_cmd.linear.x<0)
        ser.write(doBrake,8);
    else;
}
int main( int argc, char* argv[] )
{
    ros::init(argc,argv,"serial_port");
    //设置串口属性,并打开串口
    ser.setPort("/dev/ttyUSB0");
    ser.setBaudrate(9600);
    serial::Timeout to = serial::Timeout::simpleTimeout(100);
    ser.setTimeout(to);
    try
    {
        ser.open();
    }
    catch (serial::IOException& e)
    {
        ROS_ERROR_STREAM("Unable to open port ");
        return -1;
    }
    //检测串口是否已经打开,并给出提示信息
    if(ser.isOpen())
    {
        ROS_INFO_STREAM("Serial Port initialized");
    }
    else
    {
        return -1;
    }

    ros::init(argc, argv, "myCar" );
    ros::NodeHandle n;
    ros::Subscriber sub = n.subscribe("/turtle1/cmd_vel", 1000, cmd_vel_callback);
    while( n.ok() )
    {
        ros::spin();
    }
    return 1;
}

重新编译

cd ~/catkin
catkin_make

测试:

1,用两个串口模块连接到电脑端。并查看串口号。ttyUSB0的输出用导线连接到ttyUSB1的输入。

 2,打开串口调试工具,监控串口ttyUSB1。

sudo cutecom

 3,依次启动节点

启动内核:   roscore

启动键盘控制节点: rosrun turtlesim turtle_teleop_key

启动myCar节点: rosrun bjtucar bjtucar

 

 在键盘输入的终端,分别输入方向按键,可以监控到串口出不同的刹车指令。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单的ROS小车自动规划路径的编写程序示例,供参考: 1. 创建地图 首先需要使用SLAM技术创建地图,可以使用ROS中的gmapping包进行地图创建。在终端中运行以下命令: ``` roslaunch turtlebot_gazebo turtlebot_world.launch roslaunch turtlebot_gazebo gmapping_demo.launch ``` 这会启动Gazebo仿真器和gmapping包,开始创建地图。在地图被创建完成后,使用以下命令将地图保存到本地: ``` rosrun map_server map_saver -f /tmp/my_map ``` 2. 编写路径规划程序 在终端中运行以下命令,启动move_base节点: ``` roslaunch turtlebot_navigation amcl_demo.launch map_file:=/tmp/my_map.yaml ``` 这会启动AMCL(Adaptive Monte Carlo Localization)算法和move_base节点,开始路径规划。在路径规划过程中,move_base节点会发布一些ROS话题,包括move_base_simple/goal(目标点)、move_base/feedback(反馈信息)和move_base/result(任务结果)等。 创建一个ROS节点,订阅move_base_simple/goal话题,向该话题发布目标点,即可启动路径规划。在路径规划完成后,ROS小车会自动移动到目标点。 示例代码如下: ```python #!/usr/bin/env python import rospy from geometry_msgs.msg import PoseStamped class PathPlanner: def __init__(self): self.pub_goal = rospy.Publisher('/move_base_simple/goal', PoseStamped, queue_size=10) self.goal = PoseStamped() def send_goal(self): self.goal.header.frame_id = "map" self.goal.header.stamp = rospy.Time.now() self.goal.pose.position.x = 1.0 self.goal.pose.position.y = 1.0 self.goal.pose.orientation.w = 1.0 self.pub_goal.publish(self.goal) if __name__ == '__main__': rospy.init_node('path_planner') path_planner = PathPlanner() path_planner.send_goal() rospy.spin() ``` 3. 编写控制程序 在ROS中,控制小车运动通常使用ROS控制器(ROS Control)框架。ROS控制器是一种通用的机器人控制框架,提供了基于PID控制器的控制接口,可以方便地控制机器人的运动。 创建一个ROS控制器,订阅move_base/feedback话题,获取ROS小车的当前位置和姿态信息,然后根据路径规划结果计算出控制指令,使用控制器将小车移动到目标位置。在控制过程中,可以使用ROS中的ROS MoveIt!库来实现路径规划和控制。 示例代码如下: ```python #!/usr/bin/env python import rospy import actionlib from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal from geometry_msgs.msg import PoseStamped, Twist class PathController: def __init__(self): self.sub_feedback = rospy.Subscriber('/move_base/feedback', MoveBaseActionFeedback, self.feedback_cb) self.pub_cmd_vel = rospy.Publisher('/cmd_vel', Twist, queue_size=10) self.current_pose = None self.goal_pose = None self.result = None def feedback_cb(self, feedback): self.current_pose = feedback.feedback.base_position.pose def move_to_goal(self, goal): client = actionlib.SimpleActionClient('move_base', MoveBaseAction) client.wait_for_server() mb_goal = MoveBaseGoal() mb_goal.target_pose = goal client.send_goal(mb_goal) while not rospy.is_shutdown(): if client.get_state() == GoalStatus.SUCCEEDED: self.result = True break if self.current_pose is not None: # 计算控制指令 twist = Twist() twist.linear.x = 0.2 twist.angular.z = 0.5 self.pub_cmd_vel.publish(twist) return self.result if __name__ == '__main__': rospy.init_node('path_controller') path_controller = PathController() # 设置目标点 goal = PoseStamped() goal.header.frame_id = 'map' goal.header.stamp = rospy.Time.now() goal.pose.position.x = 1.0 goal.pose.position.y = 1.0 goal.pose.orientation.w = 1.0 # 调用控制函数 path_controller.move_to_goal(goal) rospy.spin() ``` 以上是一个简单的ROS小车自动规划路径的编写程序示例,供参考。由于ROS系统非常灵活,实际的程序实现可能会因具体应用场景和硬件设备的不同而有所差异。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值