ROS与Python3

举报
Hermit_Rabbit 发表于 2022/07/26 15:23:36 2022/07/26
【摘要】 一、Anaconda与Virtualenv 虚拟环境Anaconda与Virtualenv可以二选一 1.1 AnacondaTip:ros 和Anaconda 一起使用的时候,如果先安装了Anaconda,再安装ros,会报错,因此正确的联合使用方式为:先安装ros相关,后安装anaconda即可。Anaconda安装完成后会在~/.bashrc中写入如下命令:# >>> conda i...

一、Anaconda与Virtualenv

虚拟环境Anaconda与Virtualenv可以二选一

1.1 Anaconda

Tip:ros 和Anaconda 一起使用的时候,如果先安装了Anaconda,再安装ros,会报错,因此正确的联合使用方式为:先安装ros相关,后安装anaconda即可。
Anaconda安装完成后会在~/.bashrc中写入如下命令:

# >>> conda initialize >>>
# !! Contents within this block are managed by ‘conda init‘ !!
__conda_setup="$(‘/home/“user”/anaconda3/bin/conda‘ ‘shell.bash‘ ‘hook‘ 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/home/"user"/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/home/"user"/anaconda3/etc/profile.d/conda.sh"
    else
        export PATH="/home/"user"/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

在这里插入图片描述

脚本命令解析:

$ if [ $? -eq 0 ]; then echo "true"; else echo "false"; fi;
#这条命令的意思是:如果上一条命令执行成功则打印true,否则打印false
#对于上述~/.bashrc中的命令,通常的结果是执行eval "$__conda_setup"
#除非__conda_setup="$('/home/jay/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"这一句出现了错误

可以通过在终端运行$ echo "$('/home/jay/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"命令来查看eval "$__conda_setup"都干了哪些事。你也可以运行$ cat /home/jay/anaconda3/etc/profile.d/conda.sh看一下这个脚本里的内容,没错,二者做了相同的工作,只不过前者比后者多执行了一步conda activate baseif [ -f "/home/jay/anaconda3/etc/profile.d/conda.sh" ];的意思是判断这个脚本文件是否存在且没有被损坏,通常这个条件也是满足的。

博主想要表达的意思是,只有当前两个条件都不满足时才会执行export PATH="/home/jay/anaconda3/bin:$PATH",可见这个操作并不是上上之选。然而很多人在装完Anaconda后会直接将anaconda的bin目录加入环境变量,鄙人认为这是不科学的,且事实证明这样做会经常带来一些问题,因为它干扰了系统原生的环境。

按照Anaconda默认的配置,打开一个新的终端会自动进入Anaconda的环境:
在这里插入图片描述
如果不想直接进入Anaconda的环境,博主的做法是在~/.bashrc中添加一句conda deactivate,这样打开一个新的终端就是系统原始的Python环境:
在这里插入图片描述
要再进入Anaconda环境就运行$ conda activate
在这里插入图片描述
上图对比了进入anaconda环境与退出anaconda环境后,系统环境变量发生的变化。显然,在进入anaconda环境后,PATH中多了/home/jay/anaconda3/bin,而退出anaconda环境后/home/jay/anaconda3/bin又消失了,博主认为这才是使用Anaconda的正确姿势。

利用Anaconda创建自己的虚拟环境:

$ conda create -n py3.7 python=3.7
$ conda activate py3.7

在这里插入图片描述

1.2 Virtualenv

安装Virtualenv:

$ sudo pip install virtualenv

创建虚拟Python环境:

$ whereis python2
$ whereis python3
$ mkdir ~/virtualenv
$ virtualenv -p /usr/bin/python3.5 ~/virtualenv/py3.5
$ source ~/virtualenv/py3.5/bin/activate

在这里插入图片描述
可以在虚拟环境中装个TensorFlow玩一下:

$ pip install tensorflow -i https://pypi.tuna.tsinghua.edu.cn/simple

二、在Python3环境下编译ROS包

为了说明问题,我们使用OpenCV在两个虚拟环境中折腾一下:用Anaconda创建的py3.7编写一个OpenCV的Python节点来发布图像话题,然后编写一个C++节点用来订阅图像话题并显示,在Virtualenv创建的py3.5环境下进行编译。具体步骤如下:

首先创建一个ROS工作空间并新建一个ROS包:

$ mkdir -p ~/ros_ws/src
$ cd ~/ros_ws/src
$ catkin_init_workspace
$ catkin_create_pkg cv_package roscpp cv_bridge OpenCV
$ cd cv_package/src
$ touch pub_image.py sub_image.cpp

然后在pub_image.py中粘贴以下内容:

#!/home/jay/anaconda3/envs/py3.7/bin/python
#-*-coding:utf-8-*-
#注意这里import的顺序
import numpy
import rospy
from sensor_msgs.msg import Image
import sys
sys.path.remove('/opt/ros/kinetic/lib/python2.7/dist-packages')
import cv2


