赞
踩
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 base
。if [ -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
安装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
为了说明问题,我们使用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,则需要参考另一篇文章的配置
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。