diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3b21ee60a39e9c00a8171be64b82f3948eba52b0
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,214 @@
+stages:
+  - license
+  - build_and_test
+  - demos
+  
+############ YAML ANCHORS ############
+.preliminaries_template: &preliminaries_definition
+  ## Install ssh-agent if not already installed, it is required by Docker.
+  ## (change apt-get to yum if you use an RPM-based image)
+  - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
+
+  ## Run ssh-agent (inside the build environment)
+  - eval $(ssh-agent -s)
+
+  ## Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store
+  ## We're using tr to fix line endings which makes ed25519 keys work
+  ## without extra base64 encoding.
+  ## https://gitlab.com/gitlab-examples/ssh-private-key/issues/1#note_48526556
+  - mkdir -p ~/.ssh
+  - chmod 700 ~/.ssh  
+  - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
+  # - echo "$SSH_KNOWN_HOSTS" > $HOME/.ssh/known_hosts
+  - ssh-keyscan -H -p 2202 gitlab.iri.upc.edu >> $HOME/.ssh/known_hosts
+
+  # update apt
+  - apt-get update
+
+  # create ci_deps folder (if not exists)
+  - mkdir -pv ci_deps
+
+  # manually source ros setup.bash
+  - source /root/catkin_ws/devel/setup.bash
+  - roscd # check that it works
+
+.license_header_template: &license_header_definition
+  - cd $CI_PROJECT_DIR
+
+  # configure git
+  - export CI_NEW_BRANCH=ci_processing$RANDOM
+  - echo creating new temporary branch... $CI_NEW_BRANCH
+  - git config --global user.email "${CI_EMAIL}"
+  - git config --global user.name "${CI_USERNAME}"
+  - git checkout -b $CI_NEW_BRANCH # temporary branch
+
+  # license headers
+  - export CURRENT_YEAR=$( date +'%Y' )
+  - echo "current year:" ${CURRENT_YEAR}
+  - if [ -f license_header_${CURRENT_YEAR}.txt ]; then
+      # add license headers to new files
+  -   echo "File license_header_${CURRENT_YEAR}.txt already exists. License headers are assumed to be updated. Adding headers to new files..."
+  -   ./ci_deps/wolf/wolf_scripts/license_manager.sh --add --path=. --license-header=license_header_${CURRENT_YEAR}.txt --exclude=ci_deps
+  - else
+      # update license headers of all files
+  -   export PREV_YEAR=$(( CURRENT_YEAR-1 ))
+  -   echo "Creating new file license_header_${CURRENT_YEAR}.txt..."
+  -   git mv license_header_${PREV_YEAR}.txt license_header_${CURRENT_YEAR}.txt
+  -   sed -i "s/${PREV_YEAR}/${PREV_YEAR},${CURRENT_YEAR}/g" license_header_${CURRENT_YEAR}.txt
+  -   ./ci_deps/wolf/wolf_scripts/license_manager.sh --update --path=. --license-header=license_header_${CURRENT_YEAR}.txt --exclude=ci_deps
+  - fi
+
+  # push changes (if any)
+  - if git commit -a -m "[skip ci] license headers added or modified" ; then
+  -   git remote set-url --push origin "ssh://git@gitlab.iri.upc.edu:2202/${CI_PROJECT_PATH}.git"
+  -   git push origin $CI_NEW_BRANCH:${CI_COMMIT_REF_NAME}
+  - else
+  -   echo "No changes, nothing to commit!"
+  - fi
+
+.install_wolf_template: &install_wolf_definition
+  - cd ${CI_PROJECT_DIR}/ci_deps
+  - if [ -d wolf ]; then
+  -   echo "directory wolf exists"
+  -   cd wolf
+  -   git checkout devel
+  -   git pull
+  -   git checkout $WOLF_CORE_BRANCH
+  -   git pull
+  - else
+  -   git clone -b $WOLF_CORE_BRANCH ssh://git@gitlab.iri.upc.edu:2202/mobile_robotics/wolf_projects/wolf_lib/wolf.git
+  -   cd wolf
+  - fi
+  - mkdir -pv build
+  - cd build
+  - cmake -DCMAKE_BUILD_TYPE=release -DBUILD_DEMOS=OFF -DBUILD_TESTS=OFF ..
+  - make -j$(nproc)
+  - make install
+
+.install_visionutils_template: &install_visionutils_definition
+  - cd ${CI_PROJECT_DIR}/ci_deps
+  - if [ -d vision_utils ]; then
+  -   echo "directory vision_utils exists"
+  -   cd vision_utils
+  -   git pull
+  - else
+  -   git clone https://gitlab.iri.upc.edu/labrobotica/algorithms/vision_utils.git
+  -   cd vision_utils
+  - fi
+  - mkdir -pv build
+  - cd build
+  - cmake -DCMAKE_BUILD_TYPE=release ..
+  - make -j$(nproc)
+  - make install
+
+.install_wolfvision_template: &install_wolfvision_definition
+  - cd ${CI_PROJECT_DIR}/ci_deps
+  - if [ -d vision ]; then
+  -   echo "directory vision exists"
+  -   cd vision
+  -   git checkout devel
+  -   git pull
+  -   git checkout $WOLF_VISION_BRANCH
+  -   git pull
+  - else
+  -   git clone -b $WOLF_VISION_BRANCH ssh://git@gitlab.iri.upc.edu:2202/mobile_robotics/wolf_projects/wolf_lib/plugins/vision.git
+  -   cd vision
+  - fi
+  - mkdir -pv build
+  - cd build
+  - cmake -DCMAKE_BUILD_TYPE=release -DBUILD_TESTS=OFF ..
+  - make -j$(nproc)
+  - make install
+
+.clone_wolfrosnode_template: &clone_wolfrosnode_definition
+  - roscd
+  - cd ../src
+  - git clone ssh://git@gitlab.iri.upc.edu:2202/mobile_robotics/wolf_projects/wolf_ros/wolf_ros_node.git
+  - cd wolf_ros_node
+  - git checkout $WOLF_ROS_CORE_BRANCH
+
+.build_and_test_template: &build_and_test_definition
+  - roscd
+  - cd ../src
+  - git clone ssh://git@gitlab.iri.upc.edu:2202/${CI_PROJECT_PATH}.git
+  - cd wolf_ros_vision
+  - git checkout $CI_COMMIT_BRANCH
+  - cd ../..
+  - catkin_make
+
+############ LICENSE HEADERS ############
+license_headers:
+  stage: license
+  image: labrobotica/wolf_vision_deps_ros:20.04
+  cache: []
+  except:
+    - master
+  before_script:
+    - *preliminaries_definition
+    - *install_wolf_definition
+  script:
+    - *license_header_definition
+
+############ UBUNTU 18.04 TEST ############
+build_and_test:bionic:
+  stage: build_and_test
+  image: labrobotica/wolf_vision_deps_ros:18.04
+  cache:
+    - key: wolf-bionic
+      paths:
+      - ci_deps/wolf/
+    - key: visionutils-bionic
+      paths:
+      - ci_deps/vision_utils/
+    - key: vision-bionic
+      paths:
+      - ci_deps/vision/
+  except:
+    - master
+  before_script:
+    - *preliminaries_definition
+    - *install_wolf_definition
+    - *install_visionutils_definition
+    - *install_wolfvision_definition
+    - *clone_wolfrosnode_definition
+    - ldconfig
+  script:
+    - *build_and_test_definition
+
+############ UBUNTU 20.04 TEST ############
+build_and_test:focal:
+  stage: build_and_test
+  image: labrobotica/wolf_vision_deps_ros:20.04
+  cache:
+    - key: wolf-focal
+      paths:
+      - ci_deps/wolf/
+    - key: visionutils-focal
+      paths:
+      - ci_deps/vision_utils/
+    - key: vision-focal
+      paths:
+      - ci_deps/vision/
+  except:
+    - master
+  before_script:
+    - *preliminaries_definition
+    - *install_wolf_definition
+    - *install_visionutils_definition
+    - *install_wolfvision_definition
+    - *clone_wolfrosnode_definition
+    - ldconfig
+  script:
+    - *build_and_test_definition
+
+############ RUN DEMOS ############
+demo_apriltag:
+  stage: demos
+  variables:
+    WOLF_CORE_BRANCH: $WOLF_CORE_BRANCH
+    WOLF_VISION_BRANCH: $WOLF_VISION_BRANCH
+    WOLF_APRILTAG_BRANCH: $WOLF_APRILTAG_BRANCH
+    WOLF_ROS_CORE_BRANCH: $WOLF_ROS_CORE_BRANCH
+    WOLF_ROS_APRILTAG_BRANCH: $CI_COMMIT_BRANCH
+  trigger: 
+    project: mobile_robotics/wolf_projects/wolf_ros/demos/wolf_demo_apriltag_imu