This blog contains material that I prepared for my recitation “Efficient C++.” I presented this on Feb 12, 2024 to the Planning Techniques for Robotics class at CMU.
An Abstract Data Type is an interface for interacting with data. It defines operations and results, but not how they’re implemented. Examples:
Data Structure is an implementation of an Abstract Data Type. Data structures you should know for robot planning:
Specific to robot planning problems:
Debugging means to look for bugs and their cause in applications. A bug can be an error or just some unexpected behaviour (e.g. a user complains that he/she receives an error when he/she uses an invalid date format). The problem is that the error may occur several lines of code after the actual bug. Therefore, we need principles of debugging to quickly locate the bug. Typically a debugger is used that can pause the execution of an application, examine variables and manipulate them.
Profiling typically refers to CPU Profiling. It’s a method to detect how long each function or each line of code takes to run and how often it gets executed. The profiler is used to find the bottlenecks in the code. Once you detect it, you might greatly increase the speed of execution by applying efficient C++ principles to the bottleneck.
This is the simplest form of debugging. Make expecations on what the variable values should be for a certain input. Print variables at various steps to check that it matches expectation.
Something I use a lot is the pincer move. If my function containing the bug is a large block of code, I will put print statements at the beginning and end. Let’s say, the former print statement is alright but the latter print statement shows that something went wrong. Like a pincer, I keep moving my print statements inwards from the front and the back. It converges to the line(s) that are actually causing the bug. This principle becomes more useful with larger code spanning multiple files. I quickly reduce my search space by converging like this.
Check the Debugging Demos section to see an example of using these.
g++ -g hello_world.cpp helper.cpp
# -g flag produces debugging information in the operating
# system's native format that gdb can use
gdb -tui ./a.out
# -tui flag opens the terminal user interface
Check the Debugging Demos section to see an example of using these.
Steps:
.vscode
folder in your project folderjson
files to the .vscode
folder.cpp
file containing the int main()
functionRun and Debug
or press Ctrl+Shift+D
(gdb) Launch
configuration from the list"args": []
field in launch.json
and run the debugger againtasks.json
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "C/C++: g++ build active file",
"command": "/usr/bin/g++",
"args": [
"-g",
"${fileDirname}/*.cpp",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "/usr/bin"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
launch.json
{
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"preLaunchTask": "C/C++: g++ build active file",
"args": [], // Remember to add arguments needed by your program
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}
If you want to follow along with these demos, please clone this repository
Guide on what those shortcuts mean
This is the simplest form of profiling based on timing blocks of code. Print time taken between two points in the code using chrono
#include <chrono> // At the top
auto start = std::chrono::high_resolution_clock::now();
/**
* Some computation
*/
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(end - start).count();
printf("Wall clock time: %.2f s\n", duration / 1.0e6);
CPU Profiler: Samples CPU each millisecond to check execution is currently inside which function
Names of some tools:
When to use?
Check the example usage in my Foreign Exchange Converter project. Relevant snippets from the project code:
ostream &operator<<(ostream &os, const set<string> &s) {
for (auto const &i: s) {
os << i << " ";
}
os << "\n";
return os;
}
Check the example usage in my Foreign Exchange Converter project. Relevant snippets from the project code:
template<typename T>
void printSet(set<T> const &s) {
// for(auto i : s) makes a copy of each element of s
for (auto const &i: s) {
cout << i << " ";
}
cout << endl;
}
Check the example usage in my Foreign Exchange Converter project. Relevant snippets from the project code:
int main(void) {
...
// Using lambda expression
auto validateCurrency = [valid_curr](string curr) -> bool {
return valid_curr.find(curr) != valid_curr.end();
};
if (!validateCurrency(curr1) || !validateCurrency(curr2)) {
cout << "Please use valid currency code. Exiting.\n";
}
else {
...
}
...
}
Check the example usage in my Foreign Exchange Converter project. We have currency_codes.txt
as a text file in the same directory. Relevant snippets from the project code:
#include <fstream>
void fetchValidCurrency(set<string> &valid_curr) {
if (ifstream input{"currency_codes.txt"}) {
while (input) {
string line;
getline(input, line);
if (line.empty())
continue;
valid_curr.insert(line);
}
}
}
Vector
Deque
List
Array
Set
Map
Multiset and Multimap
Unordered_set
Unordered_map
Sort vector nums
while keeping track of indices
vector<pair<int,int>> vp(nums.size());
for(int i=0; i<nums.size(); i++){
vp[i] = make_pair(nums[i],i);
}
sort(vp.begin(), vp.end()); // By default sorts using the first item
Convert a string str
to upper case
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
nullptr
, not NULL
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* reverse_head = NULL;
ListNode* prev = NULL;
reverse(head, prev, reverse_head);
return reverse_head;
}
// This will work-
void reverse(ListNode* curr, ListNode* prev, ListNode* &reverse_head) {
// This will not-
// void reverse(ListNode* curr, ListNode* prev, ListNode* reverse_head) {
// Because even a pointer reverse_head needs to be passed by reference
if(curr == nullptr){
reverse_head = prev;
if(prev != nullptr){
cout << prev->val << endl;
cout << reverse_head->val << endl;
}
return;
}
reverse(curr->next, curr, reverse_head);
if(reverse_head != nullptr)
cout << reverse_head->val << endl;
if(prev != nullptr)
cout << prev->val << endl;
curr->next = prev;
return;
}
};
std::string
but simply int
or float
?
std
is the namespace in which all of the C++ standard library functions, classes, and objects reside.ps aux
can also be used to view the memory and cpu usage of the currently running application.
Usage : ps aux | grep |
$ gcc -O2 -frecord-gcc-switches a.c
$ readelf -p .GCC.command.line a.out
Debugging:
Profiling:
Testing:
First responder personnel (FPR) receives a disaster alert for trapped victims in a building, but unsafe conditions prevent entry due to unknown hazard spreads (e.g., fire/radiation). DarkBot enters the cluttered area with narrow pathways, performing exploration, reconstructing a 3D map, and marking survivors on the map. Collected information by DarkBot is sent back to FRPs, providing indoor structure insights and victim location
The system performs area coverage to locate humans based on TARE planner. Conducts mapping and localization within unknown environments. Inputs include robot pose, Velodyne point cloud data, and terrain maps. Output is the subsequent waypoint that the robot must visit next. Solves the problem as a Traveling Salesman Problem (TSP), with an A* path between consecutive viewpoints and refines it for smoother robot navigation
Aligns itself with the active waypoint and proceeds toward it. Leverages the robot’s omni-directional motion capability. Proportional controller outperformed more complex local planners across various scenarios
Robot halts if the planner uncertainty exceeds threshold or if requested command velocity is deemed unsafe. High-frequency command “permission to move” is sent from the operator, the robot pauses if loses connection
registered_scan
(Fuse lidar and IMU)terrain_map
(Terrain Analysis)state_estimation
(Superodometry)Non-linear model predictive controller (NMPC) designed to convert the center of mass trajectory into precise joint states. Responding swiftly to environmental disturbances, the joint controller solves a high-frequency whole-body optimization problem, generating accurate joint torques as output. Leveraging the SQP algorithm from ETH Zurich’s OCS2 package, the optimization process ensures efficient and effective problem-solving.
Devised non-linear model predictive control tracked using reactive whole-body control and deployed to quadruped. Implemented safety features for disaster sites & demonstrated on-demand temporary takeover by safety operator. Integrated localization (Superodometry), controller (custom), and exploration (TARE Planner) sub-systems. Demonstrated robust exploration at 16.5 m2/min coverage rate of unknown, cluttered room with trapped humans
]]>In TeXStudio, click on the following menu
Options > Configure TeXStudio > Commands
And add:
pdflatex -synctex=1 -interaction=nonstopmode --shell-escape %.tex
https://tex.stackexchange.com/questions/99475/how-to-invoke-latex-with-the-shell-escape-flag-in-texstudio-former-texmakerx
TODO: Write the error message and add screenshots of what it looks like before and after.
]]>A metapackage is a package of packages. It does not contain code or physically contain the other packages. It is just a convenience tool. If a group of packages should be together, that information can be added inside a metapackage. So you can apt install
or catkin build
only the metapackage’s name and the coherent group of packages will all be built together.
While populating the package.xml
, I realized that you should avoid putting only the metapackage name, and put the actual list of packages instead. Else, catkin build
throws a warning, for example –
WARNING: package “grid_map_simpletest” should not depend on metapackage “grid_map” but on its packages instead
There are two tracks of self-development I have in mind:
This blog attempts to journal my odyssey through the first track.
# First time setup steps
# I will keep referring to ROOT_DIR in the rest of the post
ROOT_DIR=<ASSIGN PREFERRED ROOT DIRECTORY ADDRESS HERE>
cd $ROOT_DIR
mkdir -p opensource_ws/src
cd opensource_ws
# Install catkin-tools: https://catkin-tools.readthedocs.io/en/latest/installing.html
catkin init
catkin build
Summary: The kindr package provides interfaces to standard mathematical quantities encountered in kinematics and dynamics for robotics.
Latest as of: Mar 26, 2023
cd $ROOT_DIR
cd opensource_ws/src
git clone https://github.com/ANYbotics/kindr.git
catkin build kindr
Summary: The grid_map is intended for 2.5-dimensional grid mapping, i.e., heightmaps. It is intended to be used as a local data map and it uses a circular buffer to shift the data as the robot moves.
Latest as of: Mar 26, 2023
cd $ROOT_DIR
cd opensource_ws/src
git clone https://github.com/ANYbotics/grid_map.git
catkin build grid_map
Interesting aside here: The grid_map
package is a metapackage. The other packages like grid_map_core
and grid_map_octomap
are where the actual code is implemented. So what’s the difference between a package and a metapackage? I answer it in a short blog post.
Learned a new aspect of ROS CMakeLists.txt while writing the above simpletest. The grid_map
library source code is not accessible even if you include the relevant package names. You have to link to the library using the following code –
target_link_libraries(${PROJECT_NAME}_node
${catkin_LIBRARIES}
)
I created this grid map after figuring out the APIs from grid_map
source code —
Summary: The elevation_mapping package creates a local heightmap around the robot. It needs to be provided with range sensor data and robot pose estimation.
Latest as of: Mar 28, 2023
cd $ROOT_DIR
cd opensource_ws/src
git clone https://github.com/ANYbotics/grid_map.git
catkin build grid_map
Aside — I tried building it on ROS Melodic as well. Melodic fixes below:
filter_base.hpp
with filter_base.h
, filter_chain.hpp
with filter_chain.h
# find_package(TBB 2020.1 EXACT REQUIRED)
PCL_MAKE_ALIGNED_OPERATOR_NEW
to EIGEN_MAKE_ALIGNED_OPERATOR_NEW
in elevation_mapping package PointXYZRGBConfidenceRatio.hpp
.trunc8/elevation_mapping_simpletest
Summary: The legged_control package is a legged robot control stack based on NMPC (Nonlinear Model Predictive Control) and WBC (Whole Body Controller).
Latest as of: Apr 01, 2023
cd $ROOT_DIR
cd opensource_ws/src
mkdir legged_control_pkgs && cd legged_control_pkgs
# Clone legged_control
git clone git@github.com:qiayuanliao/legged_control.git
# Clone OCS2
git clone git@github.com:leggedrobotics/ocs2.git
# Clone pinocchio
git clone --recurse-submodules https://github.com/leggedrobotics/pinocchio.git
# Clone hpp-fcl
git clone --recurse-submodules https://github.com/leggedrobotics/hpp-fcl.git
# Clone ocs2_robotic_assets
git clone https://github.com/leggedrobotics/ocs2_robotic_assets.git
# Install dependencies
sudo apt install liburdfdom-dev liboctomap-dev libassimp-dev
catkin config -DCMAKE_BUILD_TYPE=RelWithDebInfo
catkin build ocs2_legged_robot_ros ocs2_self_collision_visualization
source $ROOT_DIR/devel/setup.zsh
roslaunch ocs2_legged_robot_ros legged_robot_ddp.launch
The last link is useful. There are two directions from here:
mbs_unitree_ros
I just got done with my MRSD team’s first progress presentation for our capstone project. I feel super good!
Link to recording of the entire presentation
My MRSD capstone project runs over 3 semesters (Sep 2022 — Dec 2023). The end-goal in the first semester is concept development and working out the systems design. At the end of semester two and three, we have the behemoths of Spring Validation Demo (SVD) and Fall Validation Demo (FVD) respectively.
A one-line description of our project idea is –
Human-robot collaborative search and rescue in low-light and narrow cluttered environment.
Our team name is the NightWalkers and the robot will be named as the DarkBot.
Our team has been through some pretty interesting experiences. We went down from a five-membered to a four-membered team last week. The original project topic was Heterogeneous Multi-robot Search and Rescue. I know, reallly cool!
We are no longer focusing on heterogeneous nor multi-robot nor rescue. The space of S&R is vast and we always had to narrow down our focuses. So we did, and at this moment, I’m super excited with our current pillars of focus:
And most of all, I’m very grateful for my current team. There were communication gaps initially. That’s why when one of our members switched team, it took me by surprise. But from my experience this past week, everyone in the current team is an asset. And that I’m grateful about.
This week marked the first round of class presentations for the capstone projects. It’s surreal — other teams are working on lunar robots, pipe inspection robots, gap-crossing robots, telepresence robots. Listening in to the presentations gets monotonous and a little boring, but I can only envision what these presentations would like a few months from now. Live robot demos!
Of all the projects, I am most excited about my own. This project was literally what I had dreamt of working upon in my Statement of Purpose! And here I am.
In my project, there’s exploration, there’s planning, there’s impact. As the program progresses, I hope not to tunnel vision myself into seeing this as just a project. I want to do justice to the potential impact that my project can have — impacting the lives of first responders. Our work here doesn’t have to change the industry; even if it solves just one piece of the puzzle, I will feel I have done justice to my resources and my talents.
]]>Tried Midnight Commander
. Didn’t like as much.
Ranger
stuck with me!
I had been contemplating and dreaming of using a terminal file manager for the longest time. The time is finally here.
I have already started playing around with its config parameters.
ueberzug
ueberzug
to pip install. I hope it doesn’t break any other of my dependenciesReally feeling the lack of fasd
shortcuts here. I will try to integrate them soon.
torch==1.8.1
and torchvision==0.9.1
are required which are available with older versions of pythonmkdir ~/Pydockerfiles && cd ~/Pydockerfiles
touch Dockerfile
touch run
touch requirements.txt
requirements.txt
if you have any reference listchmod +x run
./run
FROM python:3.8-slim-buster
WORKDIR /home
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install jupyter notebook
RUN apt-get update && apt-get install -y python3-opencv
CMD jupyter notebook --ip 0.0.0.0 --no-browser --allow-root
#!/bin/sh
docker build --tag python-docker .
docker run -it \
--rm \
-p 8888:8888 \
--name py-doc \
-v ~/{WORK_DIRECTORY_PATH}:/home/{WORK_DIRECTORY_NAME} \
python-docker
ImportError: libGL.so.1: cannot open shared object file: No such file or directory
: Stackoverflow postI fixed the xmodmap
issue in my system after a month and life already feels so much better. xmodmap
is used to re-map keyboard bindings. And shortcuts associated with these key-bindings are what make the i3-wm system very special. (Error Resolution is at the end)
My usage of Esc is extensive because I use vim key-bindings in my terminal (zsh), my lock, shut down, log out… options are accessed by Super+Esc. Also vimium bindings in chrome, rofi, etc. Always keep needing the Esc key.
In combination with Esc key (above) as well as for workspace switching, screenshot, etc. Many of my custom shortcuts are linked to Super key.
The xmodmap issue started after switching from Ubuntu 20.04 to 22.04. This is because Ubuntu made Wayland server the default in 22.04 from the earlier X server in 20.04.
Steps to resolve this:
sudo nano /etc/gdm3/custom.conf
WaylandEnable=false
One of the commands you can try out is below
xmodmap -e "clear lock" #disable caps lock switch
xmodmap -e "keysym Caps_Lock = Escape" #set caps_lock as escape
Add this to your ~/.config/i3/config
or ~/.*shrc
to automatically remap at every boot.