Robobot compile

From Rsewiki

Back to Robobot

Back to Robobot software description

Compile using CMake

To compile, the compiler uses a lot of parameters to specify what to compile, where the system libraries are placed and other compile options. A Makefile is often used to specify these options, to check for dependencies and not to compile more than needed.

A Makefile can be complicated too, and a number of apps exist to simplify the generation of the Makefile. One of the most widely used is CMake

CMake

CMake has a specification file called CMakeLists.txt, for our project, it looks like this:

cmake_minimum_required(VERSION 3.8)
project(raubase)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

find_package(OpenCV REQUIRED )
find_package(Threads REQUIRED)
#find_package(libgpiodcxx REQUIRED) 

include_directories(${OpenCV_INCLUDE_DIRS} ${rclcpp_INCLUDE_DIRS} ${dlib_INCLUDE_DIR})
execute_process(COMMAND uname -m RESULT_VARIABLE IS_OK OUTPUT_VARIABLE CPU1)
string(STRIP ${CPU1} CPU)
# works for Raspberry 3 and 4
if (${CPU} MATCHES "armv7l" OR ${CPU} MATCHES "aarch64")
   message("# Is a RASPBERRY; CPU=${CPU} (Pi3=armv7l, pi4=aarch64)")
    #    set(EXTRA_CC_FLAGS " -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -DRASPBERRY_PI -D${CPU}")
    set(EXTRA_CC_FLAGS "-D${CPU} -O2 -g0 -DRASPBERRY_PI -I/home/local/git/CLI11/include")
    #set(EXTRA_CC_FLAGS "-D${CPU} -O0 -g2 -DRASPBERRY_PI")
 else()
    message("# Not a RASPBERRY; CPU=${CPU}")
    set(EXTRA_CC_FLAGS "-D${CPU} -O0 -g2")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic \
    -Wno-format-truncation -Wno-return-type \
    -std=c++20 ${EXTRA_CC_FLAGS}")
set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-pthread") 

add_executable(raubase
     src/bplan20.cpp
     src/bplan21.cpp
     src/bplan40.cpp
     src/cedge.cpp
     src/cheading.cpp
     src/cmixer.cpp
     src/cmotor.cpp
     src/cservo.cpp
     src/main.cpp
     src/medge.cpp
     src/mpose.cpp
     src/sedge.cpp
     src/sencoder.cpp
     src/sgpiod.cpp
     src/simu.cpp
     src/sdist.cpp
     src/sjoylogitech.cpp
     src/spyvision.cpp
     src/sstate.cpp
     src/steensy.cpp
     src/upid.cpp
     src/uservice.cpp
     src/usocket.cpp
     src/utime.cpp
     )

if (${CPU} MATCHES "armv7l" OR ${CPU} MATCHES "aarch64")
  target_link_libraries(raubase ${CMAKE_THREAD_LIBS_INIT} readline gpiod rt)
else()
  target_link_libraries(raubase ${CMAKE_THREAD_LIBS_INIT} readline gpiod)
endif()

This file defines the name of the executable: raubase.

Adaptation to Raspberry Pi is handled in a few if sections. This allows the software to be compiled and run on other platforms; this has been an advantage, especially during the initial debugging.

What to compile is specified here. If you add new mission plans (or other functions), such files need to be added to this list.

Build directory

Both CMake and Make generate a lot of files to make the compilation faster. In order not to clutter the base directory, it is recommended to make a build directory as a sub-directory to the base directory.

This build directory is already present in the Raspberry disk for the Robobot:

$ cd ~/svn/robobot/raubase/build

If this directory is empty, or the CMakeLists.txt is changed substantially, then CMake is needed to generate or regenerate the Makefile.

Run CMake

$ cd ~/svn/robobot/raubase/build
$ cmake ..

The ".." means parent directory and tells cmake where to find the CMakeLists.txt file.

The CMake list the progress like this:

$ cmake ..
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found OpenCV: /usr (found version "4.5.1") 
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in thread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE  
# Is a RASPBERRY; CPU=armv7l (Pi3=armv7l, pi4=aarch64)
-- Configuring done
-- Generating done
-- Build files have been written to: /home/local/svn/robobot/raubase/build

