当前位置: 首页 > news >正文

在已安装二进制movit2的情况下使用自编译moveit2

  • 在已安装二进制movit2的情况下,想使用自编译moveit2,只要引入一下自编译moveit2库的环境变量即可。主要是想搞明白这个过程发生了什么,也就是引入环境后有什么变化,以及如何对编译过程产生影响

一、setup.bash流程

  • 所有资料上都说setup.bash作用就是添加环境,其实就是将对应的地址添加到不同的环境变量当中了,这里主要想分析一下这个过程是如何实现的
  • 主要 关注的环境变量是LD_LIBRARY_PATH、CMAKE_PREFIX_PATH、AMENT_PREFIX_PATH

1、运行source ./install/setup.bash效果

==========运行source ./install/setup.bash前==========
~/ws_moveit2$ echo $LD_LIBRARY_PATH
/usr/local/etherlab/lib:/opt/ros/humble/opt/rviz_ogre_vendor/lib:/opt/ros/humble/lib/x86_64-linux-gnu:/opt/ros/humble/lib

~/ws_moveit2$ echo $CMAKE_PREFIX_PATH

~/ws_moveit2$ echo $AMENT_PREFIX_PATH
/opt/ros/humble

  • 运行后自己包中的所有lib文件就添加到LD_LIBRARY_PATH变量中,类似~/ws_moveit2/install/moveit_ros_planning_interface/lib的地址
  • CMAKE_PREFIX_PATH和AMENT_PREFIX_PATH变量添加了很多类似~/ws_moveit2/install/moveit_ros_planning_interface的地址

2、./install/setup.bash文件分析

  • 文件中用的是shell语言,跟命令行中用的一样。不过两个语法略有不同,属于不同的shell类型,大部分差不多

(1)定义_colcon_prefix_chain_bash_source_script()函数

_colcon_prefix_chain_bash_source_script() {
  if [ -f "$1" ]; then
    if [ -n "$COLCON_TRACE" ]; then
      echo "# . \"$1\""
    fi
    . "$1"  
  else
    echo "not found: \"$1\"" 1>&2
  fi
}

(2)加载基础ros环境

COLCON_CURRENT_PREFIX="/opt/ros/humble"  #系统中ros的安装位置
_colcon_prefix_chain_bash_source_script "$COLCON_CURRENT_PREFIX/local_setup.bash" #运行对应的bash文件
  • 每个工作空间都默认加载了基础的环境变量

(3)加载当前工作空间的环境

COLCON_CURRENT_PREFIX="$(builtin cd "`dirname "${BASH_SOURCE[0]}"`" > /dev/null && pwd)"
_colcon_prefix_chain_bash_source_script "$COLCON_CURRENT_PREFIX/local_setup.bash"
  • 这里比较复杂的就是第一行,测试一下就可以那段命令就是运行
builtin cd "`dirname "${BASH_SOURCE[0]}"`" > /dev/null && pwd

结果就是返回了当前路径

~/ws_moveit2/install
  • 具体语法解读
    builtin cd : 使用内置命令cd
    ${BASH_SOURCE[0]} : 这个变量显示此脚本的位置包括文件名
    dirname : 取出地址,即取出文件名
    ‘ ’ : 先执行反引号内部的命令
    /dev/null : 把输出放入黑洞设备,也就是不输出
    上面命令一起就是cd到当前,然后再用pwd输出即可传递给COLCON_CURRENT_PREFIX

(4)删除定义的变量和函数

unset COLCON_CURRENT_PREFIX
unset _colcon_prefix_chain_bash_source_script
  • 删除定义的变量和函数

3、./install/local_setup.bash文件分析

(1)添加地址到环境变量