def shutdown():
    print("shut down!")


def publisher():
    rospy.init_node("image_publisher", anonymous=True)
    if len(sys.argv)<2:
        rospy.loginfo("There should be a parameter follow the %s, such as 0 or 1.", sys.argv[0])
        rospy.on_shutdown(shutdown)
        return
    capture=cv2.VideoCapture(int(sys.argv[1]))
    imgPub=rospy.Publisher('/camera/image_raw',Image,queue_size=1)
    rospy.loginfo("I am publishing an image...")
    rate = rospy.Rate(30)
    
    while not rospy.is_shutdown():
        ref,frame=capture.read()
        image=Image()
        image.encoding='bgr8'
        image.height=frame.shape[0]
        image.width=frame.shape[1]
        image.step=frame.shape[1]*frame.shape[2]
        image.data=numpy.array(frame).tostring()
        image.header.stamp=rospy.Time.now()
        imgPub.publish(image)
        rate.sleep()


if __name__ == '__main__':
    try:
        publisher()
    except rospy.ROSInterruptException:
        pass

在sub_image.cpp中粘贴以下内容:

#include <ros/ros.h>
#include <cv_bridge/cv_bridge.h>
#include <opencv2/highgui/highgui.hpp>

void subscriber(const sensor_msgs::ImageConstPtr& msg)
{
    cv::Mat img;
    cv_bridge::CvImageConstPtr cv_ptr;
    try
    {
        cv_ptr = cv_bridge::toCvShare(msg);
    }
    catch (cv_bridge::Exception& e)
    {
        ROS_ERROR("cv_bridge exception: %s", e.what());
        return;
    }
    cv_ptr->image.copyTo(img);
    cv::imshow("image",img);
    if(27==cv::waitKey(10))ros::shutdown();
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "image_subscriber");
    ros::NodeHandle nh;
    if(!nh.ok())return 0;
    ros::Subscriber imgSub = nh.subscribe("camera/image_raw", 10, subscriber);
    ROS_INFO("I am subscribing an image...");
    while (ros::ok())ros::spin();
    cv::destroyAllWindows();
    return 0;
}

再修改一下CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.3)
project(cv_package)

## Compile as C++11, supported in ROS Kinetic and newer
add_compile_options(-std=c++11)

set(OpenCV_DIR /opt/ros/kinetic/share/OpenCV-3.3.1-dev/)
find_package(catkin REQUIRED COMPONENTS
  OpenCV
  cv_bridge
  roscpp
)

catkin_package(
)

include_directories(
  ${catkin_INCLUDE_DIRS}
)

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

最后在py3.5环境中进行编译(编译本身和Python3.5并没有关系,这里只是用到了它的环境)

$ source ~/virtualenv/py3.5/bin/activate
$ cd ~/ros_ws
$ catkin_make  #不出意外的话这一步会报错,然后按照以下步骤进行编译
$ pip install catkin_pkg pyyaml empy rospkg numpy
$ rm -rf build
$ catkin_make
$ chmod +x src/cv_package/src/pub_image.py
$ echo "source ~/ros_ws/devel/setup.bash" >> ~/.bashrc

先运行$ roscore,再运行pub_image和sub_image这两个节点:

# 运行pub_image.py之前,要先在py3.7环境下安装一些依赖
$ conda activate py3.7
$ pip install numpy pyyaml rospkg opencv_python -i https://pypi.tuna.tsinghua.edu.cn/simple
$ conda deactivate  #这一步也可以不执行
$ rosrun cv_package pub_image.py 0
# 打开一个新的终端
$ rosrun cv_package sub_image

三、解决相关的疑难杂症
opencv常见症状如下:

/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFReadRGBAStrip@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFReadDirectory@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFWriteEncodedStrip@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFIsTiled@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFWriteScanline@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFGetField@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFNumberOfStrips@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFScanlineSize@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFReadEncodedTile@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFReadRGBATile@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFClose@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFClientOpen@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFRGBAImageOK@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFOpen@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFReadEncodedStrip@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFSetField@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFSetWarningHandler@LIBTIFF_4.0’未定义的引用
/opt/ros/kinetic/lib/x86_64-linux-gnu/libopencv_imgcodecs3.so.3.3.1:对‘TIFFSetErrorHandler@LIBTIFF_4.0’未定义的引用

解决办法:修改CMakeLists.txt,在target_link_libraries中添加/usr/lib/x86_64-linux-gnu/libtiff.so,如下:

add_executable(${PROJECT_NAME}_node src/main.cpp)
target_link_libraries(${PROJECT_NAME}_node 
  ${catkin_LIBRARIES} 
  /usr/lib/x86_64-linux-gnu/libtiff.so
)

安装python3环境中的问题参考链接https://blog.csdn.net/weixin_44088559/article/details/105116697

tip:如果要使用cv_bridge,则需要参考另一篇文章的配置

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。