CMake is also looking for some non-relevant features, like PTHREAD as C-library CMAKE_HAVE_LIBC_PTHREAD, but this is not used here, so that is OK.

It detects that it is running on a Raspberry PI version 3.

Makefile and make

There is now a Makefile in the build directory, but there are other files too:

$ ls
CMakeCache.txt  CMakeFiles  Makefile  cmake_install.cmake

The Makefile is long and almost unreadable, but we just need it to compile. It will also check if the CMakeLists.txt file is changed, and re-run CMake if needed.

So just make the executable using the Makefile, here is added a "-j3" option to allow the compiler to use 3 CPU kernels to the compile task:

$ make -j3
[ 12%] Building CXX object CMakeFiles/raubase.dir/src/bplan21.cpp.o
[ 12%] Building CXX object CMakeFiles/raubase.dir/src/bplan40.cpp.o
[ 12%] Building CXX object CMakeFiles/raubase.dir/src/bplan20.cpp.o
[ 16%] Building CXX object CMakeFiles/raubase.dir/src/cedge.cpp.o
[ 20%] Building CXX object CMakeFiles/raubase.dir/src/cheading.cpp.o
[ 24%] Building CXX object CMakeFiles/raubase.dir/src/cmixer.cpp.o
[ 28%] Building CXX object CMakeFiles/raubase.dir/src/cmotor.cpp.o
[ 32%] Building CXX object CMakeFiles/raubase.dir/src/cservo.cpp.o
[ 36%] Building CXX object CMakeFiles/raubase.dir/src/main.cpp.o
[ 40%] Building CXX object CMakeFiles/raubase.dir/src/medge.cpp.o
[ 44%] Building CXX object CMakeFiles/raubase.dir/src/mpose.cpp.o
[ 48%] Building CXX object CMakeFiles/raubase.dir/src/sedge.cpp.o
[ 52%] Building CXX object CMakeFiles/raubase.dir/src/sencoder.cpp.o
[ 56%] Building CXX object CMakeFiles/raubase.dir/src/sgpiod.cpp.o
[ 60%] Building CXX object CMakeFiles/raubase.dir/src/simu.cpp.o
[ 64%] Building CXX object CMakeFiles/raubase.dir/src/sdist.cpp.o
[ 68%] Building CXX object CMakeFiles/raubase.dir/src/sjoylogitech.cpp.o
[ 72%] Building CXX object CMakeFiles/raubase.dir/src/spyvision.cpp.o
[ 76%] Building CXX object CMakeFiles/raubase.dir/src/sstate.cpp.o
[ 80%] Building CXX object CMakeFiles/raubase.dir/src/steensy.cpp.o
[ 84%] Building CXX object CMakeFiles/raubase.dir/src/upid.cpp.o
[ 88%] Building CXX object CMakeFiles/raubase.dir/src/uservice.cpp.o
[ 92%] Building CXX object CMakeFiles/raubase.dir/src/usocket.cpp.o
/home/local/svn/robobot/raubase/src/steensy.cpp: In member function ‘bool UOutQueue::setMessage(const char*)’:
/home/local/svn/robobot/raubase/src/steensy.cpp:65:12: warning: ‘char* strncpy(char*, const char*, size_t)’ output may be truncated copying 3 bytes from a string of length 3 [-Wstringop-truncation]
   65 |     strncpy(msg, cc, 3);
      |     12:06, 31 December 2023 (CET)~~^12:06, 31 December 2023 (CET)12:06, 31 December 2023 (CET)~
[ 96%] Building CXX object CMakeFiles/raubase.dir/src/utime.cpp.o
[100%] Linking CXX executable raubase
[100%] Built target raubase

There is a single warning, but I couldn't find a simple way to avoid the warning, and it has no negative consequences other than the warning.

Executable

There is now a raubase executable:

$ ls
CMakeCache.txt  CMakeFiles  Makefile  cmake_install.cmake  raubase

If you run the executable with a "--help" option, you get:

$ ./raubase --help
ROBOBOT app
Usage: ./raubase [OPTIONS]
Options:
 -h,--help                   Print this help message and exit
 -v,--version                Latest SVN version (for uservice.cpp)
 -a,--api-list               List available modules
 -d,--daemon                 Do not listen to the keyboard (daemon mode)
 -w,--white                  Calibrate line sensor on white surface
 -b,--black                  Calibrate line sensor on black surface
 -s,--sensor INT             Calibrate (sharp) distance sensor [1 or 2], use with '-c'
 -c,--calibrate-distance INT Calibrate (sharp) distance sensor at [13 or 50] cm, use with '-s'
 -g,--gyro                   Calibrate gyro offset
 -n,--number INT             Set robot number to Regbot part [0..150]

This is primarily helpful for calibration, see Robobot sensor calibration

Default Ini-file

If you run the raubase with no parameters, it will run the mission.

The default (if no robot.ini exists) is that no mission plans will run. But be careful and place the robot on the floor.

$ cd ~/svn/robobot/raubase/build
$ ./raubase
# STeensy::setup: took 0.010128 sec to open to Teensy
# SState::decode: asked for new name (idi -> name)
# UService::setup - waited 0.060661 sec for initial Teensy setup
# SpyVision:: disabled in robot.ini
# UJoyLogitech:: no joystick found (/dev/input/js0)
# UService::setup - waited 0.082176 sec for full setup
# UService:: setup of all modules finished OK.
# --------- terminating -----------
# UService:: configuration saved to robot.ini

Some modules will print a status - primarily for debugging.

The default behaviour is to setup everything, ask all behaviour plans if they should run, wait for one second at zero velocity, and then terminate, closing all logfiles.

There is now a configuration file robot.ini with default values.

$ ls
CMakeCache.txt  CMakeFiles  Makefile  cmake_install.cmake  log  raubase  robot.ini

Logfile directory

When raubase has run, there is generated logfiles (if not all log options are false).

In this default case, there are log files in the 'log' directory:

$ cd ~/svn/robobot/raubase/build
$ ls -l log
total 168
-rw-r--r-- 1 local local  3299 Dec 31 12:49 log_acc.txt
-rw-r--r-- 1 local local  5277 Dec 31 12:49 log_edge.txt
-rw-r--r-- 1 local local   287 Dec 31 12:49 log_edge_ctrl.txt
-rw-r--r-- 1 local local  7253 Dec 31 12:49 log_edge_normalized.txt
-rw-r--r-- 1 local local  6243 Dec 31 12:49 log_edge_raw.txt
-rw-r--r-- 1 local local  4941 Dec 31 12:49 log_encoder.txt
-rw-r--r-- 1 local local   143 Dec 31 12:49 log_gpio.txt
-rw-r--r-- 1 local local  3377 Dec 31 12:49 log_gyro.txt
-rw-r--r-- 1 local local   475 Dec 31 12:49 log_hbt.txt
-rw-r--r-- 1 local local  7396 Dec 31 12:49 log_heading.txt
-rw-r--r-- 1 local local  1103 Dec 31 12:49 log_irdist.txt
-rw-r--r-- 1 local local  9105 Dec 31 12:49 log_mixer.txt
-rw-r--r-- 1 local local  7889 Dec 31 12:49 log_motor_0.txt
-rw-r--r-- 1 local local  7780 Dec 31 12:49 log_motor_1.txt
-rw-r--r-- 1 local local   101 Dec 31 12:49 log_plan20.txt
-rw-r--r-- 1 local local   101 Dec 31 12:49 log_plan21.txt
-rw-r--r-- 1 local local   101 Dec 31 12:49 log_plan40.txt
-rw-r--r-- 1 local local 11590 Dec 31 12:49 log_pose.txt
-rw-r--r-- 1 local local  6814 Dec 31 12:49 log_pose_abs.txt
-rw-r--r-- 1 local local  1277 Dec 31 12:49 log_servo.txt
-rw-r--r-- 1 local local    96 Dec 31 12:49 log_servo_ctrl.txt
-rw-r--r-- 1 local local 34379 Dec 31 12:49 log_teensy_io.txt

Some are filled with sensor data, and others are relatively empty.