_colcon_prefix_bash_prepend_unique_value() {
  # arguments
  _listname="$1"
  _value="$2"

  # get values from variable
  eval _values=\"\$$_listname\"
  # backup the field separator
  _colcon_prefix_bash_prepend_unique_value_IFS="$IFS"
  IFS=":"
  # start with the new value
  _all_values="$_value"
  _contained_value=""
  # iterate over existing values in the variable
  for _item in $_values; do
    # ignore empty strings
    if [ -z "$_item" ]; then
      continue
    fi
    # ignore duplicates of _value
    if [ "$_item" = "$_value" ]; then
      _contained_value=1
      continue
    fi
    # keep non-duplicate values
    _all_values="$_all_values:$_item"
  done
  unset _item
  if [ -z "$_contained_value" ]; then
    if [ -n "$COLCON_TRACE" ]; then
      if [ "$_all_values" = "$_value" ]; then
        echo "export $_listname=$_value"
      else
        echo "export $_listname=$_value:\$$_listname"
      fi
    fi
  fi
  unset _contained_value
  # restore the field separator
  IFS="$_colcon_prefix_bash_prepend_unique_value_IFS"
  unset _colcon_prefix_bash_prepend_unique_value_IFS
  # export the updated variable
  eval export $_listname=\"$_all_values\"
  unset _all_values
  unset _values

  unset _value
  unset _listname
}

(2)添加前缀地址到COLCON_PREFIX_PATH

_colcon_prefix_bash_prepend_unique_value COLCON_PREFIX_PATH "$_colcon_prefix_bash_COLCON_CURRENT_PREFIX"
unset _colcon_prefix_bash_prepend_unique_value

(3)检查python环境变量

if [ -n "$COLCON_PYTHON_EXECUTABLE" ]; then
  if [ ! -f "$COLCON_PYTHON_EXECUTABLE" ]; then
    echo "error: COLCON_PYTHON_EXECUTABLE '$COLCON_PYTHON_EXECUTABLE' doesn't exist"
    return 1
  fi
  _colcon_python_executable="$COLCON_PYTHON_EXECUTABLE"
else
  # try the Python executable known at configure time
  _colcon_python_executable="/usr/bin/python3"
  # if it doesn't exist try a fall back
  if [ ! -f "$_colcon_python_executable" ]; then
    if ! /usr/bin/env python3 --version > /dev/null 2> /dev/null; then
      echo "error: unable to find python3 executable"
      return 1
    fi
    _colcon_python_executable=`/usr/bin/env python3 -c "import sys; print(sys.executable)"`
  fi
fi

(4)加载另外的bash脚本,并根据COLCON_TRACE决定是否输出调试信息

  • 下面这个代码不是原版,有一些调试信息
echo "==========================="
echo "2"
echo $1
echo "3"
echo $COLCON_TRACE
_colcon_prefix_sh_source_script() {
  if [ -f "$1" ]; then
    if [ -n "$COLCON_TRACE" ]; then
      echo "# . \"$1\""
    fi
      echo "source \"$1\""
    . "$1"
  else
    echo "not found: \"$1\"" 1>&2
  fi
}

echo "===========================1"
echo "${_colcon_ordered_commands}"
# get all commands in topological order
_colcon_ordered_commands="$($_colcon_python_executable "$_colcon_prefix_bash_COLCON_CURRENT_PREFIX/_local_setup_util_sh.py" sh bash)"

echo "===========================1.5"
echo "${_colcon_ordered_commands}"

unset _colcon_python_executable
if [ -n "$COLCON_TRACE" ]; then
  echo "$(declare -f _colcon_prefix_sh_source_script)"
  echo "# Execute generated script:"
  echo "# <<<"
  echo "${_colcon_ordered_commands}"
  echo "# >>>"
  echo "unset _colcon_prefix_sh_source_script"
fi
echo "===========================2"
echo $AMENT_PREFIX_PATH
echo "===========================3"
echo "${_colcon_ordered_commands}"
eval "${_colcon_ordered_commands}"
unset _colcon_ordered_commands

unset _colcon_prefix_sh_source_script

unset _colcon_prefix_bash_COLCON_CURRENT_PREFIX
echo "==========================="
echo $AMENT_PREFIX_PATH
  • 下面这行运行了_local_setup_util_sh.py文件,生成了添加地址到指定环境变量的命令将其存到_colcon_ordered_commands
_colcon_ordered_commands="$($_colcon_python_executable "$_colcon_prefix_bash_COLCON_CURRENT_PREFIX/_local_setup_util_sh.py" sh bash)"
  • 下面这步则是直接执行_colcon_ordered_commands
eval "${_colcon_ordered_commands}"

二、find_package流程

