Bootstrap

Ubuntu 20.04 安装 Franka Control Interface (FCI)


前言

本文介绍在 ubuntu 20.04 中安装 Franka Control Interface (FCI),前提为已安装好 ROS Noetic,参考文档如下:


一、安装 libfranka 和 franka_ros

安装好 ROS Noetic 后,执行:

sudo apt install ros-noetic-libfranka ros-noetic-franka-ros

从源代码构建之前,卸载 libfrankafranka_ros 的现有安装,以避免冲突:

sudo apt remove "*libfranka*"

从Ubuntu的包管理器安装以下依赖项以构建 libfranka:

sudo apt install build-essential cmake git libpoco-dev libeigen3-dev

从 GitHub 下载 libfranka 源代码:

  • 对于 Panda:
git clone --recursive https://github.com/frankaemika/libfranka # only for panda
cd libfranka
  • 对于 Franka Research 3:
git clone --recursive https://github.com/frankaemika/libfranka --branch 0.10.0 # only for FR3
cd libfranka

在源目录中,创建一个生成目录并运行 CMake:

mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=OFF ..
cmake --build .

可选(但推荐)在同一目录中构建 libfranka-Debian 包并安装:

cpack -G DEB
sudo dpkg -i libfranka*.deb

在选择的目录中创建 Catkin 工作区:

cd /path/to/desired/folder
mkdir -p catkin_ws/src
cd catkin_ws
source /opt/ros/noetic/setup.sh
catkin_init_workspace src

然后从 GitHub 下载 franka_ros 存储库:

git clone --recursive https://github.com/frankaemika/franka_ros src/franka_ros

安装任何丢失的依赖项并生成包:

rosdep install --from-paths src --ignore-src --rosdistro noetic -y --skip-keys libfranka
catkin_make -DCMAKE_BUILD_TYPE=Release -DFranka_DIR:PATH=/path/to/libfranka/build
source devel/setup.sh

二、设置实时内核

1. 安装依赖

首先安装编译所需的几个软件包:

sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev fakeroot

安装 dwarves 软件包:

sudo apt install dwarves

接下来从官方网站 kernel.org 下载内核源代码,选择最新的 longterm 版本并复制 tarball 链接,用该链接下载内核源代码并将其解压缩:

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.53.tar.xz
tar -xf linux-6.1.53.tar.xz

2. 编译内核

进入Linux源的目录:

cd linux-6.1.53

复制当前安装的 Linux 内核的配置文件:

cp -v /boot/config-$(uname -r) .config

这个配置文件包含了大量不必要的驱动程序和内核模块。可以使用 localmodconfig 命令查看系统中已加载的内核模块,并修改该文件,以便在构建中只包含这些模块。运行该命令时,有任何请求提示,只需每次点击回车键(不键入答案)。

make localmodconfig

接下来,通过运行以下命令对配置进行四次修改:

scripts/config --disable SYSTEM_TRUSTED_KEYS
scripts/config --disable SYSTEM_REVOCATION_KEYS
scripts/config --set-str CONFIG_SYSTEM_TRUSTED_KEYS ""
scripts/config --set-str CONFIG_SYSTEM_REVOCATION_KEYS ""

运行以下命令编译内核:

fakeroot make

或者,8 表示 CPU 核的数量:

fakeroot make -j8

构建完成后通过运行以下命令以检查编译是否成功。返回 0 表示成功,返回其他任何值都不成功:

echo $?

3. 安装内核

首先安装内核模块:

sudo make modules_install

然后安装内核:

sudo make install

最后重启:

sudo reboot

4. 验证内核

通过以下命令检查安装的内核的版本:

uname -rs

返回值与下载的内核源版本相匹配,那么您安装是成功的:

Linux 6.1.53

三、在实时内核下安装显卡驱动

安装完实时内核并重启后,在终端中输入 nvidia-smi 没有弹出显卡驱动信息,这是因为实时内核下的显卡驱动掉了。切换回原来的内核版本,发现是有显卡驱动信息的。在实时内核下,无法直接下载显卡驱动,所以该节介绍怎么在实时内核下安装显卡驱动。

1. 切换回之前的内核

nvidia官网下载适配自己电脑显卡版本的驱动 (.run 文件),以 GeForce RTX 3070 Laptop GPU 为例,显卡驱动的版本为 535.104.05 。首先安装 dkms 管理工具:

sudo apt install dkms

禁用 nouveau:

