背景:电脑配置不太行,我在ubuntu再运行vmware,里面运行亚博官方的虚拟机镜像ubuntu,系统很卡。基本上8G内存给打满了。还是想把亚博官方的代码迁移出来,之前售后就说除了官方镜像虚拟机,需要自己摸索迁移。
先从键盘控制入手吧。这个模块就是发消息,类似于小海龟那个,比小海龟还要简化下,只是命令多一些,相对独立,依赖少,适合上手练习。
一 准备工作
启动代理:
docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:humble udp4 --port 8090 -v4
可以参考之前的文章:亚博microROS 机器人配置与控制-CSDN博客
小车的配置:要与电脑IP保持一致,不是虚拟机的IP
还要关注一点:检查node
bohu@bohu-TM1701:~$ ros2 node list
/YB_Car_Node
如果没有,请检查确认虚拟机/电脑上.bashrc文件的ROS DOMAIN ID与microROS控制板上配置的一致才可以搜索到节点信息。初次通常需要在.bashrc文件加一行:
export ROS_DOMAIN_ID=20
运行后小车开启电源效果如下:
bohu@bohu-TM1701:~$ docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:humble udp4 --port 8090 -v4
[1737378512.062782] info | UDPv4AgentLinux.cpp | init | running... | port: 8090
[1737378512.063437] info | Root.cpp | set_verbose_level | logger setup | verbose_level: 4
[1737378512.532474] info | Root.cpp | create_client | create | client_key: 0x2BEF9112, session_id: 0x81
[1737378512.532669] info | SessionManager.hpp | establish_session | session established | client_key: 0x2BEF9112, address: 192.168.0.107:39455
[1737378512.677740] info | ProxyClient.cpp | create_participant | participant created | client_key: 0x2BEF9112, participant_id: 0x000(1)
[1737378512.690384] info | ProxyClient.cpp | create_topic | topic created | client_key: 0x2BEF9112, topic_id: 0x000(2), participant_id: 0x000(1)
[1737378512.697153] info | ProxyClient.cpp | create_publisher | publisher created | client_key: 0x2BEF9112, publisher_id: 0x000(3), participant_id: 0x000(1)
[1737378512.705426] info | ProxyClient.cpp | create_datawriter | datawriter created | client_key: 0x2BEF9112, datawriter_id: 0x000(5), publisher_id: 0x000(3)
[1737378512.714186] info | ProxyClient.cpp | create_topic | topic created | client_key: 0x2BEF9112, topic_id: 0x001(2), participant_id: 0x000(1)
[1737378512.725294] info | ProxyClient.cpp | create_publisher | publisher created | client_key: 0x2BEF9112, publisher_id: 0x001(3), participant_id: 0x000(1)
[1737378512.800394] info | ProxyClient.cpp | create_datawriter | datawriter created | client_key: 0x2BEF9112, datawriter_id: 0x001(5), publisher_id: 0x001(3)
[1737378512.813041] info | ProxyClient.cpp | create_topic | topic created | client_key: 0x2BEF9112, topic_id: 0x002(2), participant_id: 0x000(1)
[1737378512.822137] info | ProxyClient.cpp | create_publisher | publisher created | client_key: 0x2BEF9112, publisher_id: 0x002(3), participant_id: 0x000(1)
[1737378512.833437] info | ProxyClient.cpp | create_datawriter | datawriter created | client_key: 0x2BEF9112, datawriter_id: 0x002(5), publisher_id: 0x002(3)
这是前提,否则没法控制小车
二 控制代码
在src/yahboomcar_ctrl/yahboomcar_ctrl/目录下新建文件yahboom_keyboard.py,
代码如下:
#!/usr/bin/env python
# encoding: utf-8
#import public lib
from geometry_msgs.msg import Twist # 消息
import sys, select, termios, tty #tty 设置终端模式。sys 系统模块,select 监听输入,termios 保存和恢复#import ros lib
import rclpy
from rclpy.node import Nodemsg = """
Control Your SLAM-Bot!
---------------------------
Moving around:u i oj k lm , .q/z : increase/decrease max speeds by 10%
w/x : increase/decrease only linear speed by 10%
e/c : increase/decrease only angular speed by 10%
t/T : x and y speed switch
s/S : stop keyboard control
space key, k : force stop
anything else : stop smoothlyCTRL-C to quit
"""moveBindings = {'i': (1, 0),'o': (1, -1),'j': (0, 1),'l': (0, -1),'u': (1, 1),',': (-1, 0),'.': (-1, 1),'m': (-1, -1),'I': (1, 0),'O': (1, -1),'J': (0, 1),'L': (0, -1),'U': (1, 1),'M': (-1, -1),
}speedBindings = {'Q': (1.1, 1.1),'Z': (.9, .9),'W': (1.1, 1),'X': (.9, 1),'E': (1, 1.1),'C': (1, .9),'q': (1.1, 1.1),'z': (.9, .9),'w': (1.1, 1),'x': (.9, 1),'e': (1, 1.1),'c': (1, .9),
}class Yahboom_Keybord(Node):def __init__(self,name):#初始化super().__init__(name)self.pub = self.create_publisher(Twist,'cmd_vel',1000)self.declare_parameter("linear_speed_limit",1.0) #声明参数-线速度self.declare_parameter("angular_speed_limit",5.0) #声明参数-角速度self.linenar_speed_limit = self.get_parameter("linear_speed_limit").get_parameter_value().double_valueself.angular_speed_limit = self.get_parameter("angular_speed_limit").get_parameter_value().double_valueself.settings = termios.tcgetattr(sys.stdin)def getKey(self):#读取键盘tty.setraw(sys.stdin.fileno())#原始模式,不用回车读取rlist, _, _ = select.select([sys.stdin], [], [], 0.1)# 监听输入,超时时间0.1秒if rlist: key = sys.stdin.read(1) #读取输入else: key = '' #没有输入设置为空串termios.tcsetattr(sys.stdin, termios.TCSADRAIN, self.settings) #恢复终端属性return keydef vels(self, speed, turn):#输出速度和朝向return "currently:\tspeed %s\tturn %s " % (speed,turn) def main():rclpy.init()yahboom_keyboard = Yahboom_Keybord("yahboom_keyboard_ctrl")xspeed_switch = True(speed, turn) = (0.2, 1.0)(x, th) = (0, 0)status = 0stop = Falsecount = 0twist = Twist()try:print(msg)print(yahboom_keyboard.vels(speed, turn))while (1):key = yahboom_keyboard.getKey()if key=="t" or key == "T": xspeed_switch = not xspeed_switchelif key == "s" or key == "S":print ("stop keyboard control: {}".format(not stop))stop = not stopif key in moveBindings.keys(): #方向控制x = moveBindings[key][0]th = moveBindings[key][1]count = 0 elif key in speedBindings.keys(): #加速speed = speed * speedBindings[key][0]turn = turn * speedBindings[key][1]count = 0if speed > yahboom_keyboard.linenar_speed_limit: speed = yahboom_keyboard.linenar_speed_limitprint("Linear speed limit reached!")if turn > yahboom_keyboard.angular_speed_limit: turn = yahboom_keyboard.angular_speed_limitprint("Angular speed limit reached!")print(yahboom_keyboard.vels(speed, turn))if (status == 14): print(msg)status = (status + 1) % 15elif key == ' ': (x, th) = (0, 0)else:count = count + 1if count > 4: (x, th) = (0, 0)if (key == '\x03'): breakif xspeed_switch: twist.linear.x = speed * xelse: twist.linear.y = speed * xtwist.angular.z = turn * thif not stop: yahboom_keyboard.pub.publish(twist) #发话题消息if stop:yahboom_keyboard.pub.publish(Twist())except Exception as e: print(e)finally: yahboom_keyboard.pub.publish(Twist())termios.tcsetattr(sys.stdin, termios.TCSADRAIN, yahboom_keyboard.settings) #恢复终端属性yahboom_keyboard.destroy_node()rclpy.shutdown()
代码我加了注释,从依赖上看,就是依赖了ros2基础的话题消息,剩下就是读取键盘的getKey()。
退出标识:\x03 就是ctrl+C 组合。
处理逻辑就是根据根据键盘输入调用话题发布。
三 测试:
重新构建下,再次运行节点
ros2 run yahboomcar_ctrl yahboom_keyboard
补充下相关信息
rqt看node:
bohu@bohu-TM1701:~$ ros2 node info /YB_Car_Node
/YB_Car_NodeSubscribers:/beep: std_msgs/msg/UInt16/cmd_vel: geometry_msgs/msg/Twist/servo_s1: std_msgs/msg/Int32/servo_s2: std_msgs/msg/Int32Publishers:/battery: std_msgs/msg/UInt16/imu: sensor_msgs/msg/Imu/odom_raw: nav_msgs/msg/Odometry/scan: sensor_msgs/msg/LaserScanService Servers:Service Clients:Action Servers:Action Clients:
从节点信息来看,/YB_Car_Node
订阅了话题:包含刚才的cmd_vel,用于接受指令。消息接口:
geometry_msgs/msg/Twist
发布的话题:battery 电池、imu 惯性测量数据,odom:里程计数据、scan:激光雷达的数据。
控制话题具体信息
---
linear:
x: 0.26620000000000005
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0
---
真的很感谢之前小鱼老师那本《ros2机器人开发》那本书,要是没有这本书作为入门指导,直接看亚博的源码会很吃力。这是第一步,期待后面能逐步学习完亚博的完整功能,把小车玩起来。