相关资料:

  • https://blog.csdn.net/weixin_41652700/article/details/128914776?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522a7d6f436d89e18bbe78a29bb97f8df50%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=a7d6f436d89e18bbe78a29bb97f8df50&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-1-128914776-null-null.nonecase&utm_term=cmake&spm=1018.2226.3001.4450
  • https://blog.csdn.net/m0_73640344/article/details/144246881

1、 find_package搜索地址

  • find_package实际上是在找对应的.cmake文件,这些文件会生成对应的_DIR、_LIB、_INCLUDE环境变量名。我在写一个moveit相关代码时,cmakelist中有如下内容
find_package(moveit_ros_planning_interface REQUIRED)
  • 这个搜索的地址是~/ws_moveit2/install/moveit_ros_planning_interface/share/moveit_ros_planning_interface/cmake

2、正常编译结果

message("==============find_package前=========")
message("moveit_ros_planning_interface_FOUND: ${moveit_ros_planning_interface_FOUND}")
message("moveit_ros_planning_interface_INCLUDE_DIRS: ${moveit_ros_planning_interface_INCLUDE_DIRS}")
message("moveit_ros_planning_interface_LIBRARIES: ${moveit_ros_planning_interface_LIBRARIES}")
message("moveit_ros_planning_interface_LIBRARY_DIRS: ${moveit_ros_planning_interface_LIBRARY_DIRS}")
message("moveit_ros_planning_interface_VERSION: ${moveit_ros_planning_interface_VERSION}")
message("moveit_ros_planning_interface_DIR: ${moveit_ros_planning_interface_DIR}")
find_package(moveit_ros_planning_interface REQUIRED)
message("==============find_package后=========")
message("moveit_ros_planning_interface_FOUND: ${moveit_ros_planning_interface_FOUND}")
message("moveit_ros_planning_interface_INCLUDE_DIRS: ${moveit_ros_planning_interface_INCLUDE_DIRS}")
message("moveit_ros_planning_interface_LIBRARIES: ${moveit_ros_planning_interface_LIBRARIES}")
message("moveit_ros_planning_interface_LIBRARY_DIRS: ${moveit_ros_planning_interface_LIBRARY_DIRS}")
message("moveit_ros_planning_interface_VERSION: ${moveit_ros_planning_interface_VERSION}")
message("moveit_ros_planning_interface_DIR: ${moveit_ros_planning_interface_DIR}")
  • 在find_package前这些变量都不存在
  • 没有引入手动编译moveit的工作空间的环境变量,所以在find_package后的环境变量都是在/opt/ros/humle中的,以下是其中的一部分
moveit_ros_planning_interface_FOUND: 1    #找到包
moveit_ros_planning_interface_INCLUDE_DIRS: /opt/ros/humble/include/geometry_msgs;/opt/ros/humble/include/moveit_msgs;/usr/include/bullet;/opt/ros/humble/include;   #头文件地址
moveit_ros_planning_interface_LIBRARIES: /opt/ros/humble/lib/libbuiltin_interfaces__rosidl_generator_c.so;/opt/ros/humble/lib/libbuiltin_interfaces__rosidl_typesupport_fastrtps_c.so;   #库文件
moveit_ros_planning_interface_LIBRARY_DIRS:             #空
moveit_ros_planning_interface_VERSION: 2.5.8    #版本
moveit_ros_planning_interface_DIR: /opt/ros/humble/share/moveit_ros_planning_interface/cmake   #cmake地址

3、使用手动编译moveit2

  • 关键就是添加set(moveit_ros_planning_interface_DIR “~/ws_moveit2/install/moveit_ros_planning_interface/share/moveit_ros_planning_interface/cmake”)
  • 然后将缺失的so文件添加到LD_LIBRARY_PATH环境变量,这一步也可以用cmake中连接器的相关语法,根本原因在于虽然告诉用find_package告诉了编译器怎么编译(比如CMAKE_CURRENT_SOURCE_DIR等变量),但是和环境变量相关的连接过程还是没有变化,所以要手动添加环境或者在连接器上给出具体位置(最简单的还是直接source运行一下手动编译moveit的bash文件)

4、自写库使用find_package()

