0x00 往期博文

OriginBot我的第一辆智能小车

使用(PS2)手柄控制OriginBot小车

《HelloOriginBot::使用Python编写Joy手柄功能包》

《深入Originbot:PID人脸追踪》

0x01 实验概述

在前面的实验中我们使用了手柄、PC上位机控制小车,本期我们将用Android上位机来控制OB(OriginBot 下文同理)小车;

0x02 两款开源App

  • ROS-Mobile-Android

          GitHub - ROS-Mobile/ROS-Mobile-Android:适用于Android的可视化和控制应用程序

  • RobotCA

          GitHub - mtbii/RobotCA: No longer actively maintained. Android app for remote controlling a ROS robot - University of South Carolina Capstone Project

          ROS与ROSAPP(Android应用)_ros2 与安卓app交互_姚逸神的博客-CSDN博客

          第一个链接是GitHub上原汁原味的 RobotCA 源程序,第二个链接是CSDN上的大佬修改后的app链接;

0x03 App展示

  • ROS-Mobile-Android

          ROS-Mobile是一款安卓应用程序,专为机器人操作系统(ROS)操作的移动机器人系统的 动态控制 可视化 而设计。

          该应用程序使用 ROS 节点 和 标准 ROS 消息初始化发布者和订阅者。

          整体代码体系结构模式是模型视图视图模型 (MVVM),它可以稳定应用程序并使其高度可自定义。

          ROS-Mobile目前支持以下节点。

    • Debug    调试    (类似于 rostopic echo)

    • Joystick  操纵杆(geometry_msgs/扭转)

    • GridMap 网格图 (nav_msgs/占用网格)

    • Camera  相机    (sensor_msgs/图像,sensor_msgs/压缩图像)

    • GPS       全球定位系统 (sensor_msgs/导航卫星定位)

    • Bitton      按钮    (std_msgs/布尔值)

    • Logger    记录器(std_msgs/字符串)

                     

  • RobotCA

          与 ROS 交互的原生 Andoird 程序

                     

        可选操作杆模式:

       

0x03 Apps 与 OriginBot小车的交互

两款App功能上不分伯仲,但它们都有一个共同点基于ROS1开发。而我们的OB小车基于ROS2开发,我 PC 所安装的ROS版本也是 Foxy。

不兼容啊,这可怎么办呢?

我从胡春旭老师编写的《ROS机器人开发实践》中找到了答案,我们可以在PC开发机上安装ros1 Noetic 和 ros1_bridge功能包来实现App与小车的通信;

通信流程如下:

App 连接到 PC机上的 (roscore) Master,之后手机App的数据通过 ros1_bridge 进行转换再发送给OB小车;

0x04 搭建实验环境

  • 在 PC Foxy 上安装 ROS1 Noetic;

      参考链接:

            ROS2入门教程-在ubuntu20.04源码安装ros2的foxy版本 - 创客智造 (ncnynl.com)

            ROS入门教程-安装并配置ROS环境(Noetic版本) - 创客智造 (ncnynl.com)

             Ubuntu20.04 ROS1和ROS2同时安装及使用 - 古月居 (guyuehome.com)

  • 在 PC Foxy 上编译 ros1_bridge 功能包;

      参考链接:

          ROS2入门教程-源码安装ros1_bridge - 创客智造 (ncnynl.com)

         ChatGPT

0x05 配置实验环境

1\ 在 ~/.bashrc 中添加选择ROS版本的代码:

echo "Select ROS version:"
echo "---------------------"
echo "0: ROS Foxy         |"
echo "1: ROS Noetic       |"
echo "---------------------"
echo "2: ros1_bridge      |"
echo "---------------------"
read -p "Enter your choice: " choice
if [ "$choice" == "0" ]; then
  source /opt/ros/foxy/setup.bash
elif [ "$choice" == "1" ]; then
  source /opt/ros/noetic/setup.bash
elif [ "$choice" == "2" ]; then
  source ~/ros2_bridge_ws/src/install/setup.bash
else
  echo "Invalid choice!"
fi

2\ 添加 Master IP

export ROS_IP=192.168.0.114
export ROS_MASTER_URI=http://localhost:11311

不添加这两句,App连接不上PC;

0x06 添加图像压缩的代码

在古月居官方的代码仓库中,develop分支下新增了图像压缩的代码,我们需要把这段新增的代码添加到我们的工程中;

通过 Vscode 向 OB小车中添加代码:

1\ 在 originbot_bringup/launch/camera.launch.py 中添加 transport_img 节点的代码:

            ],
            arguments=['--ros-args', '--log-level', 'error']
        ),
        Node(
            package='originbot_demo',
            executable='transport_img',
            arguments=['--ros-args', '--log-level', 'error']
        ),
    ])

2\ 新增文件 ../originbot_demo/originbot_demo/transport_img.py

import cv2
import numpy as np
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image, CompressedImage
from cv_bridge import CvBridge


class ImageCompressor(Node):
    def __init__(self):
        super().__init__('image_compressor')
        self.bridge = CvBridge()
        self.image_sub = self.create_subscription(Image, 'image_raw', self.callback, 10)
        self.compressed_pub = self.create_publisher(CompressedImage, 'compressed_image', 10)
        self.bgr8_pub = self.create_publisher(Image, 'bgr8_image', 10)

    def callback(self, msg):
        cv_image = self.bridge.imgmsg_to_cv2(msg, desired_encoding='passthrough')

        encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 50]
        _, compressed = cv2.imencode('.jpg', cv_image, encode_param)

        compressed_msg = CompressedImage()
        compressed_msg.header = msg.header
        compressed_msg.format = 'jpeg'
        compressed_msg.data = np.array(compressed).tostring()

        self.compressed_pub.publish(compressed_msg)
        decompressed = cv2.imdecode(np.frombuffer(compressed_msg.data, np.uint8), cv2.IMREAD_COLOR)
        bgr8_msg = self.bridge.cv2_to_imgmsg(decompressed, encoding='bgr8')
        self.compressed_pub.publish(compressed_msg)
        self.bgr8_pub.publish(bgr8_msg)

def main(args=None):
    rclpy.init(args=args)
    compressor = ImageCompressor()
    rclpy.spin(compressor)
    rclpy.shutdown()


if __name__ == '__main__':
    main()

压缩质量可通过 encode_param 变量中 IMWRITE_JPEG_QUALITY 的数值来修改;

3\ 在 ../originbot_demo/setup.py 文件中添加图像压缩节点;

'transport_img  = originbot_demo.transport_img:main',

4\ 编译新增的代码;

cd ./userdate/dev_ws     # cd 进入工作空间
colcon build --packages-select originbot_demo   # 选择编译
colcon build --packages-select originbot_bringup

0x06 测试App

1\ 启动 roscore 节点;

2\ 手机端输入 pc ip地址;

3\ 添加 weidget 组件;

4\ 修改 weidget 组件 订阅的话题;

这里图像订阅 /compress_image 

遥感发布的速度话题:

5\ 启动小车相机和底盘节点

ros2 launch originbot_bringup camera.launch.py
ros2 launch originbot_bringup originbot.launch.py

5\ 最终效果;