sudo gedit /etc/modprobe.d/blacklist.conf

在文件中最后一行插入:

blacklist nouveau
options nouveau modeset=0

保存退出,在终端中输入以下命令,使设置生效并重启:

sudo update-initramfs -u
sudo reboot

通过以下命令验证:

lsmod | grep nouveau

回车无任何反应,则表示成功。
卸载之前的显卡驱动:

sudo apt-get remove --purge nvidia*

在下载目录下运行显卡驱动安装包:

chmod +x NVIDIA-Linux-x86_64-535.104.05.run
sudo ./NVIDIA-Linux-x86_64-535.104.05.run

弹出第一个有关 dkms 的界面选择 yes,其它的都选 no. 安装完成后,重启,打开终端,输入查看显卡信息:

nvidia-smi

2. 切换至实时内核

通过以下 .sh 脚本实时内核下安装显卡驱动:

#!/bin/bash

BUILD_BASE=`pwd`
NV_FILE="NVIDIA-Linux-x86_64-xxx.run"  # 这里改成自己下载的.run文件名(之前安装过的)
#NV_URL="https://us.download.nvidia.cn/XFree86/Linux-x86_64/430.50/${NV_FILE}"  # 之前已经下好了显卡驱动.run文件,就不用从网上下载了,直接注释掉,而且如果要下载的话,则慢
NEED_TO_COMPILE_NV_KO=1

function clean_env() {

    [ -d ./${NV_DIR} ] && rm -rf ./${NV_DIR}
}

function check_env() {
    
    # check if in rt kernel
    uname -r | grep rt 1>/dev/null 2>&1 
    if [ $? -ne 0 ]
    then
        echo "Not in rt kernel, Please install apollo kernel and reboot machine first."
        exit 2
    fi

    # check if nv ko already in kernel
    if [ ! -f /lib/modules/`uname -r`/kernel/drivers/video/nvidia.ko ]
    then
        export NEED_TO_COMPILE_NV_KO=1
    fi
}

function prepare_nv() {

    ## download nv install file from nvidia home page 
    #if [ ! -f ./${NV_FILE} ]
    #then
    #   echo "Downloading ${NV_FILE} from nvidia website..."
    #    wget ${NV_URL} -O ${NV_FILE}
    #    if [ $? -ne 0 ]
    #    then
    #        echo "Downloading ${NV_FILE} failed, please check your network connection!"
    #        rm -rf ./${NV_FILE}
    #        exit 1
    #    fi
    #fi
    ###########上面是下载驱动的代码,我们已经提前下载好了,就不需要这段代码了,直接注释掉############

    # +x 
    chmod +x ./${NV_FILE}
    echo "Extracting nvidia install run file..."
    ./${NV_FILE} -x 1>/dev/null 2>&1
    NV_DIR="`echo ${NV_FILE} | awk -F '.run' '{print $1}'`"
    NV_VERSION="`echo ${NV_FILE} | awk -F '-' '{print $4}' | awk -F '.run' '{print $1}'`"

    export NV_DIR
    export NV_VERSION
    export NVIDIA_SOURCE="${NV_DIR}/kernel"
}