资料:
https://zhuanlan.zhihu.com/p/669872914
https://www.cnblogs.com/linxmouse/p/16778116.html

  • find_packagge()有模块和配置两种模式。模块模式一般就是自己写的cmake文件,一般是Find<package_name>.cmake文件格式。配置模式就是第三方库官方提供的cmake文件,一般是<package_name>Config.cmake格式。

(1)自写库

  • cpp文件、h头文件和CMakeList文件都跟一般代码一样,只是生成库文件。关键就是在cmake文件中添加一些变量。
src/MyLibrary.cpp
#include "MyLibrary.h"
#include <iostream>

namespace MyLibrary {
    void printMessage() {
        std::cout << "Hello from MyLibrary!" << std::endl;
    }
}

include/MyLibrary.h
#ifndef MYLIBRARY_H
#define MYLIBRARY_H

namespace MyLibrary {
    void printMessage();
}

#endif // MYLIBRARY_H

CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyLibrary VERSION 1.0)

# 添加库
add_library(MyLibrary src/MyLibrary.cpp)

# 包含头文件目录
target_include_directories(MyLibrary PUBLIC include)
cmake/FindMyLibrary.cmake
set(MyLibrary_FOUND true)
set(MyLibrary_INCLUDE_DIR /home/wangyuanhao/communication_with_thread/find_package_test/include/)
set(MyLibrary_LIBRARIES_DIR /home/wangyuanhao/communication_with_thread/find_package_test/build/)

(2)调用自写库

  • find_package只是调用了cmake文件,只是会再一些特定路径下搜索,用include直接调用cmake即可。
src/main.cpp
#include <MyLibrary.h>

int main() {
    MyLibrary::printMessage();
    return 0;
}

CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyApp)

# 查找 MyLibrary
set(CMAKE_MODULE_PATH /home/wangyuanhao/communication_with_thread/find_package_test/cmake)  #将cmake路径添加到模块路径CMAKE_MODULE_PATH,这样find_package才能找到
message(CMAKE_MODULE_PATH:${CMAKE_MODULE_PATH})

find_package(MyLibrary REQUIRED)
#include(/home/wangyuanhao/communication_with_thread/find_package_test/cmake/FindMyLibrary.cmake)#跟find_package效果一样

message(MyLibrary_INCLUDE_DIR:${MyLibrary_INCLUDE_DIR})


# 添加可执行文件
add_executable(MyApp src/main.cpp)

# 链接 MyLibrary
target_link_libraries(MyApp PRIVATE /home/wangyuanhao/communication_with_thread/find_package_test/build/libMyLibrary.a)

if (MyLibrary_INCLUDE_DIR)
    target_include_directories(MyApp PRIVATE ${MyLibrary_INCLUDE_DIR})
endif()

相关文章:

  • Redis分布式锁的实现(Redission)
  • 弱监督语义分割学习计划(2)-使用CoT进行Open Vocabulary Label简单实现类激活图
  • 【AD】3-10 原理图PDF导出
  • 【多模态大模型论文精读】MOSHI:双工实时语音对话大模型
  • java之运算符
  • 大白话TypeScript 第九章:TypeScript 项目的优化、测试与发布
  • 计算机网络概述
  • Apache IoTDB 树表双模型直播回顾(下)
  • 专线物流公共服务平台:全面提升专线物流效率
  • 【linux】详谈 环境变量
  • 基于Transformers的文本相似度
  • 小红书自动评论
  • 大模型—如何从huggingface上下载并调用模型
  • 每天一个Flutter开发小项目 (8) : 掌握Flutter网络请求 - 构建每日名言应用
  • RuoYi框架介绍,以及如何基于Python使用RuoYi框架
  • DeepSeek 使用窍门与提示词写法指南
  • Spark基础篇 RDD、DataFrame与DataSet的关系、适用场景与演进趋势
  • 聊聊Java的SPI机制
  • SocketCAN(linux中启用CAN)
  • fs 文件系统模块
  • 公司网站建设有用吗/seo网站关键词优化费用
  • 企业网站建设可行性分析表/武汉seo首页
  • 脑白金广告/网络营销seo优化
  • 网站字体设计重要性/seo流量排行榜神器
  • 附近做网站的公司电话/seo手机关键词排行推广
  • wordpress做一个视频网站吗/百度助手下载