背景:电脑配置不太行,我在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
bash
bohu@bohu-TM1701:~$ ros2 node list
/YB_Car_Node
如果没有,请检查确认虚拟机/电脑上.bashrc文件的ROS DOMAIN ID与microROS控制板上配置的一致才可以搜索到节点信息。初次通常需要在.bashrc文件加一行:
export ROS_DOMAIN_ID=20
运行后小车开启电源效果如下:
bash
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,
代码如下:
python
#!/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 Node
msg = """
Control Your SLAM-Bot!
---------------------------
Moving around:
u i o
j k l
m , .
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 smoothly
CTRL-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_value
self.angular_speed_limit = self.get_parameter("angular_speed_limit").get_parameter_value().double_value
self.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 key
def 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 = 0
stop = False
count = 0
twist = 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_switch
elif key == "s" or key == "S":
print ("stop keyboard control: {}".format(not stop))
stop = not stop
if 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 = 0
if speed > yahboom_keyboard.linenar_speed_limit:
speed = yahboom_keyboard.linenar_speed_limit
print("Linear speed limit reached!")
if turn > yahboom_keyboard.angular_speed_limit:
turn = yahboom_keyboard.angular_speed_limit
print("Angular speed limit reached!")
print(yahboom_keyboard.vels(speed, turn))
if (status == 14): print(msg)
status = (status + 1) % 15
elif key == ' ': (x, th) = (0, 0)
else:
count = count + 1
if count > 4: (x, th) = (0, 0)
if (key == '\x03'): break
if xspeed_switch: twist.linear.x = speed * x
else: twist.linear.y = speed * x
twist.angular.z = turn * th
if 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:
bash
bohu@bohu-TM1701:~$ ros2 node info /YB_Car_Node
/YB_Car_Node
Subscribers:
/beep: std_msgs/msg/UInt16
/cmd_vel: geometry_msgs/msg/Twist
/servo_s1: std_msgs/msg/Int32
/servo_s2: std_msgs/msg/Int32
Publishers:
/battery: std_msgs/msg/UInt16
/imu: sensor_msgs/msg/Imu
/odom_raw: nav_msgs/msg/Odometry
/scan: sensor_msgs/msg/LaserScan
Service 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机器人开发》那本书,要是没有这本书作为入门指导,直接看亚博的源码会很吃力。这是第一步,期待后面能逐步学习完亚博的完整功能,把小车玩起来。