function install_lib() {
   
    NV_LIB_OUTPUT_PATH="/usr/lib/x86_64-linux-gnu/"
    NV_BIN_OUTPUT_PATH="/usr/bin/"

    [ -f ./${NV_DIR}/libnvidia-ml.so.${NV_VERSION} ] && /bin/cp -f ./${NV_DIR}/libnvidia-ml.so.${NV_VERSION} ${NV_LIB_OUTPUT_PATH}
    [ -f ./${NV_DIR}/libnvidia-fatbinaryloader.so.${NV_VERSION} ] && /bin/cp -f ./${NV_DIR}/libnvidia-fatbinaryloader.so.${NV_VERSION} ${NV_LIB_OUTPUT_PATH}
    [ -f ./${NV_DIR}/libnvidia-ptxjitcompiler.so.${NV_VERSION} ] && /bin/cp -f ./${NV_DIR}/libnvidia-ptxjitcompiler.so.${NV_VERSION} ${NV_LIB_OUTPUT_PATH}
    [ -f ./${NV_DIR}/libcuda.so.${NV_VERSION} ] && /bin/cp -f ./${NV_DIR}/libcuda.so.${NV_VERSION} ${NV_LIB_OUTPUT_PATH}
    [ -f ./${NV_DIR}/nvidia-modprobe ] && /bin/cp -f ./${NV_DIR}/nvidia-modprobe ${NV_BIN_OUTPUT_PATH}
    [ -f ./${NV_DIR}/nvidia-smi ] && /bin/cp -f ./${NV_DIR}/nvidia-smi ${NV_BIN_OUTPUT_PATH}

    chmod +x /usr/bin/nvidia*
    chmod +s /usr/bin/nvidia-modprobe

    # link for nvidia
    /bin/rm -rf /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1  /usr/lib/x86_64-linux-gnu/libnvidia-ml.so
    /bin/ln -s /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.${NV_VERSION} /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1
    /bin/ln -s /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1 /usr/lib/x86_64-linux-gnu/libnvidia-ml.so

    /bin/rm -rf /usr/lib/x86_64-linux-gnu/libcuda.so  /usr/lib/x86_64-linux-gnu/libcuda.so.1
    /bin/ln -s /usr/lib/x86_64-linux-gnu/libcuda.so.${NV_VERSION} /usr/lib/x86_64-linux-gnu/libcuda.so.1
    /bin/ln -s /usr/lib/x86_64-linux-gnu/libcuda.so.1 /usr/lib/x86_64-linux-gnu/libcuda.so

    # take effect
    /sbin/ldconfig 1>/dev/null 2>&1
}

function build_nv() {

    if [ ${NEED_TO_COMPILE_NV_KO} == 0 ]
    then
        return
    fi

    NVIDIA_MOD_REL_PATH='kernel/drivers/video'
    NVIDIA_OUTPUT_PATH="/lib/modules/`uname -r`/${NVIDIA_MOD_REL_PATH}"
    CPUNUM=`cat /proc/cpuinfo | grep processor | wc | awk -F " " '{print $1}'`

    export IGNORE_PREEMPT_RT_PRESENCE=true
    cd ${NVIDIA_SOURCE} && make -j ${CPUNUM} module
    cd ${BUILD_BASE}

    unset IGNORE_PREEMPT_RT_PRESENCE

    mkdir -p ${NVIDIA_OUTPUT_PATH}

    [ -f ${NVIDIA_SOURCE}/nvidia.ko ] && cp ${NVIDIA_SOURCE}/nvidia.ko ${NVIDIA_OUTPUT_PATH}
    [ -f ${NVIDIA_SOURCE}/nvidia-modeset.ko ] && cp ${NVIDIA_SOURCE}/nvidia-modeset.ko ${NVIDIA_OUTPUT_PATH}
    [ -f ${NVIDIA_SOURCE}/nvidia-drm.ko ] && cp ${NVIDIA_SOURCE}/nvidia-drm.ko ${NVIDIA_OUTPUT_PATH}
    [ -f ${NVIDIA_SOURCE}/nvidia-uvm.ko ] && cp ${NVIDIA_SOURCE}/nvidia-uvm.ko ${NVIDIA_OUTPUT_PATH}

    depmod -a
}

# check environment
check_env

# prepare for nvidia
prepare_nv

# build nvidia.ko
build_nv

# install user lib
install_lib

# clean environment
clean_env

echo "Done to install nvidia kernel driver and user libraries."

运行以下命令,将以上脚本代码复制粘贴进去。对相应内容按自己的显卡驱动安装包的版本修改,修改部分在上面注明了:

sudo gedit install_nvidia.sh

注意: 使用以下命令查看内核版本,版本号包含 PREEMPT_DYNAMIC ,则需要注释掉脚本中的这些内容:

uname -a
uname -r | grep rt 1>/dev/null 2>&1 
    if [ $? -ne 0 ]
    then
        echo "Not in rt kernel, Please install apollo kernel and reboot machine first."
        exit 2
    fi

修改后,运行:

chmod +x install_nvidia.sh
sudo ./install_nvidia.sh

安装完成后重启。
输入查看显卡信息,出现显卡驱动信息,说明安装成功:

nvidia-smi

3. 允许用户为其进程设置实时权限

添加一个名为 realtime 的组,并将控制机器人的用户添加到此组中:

sudo addgroup realtime
sudo usermod -a -G realtime $(whoami)

将以下限制添加到 /etc/security/limits.conf 中,重启后生效:

@realtime soft rtprio 99
@realtime soft priority 99
@realtime soft memlock 102400
@realtime hard rtprio 99
@realtime hard priority 99
@realtime hard memlock 102400
;