diff --git a/.gitignore b/.gitignore
index 567849edaa6..d1b5fa53603 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# Bazel
bazel-apollo
+bazel-apollo_dev
bazel-bin
bazel-genfiles
bazel-out
@@ -7,6 +8,8 @@ bazel-testlogs
/Debug/
*.pyc
WORKSPACE
+# temporary files
+*.swp
# javascript
*bundle.js
@@ -15,6 +18,7 @@ node_modules
# generated files
generatedViews
generatedScripts
+modules/common/data/ssl_keys
# database/log files
*.sqlite
dreamview.log
@@ -26,6 +30,9 @@ npm-debug.log
.settings
.classpath
+# Vscode files
+.vscode
+
# atom.io files
*.gch
@@ -54,6 +61,24 @@ data/log
data/core
data/bag
data/cov
+data/pcd
# Doxygen
docs/doxygen
+
+# Esd can lib
+third_party/can_card_library/esd_can/include
+third_party/can_card_library/esd_can/lib
+
+# Map data files
+modules/map/data
+
+# python proto
+py_proto
+
+# gnss conf files
+modules/drivers/gnss/conf/conf_beijing
+modules/drivers/gnss/conf/conf_us
+
+# calibration files
+modules/calibration/data/mkz056
diff --git a/FAQ.md b/FAQ.md
index b348b612376..42ea26c24dd 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -19,7 +19,7 @@ Many build problems are related to the environment settings.
1. Run the script to get your environment: `bash scripts/env.sh >& env.txt`
2. Provide the content of env.txt in your post.
-## Which ports need be white list to run Apollo in public cloud instance?
+## Which ports must be whitelisted to run Apollo in a public cloud instance?
Use these ports for HMI and Dreamview:
- 8887: HMI
- 8888: Dreamview
diff --git a/WORKSPACE.in b/WORKSPACE.in
index 161f123921b..1ee10ec9653 100644
--- a/WORKSPACE.in
+++ b/WORKSPACE.in
@@ -40,97 +40,6 @@ new_http_archive(
url = "https://github.com/google/benchmark/archive/v1.1.0.tar.gz",
)
-# proto rules (Protobuf and GRPC)
-http_archive(
- name = "org_pubref_rules_protobuf",
- sha256 = "646b39438d8eeba02d9af890dee444c7e4e9d08ae8611bc0e0621257010162db",
- strip_prefix = "rules_protobuf-0.7.1",
- url = "https://github.com/pubref/rules_protobuf/archive/v0.7.1.tar.gz",
-)
-
-load("@org_pubref_rules_protobuf//cpp:rules.bzl", "cpp_proto_repositories")
-
-cpp_proto_repositories(
- lang_deps = {
- # Grpc repo is required by multiple languages but we put it here.
- "com_github_grpc_grpc": {
- "rule": "git_repository",
- "remote": "https://github.com/grpc/grpc.git",
- "init_submodules": True,
- "commit": "3808b6efe66b87269d43847bc113e94e2d3d28fb",
- #"tag": "v1.0.1",
- },
-
- # Hooray! The boringssl team provides a "chromium-stable-with-bazel" branch
- # with all BUILD files ready to go.
- "boringssl": {
- "rule": "http_archive",
- "url": "https://github.com/wanglei828/third-party/raw/master/chromium-stable-with-bazel.zip",
- },
-
- # libssl is required for c++ grpc where it is expected in
- # //external:libssl. This can be either boringssl or openssl.
- "libssl": {
- "rule": "bind",
- "actual": "@boringssl//boringssl-chromium-stable-with-bazel:ssl",
- },
-
- # C-library for zlib
- "com_github_madler_zlib": {
- "rule": "new_git_repository",
- "remote": "https://github.com/madler/zlib",
- "tag": "v1.2.8",
- "build_file": "third_party/com_github_madler_zlib.BUILD",
- },
-
- # grpc++ expects //external:zlib
- "zlib": {
- "rule": "bind",
- "actual": "@com_github_madler_zlib//:zlib",
- },
-
- # grpc++ expects "//external:protobuf_clib"
- "protobuf_clib": {
- "rule": "bind",
- "actual": "@com_github_google_protobuf//:protobuf",
- },
-
- # grpc++ expects //external:nanopb
- "nanopb": {
- "rule": "bind",
- "actual": "@com_github_grpc_grpc//third_party/nanopb",
- },
-
- # Bind the executable cc_binary grpc plugin into
- # //external:protoc_gen_grpc_cpp. Expects
- # //external:protobuf_compiler. TODO: is it really necessary to
- # bind it in external?
- "protoc_gen_grpc_cpp": {
- "rule": "bind",
- "actual": "@com_github_grpc_grpc//:grpc_cpp_plugin",
- },
-
- # Bind the protobuf proto_lib into //external. Required for
- # compiling the protoc_gen_grpc plugin
- "protobuf_compiler": {
- "rule": "bind",
- "actual": "@com_github_google_protobuf//:protoc_lib",
- },
-
- # GTest is for our own internal cc tests.
- "gtest": {
- "rule": "new_git_repository",
- "remote": "https://github.com/google/googletest.git",
- "commit": "ed9d1e1ff92ce199de5ca2667a667cd0a368482a",
- "build_file": "third_party/protobuf_gtest.BUILD",
- },
- },
-)
-
-load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_repositories")
-
-py_proto_repositories()
-
# cpplint from google style guide
new_git_repository(
name = "google_styleguide",
@@ -171,5 +80,93 @@ new_http_archive(
name = "ros",
build_file = "third_party/ros.BUILD",
strip_prefix = "ros",
- url = "https://github.com/ApolloAuto/apollo-platform/releases/download/1.0.0/ros-indigo-apollo-1.0.0.MACHINE_ARCH.tar.gz",
+ url = "https://github.com/ApolloAuto/apollo-platform/releases/download/1.5.0/ros-indigo-apollo-1.5.0-MACHINE_ARCH.tar.gz",
+)
+
+# OpenCV 2.4.13.2
+new_http_archive(
+ name = "opencv2",
+ build_file = "third_party/opencv2.BUILD",
+ strip_prefix = "opencv-2.4.13.2",
+ url = "https://github.com/opencv/opencv/archive/2.4.13.2.zip",
+)
+
+# PCL 1.7
+# =======
+# This requires libpcl-dev to be installed in your Ubuntu/Debian.
+new_local_repository(
+ name = "pcl",
+ build_file = "third_party/pcl.BUILD",
+ path = "/usr/local/include/pcl-1.7",
+)
+
+new_local_repository(
+ name = "glew",
+ build_file = "third_party/glew.BUILD",
+ path = "/usr/include",
+)
+
+new_local_repository(
+ name = "opengl",
+ build_file = "third_party/opengl.BUILD",
+ path = "/usr/include",
+)
+
+new_local_repository(
+ name = "glfw",
+ build_file = "third_party/glfw.BUILD",
+ path = "/usr/include",
+)
+
+new_local_repository(
+ name = "vtk",
+ build_file = "third_party/vtk.BUILD",
+ path = "/usr/include/vtk-5.8",
+)
+
+# Caffe
+new_local_repository(
+ name = "caffe",
+ build_file = "third_party/caffe.BUILD",
+ path = "/usr/include/caffe",
+)
+
+# YAML-CPP
+new_http_archive(
+ name = "yaml_cpp",
+ build_file = "third_party/yaml_cpp.BUILD",
+ strip_prefix = "yaml-cpp-yaml-cpp-0.5.3",
+ url = "https://github.com/jbeder/yaml-cpp/archive/yaml-cpp-0.5.3.zip",
+)
+
+# qpOASES
+new_http_archive(
+ name = "qp_oases",
+ build_file = "third_party/qp_oases.BUILD",
+ sha256 = "ae15eee80455c26d0c26078498893582b67b1d71df18f14f12591023561e5f88",
+ strip_prefix = "qpOASES-3.2.1",
+ url = "https://www.coin-or.org/download/source/qpOASES/qpOASES-3.2.1.zip",
+)
+
+# Proj.4
+new_http_archive(
+ name = "proj4",
+ build_file = "third_party/proj4.BUILD",
+ strip_prefix = "proj.4-4.9.3",
+ url = "https://github.com/OSGeo/proj.4/archive/4.9.3.zip",
+)
+
+# tinyxml2
+new_http_archive(
+ name = "tinyxml2",
+ build_file = "third_party/tinyxml2.BUILD",
+ strip_prefix = "tinyxml2-5.0.1",
+ url = "https://github.com/leethomason/tinyxml2/archive/5.0.1.zip",
+)
+
+#protobuf 3.3
+http_archive(
+ name = "com_google_protobuf",
+ strip_prefix = "protobuf-3.3.0",
+ url = "https://github.com/google/protobuf/releases/download/v3.3.0/protobuf-cpp-3.3.0.tar.gz",
)
diff --git a/apollo.sh b/apollo.sh
index 8ca356c6a9a..d911b614163 100755
--- a/apollo.sh
+++ b/apollo.sh
@@ -82,51 +82,57 @@ function check_esd_files() {
}
function generate_build_targets() {
- BUILD_TARGETS=$(bazel query //... | grep -v "_test$" | grep -v "third_party" \
- | grep -v "_cpplint$" | grep -v "release" | grep -v "kernel")
+ BUILD_TARGETS=$(bazel query //...)
if [ $? -ne 0 ]; then
fail 'Build failed!'
fi
-
if ! $USE_ESD_CAN; then
BUILD_TARGETS=$(echo $BUILD_TARGETS |tr ' ' '\n' | grep -v "hwmonitor" | grep -v "esd")
fi
}
-function generate_test_targets() {
- TEST_TARGETS=$(bazel query //... | grep "_test$" | grep -v "third_party" | grep -v "kernel")
- if [ $? -ne 0 ]; then
- fail 'Test failed!'
- fi
-
- if ! $USE_ESD_CAN; then
- TEST_TARGETS=$(echo $TEST_TARGETS| tr ' ' '\n' | grep -v "hwmonitor" | grep -v "esd")
- fi
-}
-
#=================================================
# Build functions
#=================================================
-function apollo_build() {
+function build() {
START_TIME=$(get_now)
echo "Start building, please wait ..."
generate_build_targets
- echo "Building on $MACHINE_ARCH, with targets:"
- echo "$BUILD_TARGETS"
- echo "$BUILD_TARGETS" | xargs bazel --batch --batch_cpu_scheduling build --jobs=10 --define ARCH="$MACHINE_ARCH" --define CAN_CARD=${CAN_CARD} --cxxopt=-DUSE_ESD_CAN=${USE_ESD_CAN} -c dbg
+ echo "Building on $MACHINE_ARCH..."
+ echo "$BUILD_TARGETS" | xargs bazel build $DEFINES -c $1
if [ $? -eq 0 ]; then
success 'Build passed!'
else
fail 'Build failed!'
fi
- find bazel-genfiles/* -type d -exec touch "{}/__init__.py" \;
+
+ # Build python proto
+ build_py_proto
+}
+
+function apollo_build_dbg() {
+ build "dbg"
+}
+
+function apollo_build_opt() {
+ build "opt"
+}
+
+function build_py_proto() {
+ if [ -d "./py_proto" ];then
+ rm -rf py_proto
+ fi
+ mkdir py_proto
+ PROTOC='./bazel-out/host/bin/external/com_google_protobuf/protoc'
+ find modules/ -name "*.proto" | grep -v gnss | xargs ${PROTOC} --python_out=py_proto
+ find py_proto/* -type d -exec touch "{}/__init__.py" \;
}
function check() {
local check_start_time=$(get_now)
- apollo_build && run_test && run_lint
+ apollo_build_dbg && run_test && run_lint
START_TIME=$check_start_time
if [ $? -eq 0 ]; then
@@ -157,16 +163,19 @@ function release() {
# modules
MODULES_DIR=$ROOT_DIR/modules
mkdir -p $MODULES_DIR
- for m in control canbus localization decision perception prediction planning
+ for m in control canbus localization decision perception \
+ prediction planning routing calibration
do
TARGET_DIR=$MODULES_DIR/$m
mkdir -p $TARGET_DIR
- cp bazel-bin/modules/$m/$m $TARGET_DIR
+ if [ -e bazel-bin/modules/$m/$m ]; then
+ cp bazel-bin/modules/$m/$m $TARGET_DIR
+ fi
if [ -d modules/$m/conf ];then
cp -r modules/$m/conf $TARGET_DIR
fi
if [ -d modules/$m/data ];then
- cp -r modules/$m/conf $TARGET_DIR
+ cp -r modules/$m/data $TARGET_DIR
fi
done
@@ -180,6 +189,7 @@ function release() {
# ros
cp -Lr bazel-apollo/external/ros $ROOT_DIR/
+ rm -f ${ROOT_DIR}/ros/*.tar.gz
# scripts
cp -r scripts $ROOT_DIR
@@ -188,17 +198,32 @@ function release() {
cp -Lr bazel-bin/modules/dreamview/dreamview.runfiles/apollo/modules/dreamview $MODULES_DIR
cp -r modules/dreamview/conf $MODULES_DIR/dreamview
+ # map
+ mkdir $MODULES_DIR/map
+ cp -r modules/map/data $MODULES_DIR/map
+
# common data
mkdir $MODULES_DIR/common
cp -r modules/common/data $MODULES_DIR/common
# hmi
- mkdir -p $MODULES_DIR/hmi/ros_node $MODULES_DIR/hmi/utils
- cp bazel-bin/modules/hmi/ros_node/ros_node_service $MODULES_DIR/hmi/ros_node/
+ mkdir -p $MODULES_DIR/hmi/ros_bridge $MODULES_DIR/hmi/utils
+ cp bazel-bin/modules/hmi/ros_bridge/ros_bridge $MODULES_DIR/hmi/ros_bridge/
cp -r modules/hmi/conf $MODULES_DIR/hmi
cp -r modules/hmi/web $MODULES_DIR/hmi
cp -r modules/hmi/utils/*.py $MODULES_DIR/hmi/utils
+ # perception
+ cp -r modules/perception/model/ $MODULES_DIR/perception
+
+ # gnss config
+ mkdir -p $MODULES_DIR/drivers/gnss
+ cp -r modules/drivers/gnss/conf/ $MODULES_DIR/drivers/gnss
+
+ # velodyne launch
+ mkdir -p $MODULES_DIR/drivers/velodyne/velodyne
+ cp -r modules/drivers/velodyne/velodyne/launch $MODULES_DIR/drivers/velodyne/velodyne
+
# lib
LIB_DIR=$ROOT_DIR/lib
mkdir $LIB_DIR
@@ -215,7 +240,8 @@ function release() {
mkdir -p $MODULES_DIR/monitor/hwmonitor/hw/tools/
cp bazel-bin/modules/monitor/hwmonitor/hw/tools/esdcan_test_app $MODULES_DIR/monitor/hwmonitor/hw/tools/
fi
- cp -r bazel-genfiles/* $LIB_DIR
+ cp -r bazel-genfiles/external $LIB_DIR
+ cp -r py_proto/modules $LIB_DIR
# doc
cp -r docs $ROOT_DIR
@@ -229,14 +255,13 @@ function release() {
}
function gen_coverage() {
- START_TIME=$(get_now)
-
bazel clean
- generate_test_targets
- echo "$TEST_TARGETS" | xargs bazel test --define ARCH="$(uname -m)" --define CAN_CARD=${CAN_CARD} --cxxopt=-DUSE_ESD_CAN=${USE_ESD_CAN} -c dbg --config=coverage
+ generate_build_targets
+ echo "$BUILD_TARGETS" | grep -v "cnn_segmentation_test" | xargs bazel test $DEFINES -c dbg --config=coverage
if [ $? -ne 0 ]; then
fail 'run test failed!'
fi
+
COV_DIR=data/cov
rm -rf $COV_DIR
files=$(find bazel-out/local-dbg/bin/modules/ -iname "*.gcda" -o -iname "*.gcno" | grep -v external)
@@ -245,6 +270,14 @@ function gen_coverage() {
mkdir -p "$(dirname "$target")"
cp "$f" "$target"
done
+
+ files=$(find bazel-out/local-opt/bin/modules/ -iname "*.gcda" -o -iname "*.gcno" | grep -v external)
+ for f in $files; do
+ target="$COV_DIR/objs/modules/${f##*modules}"
+ mkdir -p "$(dirname "$target")"
+ cp "$f" "$target"
+ done
+
lcov --capture --directory "$COV_DIR/objs" --output-file "$COV_DIR/conv.info"
if [ $? -ne 0 ]; then
fail 'lcov failed!'
@@ -257,15 +290,19 @@ function gen_coverage() {
"tools/*" \
-o $COV_DIR/stripped_conv.info
genhtml $COV_DIR/stripped_conv.info --output-directory $COV_DIR/report
-
- success 'Generated coverage report in $COV_DIR/report/index.html'
+ echo "Generated coverage report in $COV_DIR/report/index.html"
}
function run_test() {
START_TIME=$(get_now)
- generate_test_targets
- echo "$TEST_TARGETS" | xargs bazel test --define "ARCH=$MACHINE_ARCH" --define CAN_CARD=${CAN_CARD} --config=unit_test --cxxopt=-DUSE_ESD_CAN=${USE_ESD_CAN} -c dbg --test_verbose_timeout_warnings
+ generate_build_targets
+ if [ "$USE_GPU" == "1" ]; then
+ echo -e "${RED}Need GPU to run the tests.${NO_COLOR}"
+ echo "$BUILD_TARGETS" | xargs bazel test $DEFINES --config=unit_test -c dbg --test_verbose_timeout_warnings
+ else
+ echo "$BUILD_TARGETS" | grep -v "cnn_segmentation_test" | xargs bazel test $DEFINES --config=unit_test -c dbg --test_verbose_timeout_warnings
+ fi
if [ $? -eq 0 ]; then
success 'Test passed!'
return 0
@@ -276,11 +313,12 @@ function run_test() {
}
function run_cpp_lint() {
- bazel test --config=cpplint //...
+ generate_build_targets
+ echo "$BUILD_TARGETS" | xargs bazel test --config=cpplint -c dbg
}
function run_bash_lint() {
- FILES=$(find "${APOLLO_ROOT_DIR}" -type f -name "*.sh" | grep -v ros | grep -v kernel)
+ FILES=$(find "${APOLLO_ROOT_DIR}" -type f -name "*.sh" | grep -v ros)
echo "${FILES}" | xargs shellcheck
}
@@ -323,23 +361,9 @@ function buildify() {
rm ~/.buildifier
}
-function print_usage() {
- echo 'Usage:
- ./apollo.sh [OPTION]'
- echo 'Options:
- build : run build only
- buildify: fix style of BUILD files
- check: run build/lint/test, please make sure it passes before checking in new code
- clean: runs Bazel clean
- config: run configurator tool
- coverage: generate test coverage report
- doc: generate doxygen document
- lint: run code style check
- print_usage: prints this menu
- release: to build release version
- test: run all the unit tests
- version: current commit and date
- '
+function build_fe() {
+ cd modules/dreamview/frontend
+ yarn build
}
function gen_doc() {
@@ -375,13 +399,13 @@ function build_gnss() {
protoc modules/drivers/gnss/proto/gnss.proto --cpp_out=./
protoc modules/drivers/gnss/proto/imu.proto --cpp_out=./
- protoc modules/drivers/gnss/proto/ins.proto --cpp_out=./
+ protoc modules/drivers/gnss/proto/ins.proto --cpp_out=./ --python_out=./
protoc modules/drivers/gnss/proto/config.proto --cpp_out=./
- protoc modules/drivers/gnss/proto/gnss_status.proto --cpp_out=./
+ protoc modules/drivers/gnss/proto/gnss_status.proto --cpp_out=./ --python_out=./
protoc modules/drivers/gnss/proto/gpgga.proto --cpp_out=./
cd modules
- catkin_make_isolated --install --source drivers \
+ catkin_make_isolated --install --source drivers/gnss \
--install-space "${ROS_PATH}" -DCMAKE_BUILD_TYPE=Release \
--cmake-args --no-warn-unused-cli
find "${ROS_PATH}" -name "*.pyc" -print0 | xargs -0 rm -rf
@@ -391,6 +415,7 @@ function build_gnss() {
rm -rf modules/common/proto/*.pb.h
rm -rf modules/drivers/gnss/proto/*.pb.cc
rm -rf modules/drivers/gnss/proto/*.pb.h
+ rm -rf modules/drivers/gnss/proto/*_pb2.py
rm -rf modules/localization/proto/*.pb.cc
rm -rf modules/localization/proto/*.pb.h
@@ -399,22 +424,93 @@ function build_gnss() {
rm -rf modules/devel_isolated/
}
+function build_velodyne() {
+ CURRENT_PATH=$(pwd)
+ if [ -d "${CURRENT_PATH}/bazel-apollo/external/ros" ]; then
+ ROS_PATH="${CURRENT_PATH}/bazel-apollo/external/ros"
+ else
+ warning "ROS not found. Run apolllo.sh build first."
+ exit 1
+ fi
+
+ source "${ROS_PATH}/setup.bash"
+
+ cd modules
+ catkin_make_isolated --install --source drivers/velodyne \
+ --install-space "${ROS_PATH}" -DCMAKE_BUILD_TYPE=Release \
+ --cmake-args --no-warn-unused-cli
+ find "${ROS_PATH}" -name "*.pyc" -print0 | xargs -0 rm -rf
+ cd -
+
+ rm -rf modules/.catkin_workspace
+ rm -rf modules/build_isolated/
+ rm -rf modules/devel_isolated/
+}
+
function config() {
${APOLLO_ROOT_DIR}/scripts/configurator.sh
}
+function print_usage() {
+ RED='\033[0;31m'
+ BLUE='\033[0;34m'
+ BOLD='\033[1m'
+ NONE='\033[0m'
+
+ echo -e "\n${RED}Usage${NONE}:
+ .${BOLD}/apollo.sh${NONE} [OPTION]"
+
+ echo -e "\n${RED}Options${NONE}:
+ ${BLUE}build${NONE}: run build only
+ ${BLUE}build_opt${NONE}: build optimized binary for the code
+ ${BLUE}build_gpu${NONE}: run build only with Caffe GPU mode support
+ ${BLUE}build_opt_gpu${NONE}: build optimized binary with Caffe GPU mode support
+ ${BLUE}build_fe${NONE}: compile frontend javascript code, this requires all the node_modules to be installed already
+ ${BLUE}buildify${NONE}: fix style of BUILD files
+ ${BLUE}check${NONE}: run build/lint/test, please make sure it passes before checking in new code
+ ${BLUE}clean${NONE}: run Bazel clean
+ ${BLUE}config${NONE}: run configurator tool
+ ${BLUE}coverage${NONE}: generate test coverage report
+ ${BLUE}doc${NONE}: generate doxygen document
+ ${BLUE}lint${NONE}: run code style check
+ ${BLUE}usage${NONE}: print this menu
+ ${BLUE}release${NONE}: build release version
+ ${BLUE}test${NONE}: run all unit tests
+ ${BLUE}version${NONE}: display current commit and date
+ "
+}
+
function main() {
source_apollo_base
apollo_check_system_config
check_machine_arch
check_esd_files
+ DEFINES="--define ARCH=${MACHINE_ARCH} --define CAN_CARD=${CAN_CARD} --cxxopt=-DUSE_ESD_CAN=${USE_ESD_CAN}"
+
case $1 in
check)
+ DEFINES="${DEFINES} --cxxopt=-DCPU_ONLY"
check
;;
build)
- apollo_build
+ DEFINES="${DEFINES} --cxxopt=-DCPU_ONLY"
+ apollo_build_dbg
+ ;;
+ build_opt)
+ DEFINES="${DEFINES} --cxxopt=-DCPU_ONLY"
+ apollo_build_opt
+ ;;
+ build_gpu)
+ DEFINES="${DEFINES} --cxxopt=-DUSE_CAFFE_GPU"
+ apollo_build_dbg
+ ;;
+ build_opt_gpu)
+ DEFINES="${DEFINES} --cxxopt=-DUSE_CAFFE_GPU"
+ apollo_build_opt
+ ;;
+ build_fe)
+ build_fe
;;
buildify)
buildify
@@ -422,6 +518,12 @@ function main() {
buildgnss)
build_gnss
;;
+ build_py)
+ build_py_proto
+ ;;
+ buildvelodyne)
+ build_velodyne
+ ;;
config)
config
;;
@@ -432,6 +534,12 @@ function main() {
run_lint
;;
test)
+ DEFINES="${DEFINES} --cxxopt=-DCPU_ONLY"
+ run_test
+ ;;
+ test_gpu)
+ DEFINES="${DEFINES} --cxxopt=-DUSE_CAFFE_GPU"
+ USE_GPU="1"
run_test
;;
release)
@@ -449,6 +557,9 @@ function main() {
version)
version
;;
+ usage)
+ print_usage
+ ;;
*)
print_usage
;;
diff --git a/apollo_docker.sh b/apollo_docker.sh
index 04d003b4a7b..e47c6573c46 100755
--- a/apollo_docker.sh
+++ b/apollo_docker.sh
@@ -4,6 +4,8 @@
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "${DIR}"
+# the machine type, currently support x86_64, aarch64
+MACHINE_ARCH=$(uname -m)
source ${DIR}/scripts/apollo_base.sh
TIME=$(date +%Y%m%d_%H%M)
@@ -12,23 +14,34 @@ if [ -z "${DOCKER_REPO}" ]; then
fi
function print_usage() {
- echo 'Usage:
- ./apollo_docker.sh [OPTION]'
- echo 'Options:
- build : run build only
- buildify: fix style of BUILD files
- check: run build/lint/test, please make sure it passes before checking in new code
- clean: runs Bazel clean
- coverage: generate test coverage report
- doc: generate doxygen document
- push: pushes the images to Docker hub
- gen: release a docker release image
- lint: run code style check
- release: to build release version
- test: run all the unit tests
- version: current commit and date
- print_usage: prints this menu
- '
+ RED='\033[0;31m'
+ BLUE='\033[0;34m'
+ BOLD='\033[1m'
+ NONE='\033[0m'
+
+ echo -e "\n${RED}Usage${NONE}:
+ .${BOLD}/apollo_docker.sh${NONE} [OPTION]"
+
+ echo -e "\n${RED}Options${NONE}:
+ ${BLUE}build${NONE}: run build only
+ ${BLUE}build_opt${NONE}: build optimized binary for the code
+ ${BLUE}build_gpu${NONE}: run build only with Caffe GPU mode support
+ ${BLUE}build_opt_gpu${NONE}: build optimized binary with Caffe GPU mode support
+ ${BLUE}build_fe${NONE}: compile frontend javascript code, this requires all the node_modules to be installed already
+ ${BLUE}buildify${NONE}: fix style of BUILD files
+ ${BLUE}check${NONE}: run build/lint/test, please make sure it passes before checking in new code
+ ${BLUE}clean${NONE}: run Bazel clean
+ ${BLUE}config${NONE}: run configurator tool
+ ${BLUE}coverage${NONE}: generate test coverage report
+ ${BLUE}doc${NONE}: generate doxygen document
+ ${BLUE}lint${NONE}: run code style check
+ ${BLUE}usage${NONE}: print this menu
+ ${BLUE}release${NONE}: build release version
+ ${BLUE}test${NONE}: run all unit tests
+ ${BLUE}version${NONE}: display current commit and date
+ ${BLUE}push${NONE}: pushes the images to Docker hub
+ ${BLUE}gen${NONE}: release a docker release image
+ "
}
function start_build_docker() {
@@ -39,10 +52,10 @@ function start_build_docker() {
}
function gen_docker() {
- IMG="apolloauto/apollo:run-env-20170712_1738"
+ IMG="apolloauto/apollo:run-${MACHINE_ARCH}-20170917_1439"
RELEASE_DIR=${HOME}/.cache/release
- RELEASE_NAME="${DOCKER_REPO}:release-${TIME}"
- DEFAULT_NAME="${DOCKER_REPO}:release-latest"
+ RELEASE_NAME="${DOCKER_REPO}:release-${MACHINE_ARCH}-${TIME}"
+ DEFAULT_NAME="${DOCKER_REPO}:release-${MACHINE_ARCH}-latest"
docker pull $IMG
docker ps -a --format "{{.Names}}" | grep 'apollo_release' 1>/dev/null
@@ -66,8 +79,8 @@ function gen_docker() {
}
function push() {
- local DEFAULT_NAME="${DOCKER_REPO}:release-latest"
- local RELEASE_NAME="${DOCKER_REPO}:release-${TIME}"
+ local DEFAULT_NAME="${DOCKER_REPO}:release-${MACHINE_ARCH}-latest"
+ local RELEASE_NAME="${DOCKER_REPO}:release-${MACHINE_ARCH}-${TIME}"
docker tag "$DEFAULT_NAME" "$RELEASE_NAME"
docker push "$DEFAULT_NAME"
docker push "$RELEASE_NAME"
diff --git a/docker/dev.aarch64.dockerfile b/docker/dev.aarch64.dockerfile
index 2017bbfb72e..aef8aca1cf8 100644
--- a/docker/dev.aarch64.dockerfile
+++ b/docker/dev.aarch64.dockerfile
@@ -3,7 +3,6 @@ FROM aarch64/ubuntu:16.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update
-## the following commands are OK, skip running again
RUN apt-get install -y build-essential
RUN apt-get install -y apt-utils
RUN apt-get install -y curl
@@ -39,23 +38,23 @@ RUN apt-get install -y oracle-java8-installer
RUN apt-get clean autoclean && apt-get autoremove -y
RUN rm -fr /var/lib/apt/lists/*
-## copy bazel to /usr/local/bin
-RUN mkdir -p /usr/local/bin
-WORKDIR /usr/local/bin/
-RUN wget https://github.com/startcode/bazel-arm64/releases/download/0.4.4/bazel-aarch64 && ln -rs bazel-aarch64 bazel
-
+# Install protobuf 3.3.0
WORKDIR /tmp
-## install protobuf 3.1.0
-RUN wget https://github.com/google/protobuf/releases/download/v3.1.0/protobuf-cpp-3.1.0.tar.gz
-RUN tar xzf protobuf-cpp-3.1.0.tar.gz
-WORKDIR /tmp/protobuf-3.1.0
+RUN wget https://github.com/google/protobuf/releases/download/v3.3.0/protobuf-cpp-3.3.0.tar.gz
+RUN tar xzf protobuf-cpp-3.3.0.tar.gz
+WORKDIR /tmp/protobuf-3.3.0
RUN ./configure --prefix=/usr
RUN make
RUN make install
+RUN chmod 755 /usr/bin/protoc
-# set up node v8.0.0
-RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
-RUN apt-get install -y nodejs
+# Set up node v8.0.0
+WORKDIR /tmp
+RUN wget https://github.com/tj/n/archive/v2.1.0.tar.gz
+RUN tar xzf v2.1.0.tar.gz
+WORKDIR /tmp/n-2.1.0
+RUN make install
+RUN n 8.0.0
## Install required python packages.
WORKDIR /tmp
@@ -67,12 +66,9 @@ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y yarn
-# Remove all temporary files.
-RUN rm -fr /tmp/*
-
ENV ROSCONSOLE_FORMAT '${file}:${line} ${function}() [${severity}] [${time}]: ${message}'
-# install dependency for ros build
+# Install dependency for ros build
RUN sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
RUN apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116
@@ -92,3 +88,38 @@ RUN apt-get install -y zlib1g-dev
## https://stackoverflow.com/questions/25193161/chfn-pam-system-error-intermittently-in-docker-hub-builds
RUN ln -s -f /bin/true /usr/bin/chfn
+
+# Install pcl and opencv, prerequisites for Caffe (CPU_ONLY mode)
+RUN apt-get update
+RUN apt-get install -y libatlas-base-dev
+RUN apt-get install -y libflann-dev
+RUN apt-get install -y libhdf5-serial-dev
+RUN apt-get install -y libicu-dev
+RUN apt-get install -y libleveldb-dev
+RUN apt-get install -y liblmdb-dev
+RUN apt-get install -y libopencv-dev
+RUN apt-get install -y libopenni-dev
+RUN apt-get install -y libqhull-dev
+RUN apt-get install -y libsnappy-dev
+RUN apt-get install -y libvtk5-dev
+RUN apt-get install -y libvtk5-qt4-dev
+RUN apt-get install -y mpi-default-dev
+
+ENV CAFFE_ROOT=/apollo/bazel-genfiles/external/caffe
+RUN echo "$CAFFE_ROOT/lib" >> /etc/ld.so.conf.d/caffe.conf && ldconfig
+
+# Install Opengl
+RUN echo "deb http://ppa.launchpad.net/keithw/glfw3/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/fillwave_ext.list
+RUN echo "deb-src http://ppa.launchpad.net/keithw/glfw3/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/fillwave_ext.list
+RUN apt-get update && apt-get install -y --force-yes libglfw3 libglfw3-dev freeglut3-dev
+
+# Install GLEW
+WORKDIR /tmp
+RUN wget https://github.com/nigels-com/glew/releases/download/glew-2.0.0/glew-2.0.0.zip
+RUN unzip glew-2.0.0.zip
+WORKDIR /tmp/glew-2.0.0
+RUN make && make install
+
+# Remove all temporary files.
+WORKDIR /
+RUN rm -fr /tmp/*
diff --git a/docker/dev.x86_64.dockerfile b/docker/dev.x86_64.dockerfile
index 40fdf74904c..360ea0743de 100644
--- a/docker/dev.x86_64.dockerfile
+++ b/docker/dev.x86_64.dockerfile
@@ -6,6 +6,7 @@ RUN apt-get update && apt-get install -y \
apt-transport-https \
bc \
build-essential \
+ cmake \
cppcheck \
curl \
debconf-utils \
@@ -17,13 +18,14 @@ RUN apt-get update && apt-get install -y \
libcurl4-openssl-dev \
libfreetype6-dev \
lsof \
- python-pip \
python-matplotlib \
+ python-pip \
python-scipy \
python-software-properties \
realpath \
software-properties-common \
unzip \
+ vim \
wget \
zip
@@ -39,29 +41,23 @@ RUN rm -fr /var/lib/apt/lists/*
COPY ./modules/tools/py27_requirements.txt /tmp/
WORKDIR /tmp
-# install protobuf 3.1.0
-RUN wget https://github.com/google/protobuf/releases/download/v3.1.0/protobuf-cpp-3.1.0.tar.gz
-RUN tar xzf protobuf-cpp-3.1.0.tar.gz
-WORKDIR /tmp/protobuf-3.1.0
-RUN ./configure --prefix=/usr
-RUN make
-RUN make install
-
-WORKDIR /tmp
-RUN wget https://github.com/google/protobuf/releases/download/v3.1.0/protoc-3.1.0-linux-x86_64.zip
-RUN unzip protoc-3.1.0-linux-x86_64.zip -d protoc3
-RUN mv protoc3/bin/protoc /usr/bin/
+# install protobuf 3.3.0
+RUN wget https://github.com/google/protobuf/releases/download/v3.3.0/protobuf-cpp-3.3.0.tar.gz
+RUN tar xzf protobuf-cpp-3.3.0.tar.gz
+WORKDIR /tmp/protobuf-3.3.0
+RUN ./configure --prefix=/usr && make && make install
RUN chmod 755 /usr/bin/protoc
-# set up node v8.0.0
+# Set up node v8.0.0
+WORKDIR /tmp
RUN wget https://github.com/tj/n/archive/v2.1.0.tar.gz
RUN tar xzf v2.1.0.tar.gz
WORKDIR /tmp/n-2.1.0
RUN make install
RUN n 8.0.0
-WORKDIR /tmp
# Install required python packages.
+WORKDIR /tmp
RUN pip install -r py27_requirements.txt
# Install yarn
@@ -69,25 +65,22 @@ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y yarn
-# Remove all temporary files.
-RUN rm -fr /tmp/*
-
ENV ROSCONSOLE_FORMAT '${file}:${line} ${function}() [${severity}] [${time}]: ${message}'
-# install dependency for ros build
+# Install dependency for ros build
RUN sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
RUN apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116
RUN apt-get update && apt-get install -y \
- ros-indigo-catkin \
libbz2-dev \
libconsole-bridge-dev \
- liblog4cxx10-dev \
libeigen3-dev \
+ liblog4cxx10-dev \
liblz4-dev \
libpoco-dev \
libproj-dev \
libtinyxml-dev \
libyaml-cpp-dev \
+ ros-indigo-catkin \
sip-dev \
uuid-dev \
zlib1g-dev
@@ -97,3 +90,55 @@ RUN apt-get update && apt-get install shellcheck
# https://stackoverflow.com/questions/25193161/chfn-pam-system-error-intermittently-in-docker-hub-builds
RUN ln -s -f /bin/true /usr/bin/chfn
+
+# Install pcl and opencv, prerequisites for Caffe (CPU_ONLY mode)
+RUN apt-get update && apt-get install -y \
+ libatlas-base-dev \
+ libflann-dev \
+ libhdf5-serial-dev \
+ libicu-dev \
+ libleveldb-dev \
+ liblmdb-dev \
+ libopencv-dev \
+ libopenni-dev \
+ libqhull-dev \
+ libsnappy-dev \
+ libvtk5-dev \
+ libvtk5-qt4-dev \
+ mpi-default-dev
+
+# Install glog
+WORKDIR /tmp
+RUN wget https://github.com/google/glog/archive/v0.3.5.tar.gz
+RUN tar xzf v0.3.5.tar.gz
+WORKDIR /tmp/glog-0.3.5
+RUN ./configure && make && make install
+
+# Install gflags
+WORKDIR /tmp
+RUN wget https://github.com/gflags/gflags/archive/v2.2.0.tar.gz
+RUN tar xzf v2.2.0.tar.gz
+WORKDIR /tmp/gflags-2.2.0
+RUN mkdir build
+WORKDIR /tmp/gflags-2.2.0/build
+RUN CXXFLAGS="-fPIC" cmake .. && make && make install
+
+ENV CAFFE_ROOT=/apollo/bazel-genfiles/external/caffe
+RUN echo "$CAFFE_ROOT/lib" >> /etc/ld.so.conf.d/caffe.conf && ldconfig
+
+# Install Opengl
+RUN echo "deb http://ppa.launchpad.net/keithw/glfw3/ubuntu trusty main" | sudo tee -a /etc/apt/sources.list.d/fillwave_ext.list
+RUN echo "deb-src http://ppa.launchpad.net/keithw/glfw3/ubuntu trusty main" | sudo tee -a /etc/apt/sources.list.d/fillwave_ext.list
+RUN apt-get update && apt-get install -y --force-yes libglfw3 libglfw3-dev freeglut3-dev
+
+# Install GLEW
+WORKDIR /tmp
+RUN wget https://github.com/nigels-com/glew/releases/download/glew-2.0.0/glew-2.0.0.zip
+RUN unzip glew-2.0.0.zip
+WORKDIR /tmp/glew-2.0.0
+RUN make && make install
+RUN ln -s /usr/lib64/libGLEW.so /usr/lib/libGLEW.so
+RUN ln -s /usr/lib64/libGLEW.so.2.0 /usr/lib/libGLEW.so.2.0
+
+# Remove all temporary files.
+RUN rm -fr /tmp/*
diff --git a/docker/run_env.dockerfile b/docker/run_env.dockerfile
index 682e9a838a3..04242fe870e 100644
--- a/docker/run_env.dockerfile
+++ b/docker/run_env.dockerfile
@@ -1,52 +1,62 @@
FROM ubuntu:14.04
RUN apt-get update && apt-get install -y \
- curl \
build-essential \
+ curl \
+ git \
+ libatlas-base-dev \
libboost-all-dev \
+ libconsole-bridge-dev \
libcurl4-openssl-dev \
+ libflann-dev \
libfreetype6-dev \
+ libgflags-dev \
+ libgoogle-glog-dev \
+ libhdf5-serial-dev \
+ libicu-dev \
+ libleveldb-dev \
+ liblmdb-dev \
liblog4cxx10 \
+ liblz4-dev \
+ libopencv-dev \
+ libopenni-dev \
+ libpoco-dev \
+ libproj-dev \
libpython2.7-dev \
+ libqhull-dev \
+ libsnappy-dev \
+ libtinyxml-dev \
+ libvtk5-dev \
+ libvtk5-qt4-dev \
libyaml-cpp-dev \
libyaml-dev \
- python-pip \
+ mpi-default-dev \
python-matplotlib \
+ python-pip \
python-scipy \
python-software-properties \
realpath \
+ software-properties-common \
tmux \
unzip \
- wget \
- libtinyxml-dev \
- libpoco-dev \
- libproj-dev \
- liblz4-dev \
- libconsole-bridge-dev \
- git
+ wget
RUN apt-get clean autoclean && apt-get autoremove -y
RUN rm -fr /var/lib/apt/lists/*
COPY ./modules/tools/py27_requirements.txt /tmp/
WORKDIR /tmp
-# install protobuf 3.1.0
-RUN wget https://github.com/google/protobuf/releases/download/v3.1.0/protobuf-cpp-3.1.0.tar.gz
-RUN tar xzf protobuf-cpp-3.1.0.tar.gz
-WORKDIR /tmp/protobuf-3.1.0
-RUN ./configure --prefix=/usr
-RUN make
-RUN make install
+# install protobuf 3.3.0
+RUN wget https://github.com/google/protobuf/releases/download/v3.3.0/protobuf-cpp-3.3.0.tar.gz
+RUN tar xzf protobuf-cpp-3.3.0.tar.gz
+WORKDIR /tmp/protobuf-3.3.0
+RUN ./configure --prefix=/usr && make && make install
+RUN chmod 755 /usr/bin/protoc
ENV ROSCONSOLE_FORMAT '${file}:${line} ${function}() [${severity}] [${time}]: ${message}'
-WORKDIR /tmp
-RUN wget https://github.com/google/protobuf/releases/download/v3.1.0/protoc-3.1.0-linux-x86_64.zip
-RUN unzip protoc-3.1.0-linux-x86_64.zip -d protoc3
-RUN mv protoc3/bin/protoc /usr/bin/
-RUN chmod 755 /usr/bin/protoc
-
# set up node v8.0.0
+WORKDIR /tmp
RUN wget https://github.com/tj/n/archive/v2.1.0.tar.gz
RUN tar xzf v2.1.0.tar.gz
WORKDIR /tmp/n-2.1.0
@@ -57,8 +67,21 @@ WORKDIR /tmp
# Install required python packages.
RUN pip install -r py27_requirements.txt
-# Remove all temporary files.
-RUN rm -fr /tmp/*
-
# https://stackoverflow.com/questions/25193161/chfn-pam-system-error-intermittently-in-docker-hub-builds
RUN ln -s -f /bin/true /usr/bin/chfn
+
+# install Opengl
+RUN echo "deb http://ppa.launchpad.net/keithw/glfw3/ubuntu trusty main" | sudo tee -a /etc/apt/sources.list.d/fillwave_ext.list
+RUN echo "deb-src http://ppa.launchpad.net/keithw/glfw3/ubuntu trusty main" | sudo tee -a /etc/apt/sources.list.d/fillwave_ext.list
+RUN apt-get update && apt-get install -y --force-yes libglfw3 libglfw3-dev
+
+WORKDIR /tmp
+RUN wget https://github.com/nigels-com/glew/releases/download/glew-2.0.0/glew-2.0.0.zip
+RUN unzip glew-2.0.0.zip
+WORKDIR /tmp/glew-2.0.0
+RUN make && make install
+RUN ln -s /usr/lib64/libGLEW.so /usr/lib/libGLEW.so
+RUN ln -s /usr/lib64/libGLEW.so.2.0 /usr/lib/libGLEW.so.2.0
+
+# Remove all temporary files.
+RUN rm -fr /tmp/*
diff --git a/docker/scripts/dev_create.sh b/docker/scripts/dev_create.sh
index f911ff00225..060710d7639 100755
--- a/docker/scripts/dev_create.sh
+++ b/docker/scripts/dev_create.sh
@@ -16,13 +16,11 @@
# limitations under the License.
###############################################################################
-
TIME=$(date +%Y%m%d_%H%M)
if [ -z "${DOCKER_REPO}" ]; then
DOCKER_REPO=apolloauto/apollo
fi
-
APOLLO_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
ARCH=$(uname -m)
TAG="dev-${ARCH}-${TIME}"
@@ -31,5 +29,3 @@ TAG="dev-${ARCH}-${TIME}"
docker build -t "${DOCKER_REPO}:${TAG}" \
-f "${APOLLO_ROOT}/docker/dev.${ARCH}.dockerfile" \
"${APOLLO_ROOT}"
-
-sed -i "s/dev-${ARCH}-.*\"/${TAG}\"/g" ${APOLLO_ROOT}/docker/scripts/dev_start.sh
diff --git a/docker/scripts/dev_into.sh b/docker/scripts/dev_into.sh
index eb3d7e4d664..03adf78ca24 100755
--- a/docker/scripts/dev_into.sh
+++ b/docker/scripts/dev_into.sh
@@ -16,7 +16,6 @@
# limitations under the License.
###############################################################################
-
xhost +local:root 1>/dev/null 2>&1
docker exec \
-u $USER \
diff --git a/docker/scripts/dev_start.sh b/docker/scripts/dev_start.sh
index e2031945bfd..d53ef72b8e7 100755
--- a/docker/scripts/dev_start.sh
+++ b/docker/scripts/dev_start.sh
@@ -18,7 +18,7 @@
VERSION=""
ARCH=$(uname -m)
-VERSION_X86_64="dev-x86_64-20170707_1129"
+VERSION_X86_64="dev-x86_64-20170919_1058"
VERSION_AARCH64="dev-aarch64-20170712_1533"
if [[ $# == 1 ]];then
VERSION=$1
@@ -36,38 +36,19 @@ if [ -z "${DOCKER_REPO}" ]; then
fi
IMG=${DOCKER_REPO}:$VERSION
-LOCAL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
+APOLLO_ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
-if [ ! -e "${LOCAL_DIR}/data/log" ]; then
- mkdir -p "${LOCAL_DIR}/data/log"
-fi
-if [ ! -e "${LOCAL_DIR}/data/bag" ]; then
- mkdir -p "${LOCAL_DIR}/data/bag"
-fi
-if [ ! -e "${LOCAL_DIR}/data/core" ]; then
- mkdir -p "${LOCAL_DIR}/data/core"
+if [ ! -e /apollo ]; then
+ sudo ln -sf ${APOLLO_ROOT_DIR} /apollo
fi
-source ${LOCAL_DIR}/scripts/apollo_base.sh
+echo "/apollo/data/core/core_%e.%p" | sudo tee /proc/sys/kernel/core_pattern
-function find_device() {
- # ${1} = device pattern
- local device_list=$(find /dev -name "${1}")
- if [ -z "${device_list}" ]; then
- warning "Failed to find device with pattern \"${1}\" ..."
- else
- local devices=""
- for device in $(find /dev -name "${1}"); do
- ok "Found device: ${device}."
- devices="${devices} --device ${device}:${device}"
- done
- echo "${devices}"
- fi
-}
+source ${APOLLO_ROOT_DIR}/scripts/apollo_base.sh
function main(){
docker pull $IMG
-
+
docker ps -a --format "{{.Names}}" | grep 'apollo_dev' 1>/dev/null
if [ $? == 0 ]; then
docker stop apollo_dev 1>/dev/null
@@ -80,14 +61,7 @@ function main(){
display="${DISPLAY}"
fi
-
- # setup CAN device
- if [ ! -e /dev/can0 ]; then
- sudo mknod --mode=a+rw /dev/can0 c 52 0
- fi
- # enable coredump
- echo "${LOCAL_DIR}/data/core/core_%e.%p" | sudo tee /proc/sys/kernel/core_pattern
-
+ setup_device
local devices=""
devices="${devices} $(find_device ttyUSB*)"
@@ -95,6 +69,7 @@ function main(){
devices="${devices} $(find_device can*)"
devices="${devices} $(find_device ram*)"
devices="${devices} $(find_device loop*)"
+ devices="${devices} $(find_device nvidia*)"
USER_ID=$(id -u)
GRP=$(id -g -n)
GRP_ID=$(id -g)
@@ -108,6 +83,7 @@ function main(){
fi
docker run -it \
-d \
+ --privileged \
--name apollo_dev \
-e DISPLAY=$display \
-e DOCKER_USER=$USER \
@@ -116,7 +92,7 @@ function main(){
-e DOCKER_GRP=$GRP \
-e DOCKER_GRP_ID=$GRP_ID \
-v /tmp/.X11-unix:/tmp/.X11-unix:rw \
- -v $LOCAL_DIR:/apollo \
+ -v $APOLLO_ROOT_DIR:/apollo \
-v /media:/media \
-v $HOME/.cache:${DOCKER_HOME}/.cache \
-v /etc/localtime:/etc/localtime:ro \
diff --git a/docker/scripts/release_into.sh b/docker/scripts/release_into.sh
index 74e97cc2150..97f331f14bf 100755
--- a/docker/scripts/release_into.sh
+++ b/docker/scripts/release_into.sh
@@ -16,7 +16,6 @@
# limitations under the License.
###############################################################################
-
xhost +local:root 1>/dev/null 2>&1
docker exec \
-u $USER \
diff --git a/docker/scripts/release_start.sh b/docker/scripts/release_start.sh
index eeca314408e..e869af6ab2f 100755
--- a/docker/scripts/release_start.sh
+++ b/docker/scripts/release_start.sh
@@ -17,33 +17,15 @@
###############################################################################
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-
-if [ -e "$DIR/../../scripts/apollo_base.sh" ]; then
- # run from source
- APOLLO_ROOT_DIR=$(cd "${DIR}/../.." && pwd)
-else
- # run from script only
- APOLLO_ROOT_DIR=~
-fi
+APOLLO_ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}")/../.." && pwd )"
+# the machine type, currently support x86_64, aarch64
+MACHINE_ARCH=$(uname -m)
source $APOLLO_ROOT_DIR/scripts/apollo_base.sh
-export APOLLO_ROOT_DIR
-
-if [ ! -e "${APOLLO_ROOT_DIR}/data/log" ]; then
- mkdir -p "${APOLLO_ROOT_DIR}/data/log"
-fi
-if [ ! -e "${APOLLO_ROOT_DIR}/data/bag" ]; then
- mkdir -p "${APOLLO_ROOT_DIR}/data/bag"
-fi
-if [ ! -e "${APOLLO_ROOT_DIR}/data/core" ]; then
- mkdir -p "${APOLLO_ROOT_DIR}/data/core"
-fi
-
-echo "APOLLO_ROOT_DIR=$APOLLO_ROOT_DIR"
+echo "/apollo/data/core/core_%e.%p" | sudo tee /proc/sys/kernel/core_pattern
-VERSION=release-20170712_1820
+VERSION="release-${MACHINE_ARCH}-latest"
if [[ $# == 1 ]];then
VERSION=$1
fi
@@ -52,21 +34,18 @@ if [ -z "${DOCKER_REPO}" ]; then
fi
IMG=${DOCKER_REPO}:$VERSION
+DATA_DIR="${HOME}/data"
+if [ ! -e "${DATA_DIR}/log" ]; then
+ mkdir -p "${DATA_DIR}/log"
+fi
+
+if [ ! -e "${DATA_DIR}/bag" ]; then
+ mkdir -p "${DATA_DIR}/bag"
+fi
-function find_device() {
- # ${1} = device pattern
- local device_list=$(find /dev -name "${1}")
- if [ -z "${device_list}" ]; then
- warning "Failed to find device with pattern \"${1}\" ..."
- else
- local devices=""
- for device in $(find /dev -name "${1}"); do
- ok "Found device: ${device}."
- devices="${devices} --device ${device}:${device}"
- done
- echo "${devices}"
- fi
-}
+if [ ! -e "${DATA_DIR}/core" ]; then
+ mkdir -p "${DATA_DIR}/core"
+fi
function main() {
docker pull "$IMG"
@@ -77,13 +56,7 @@ function main() {
docker rm -f apollo_release 1>/dev/null
fi
- # setup CAN device
- if [ ! -e /dev/can0 ]; then
- sudo mknod --mode=a+rw /dev/can0 c 52 0
- fi
-
- # enable coredump
- echo "${APOLLO_ROOT_DIR}/data/core/core_%e.%p" | sudo tee /proc/sys/kernel/core_pattern
+ setup_device
local devices=""
devices="${devices} $(find_device ttyUSB*)"
@@ -91,6 +64,7 @@ function main() {
devices="${devices} $(find_device can*)"
devices="${devices} $(find_device ram*)"
devices="${devices} $(find_device loop*)"
+ devices="${devices} $(find_device nvidia*)"
local display=""
if [[ -z ${DISPLAY} ]];then
display=":0"
@@ -113,7 +87,7 @@ function main() {
--name apollo_release \
--net host \
-v /media:/media \
- -v ${APOLLO_ROOT_DIR}/data:/apollo/data \
+ -v ${HOME}/data:/apollo/data \
-v /tmp/.X11-unix:/tmp/.X11-unix:rw \
-v /etc/localtime:/etc/localtime:ro \
-v $HOME/.cache:${DOCKER_HOME}/.cache \
@@ -134,7 +108,11 @@ function main() {
$IMG
if [ "${USER}" != "root" ]; then
docker exec apollo_release bash -c "/apollo/scripts/docker_adduser.sh"
- docker exec apollo_release bash -c "chown -R ${USER}:${GRP} /apollo"
+ docker exec apollo_release bash -c "chown -R ${USER}:${GRP} /apollo/data"
+ docker exec apollo_release bash -c "chmod a+rw -R /apollo/ros/share/velodyne_pointcloud"
+ docker exec apollo_release bash -c "chmod a+rw -R /apollo/modules/common/data"
+ docker exec apollo_release bash -c "chmod a+rw -R /apollo/ros/share/gnss_driver"
+ docker exec apollo_release bash -c "chmod a+rw -R /apollo/ros/share/velodyne"
fi
docker exec -u ${USER} -it apollo_release "/apollo/scripts/hmi.sh"
}
diff --git a/docker/scripts/run_env_create.sh b/docker/scripts/run_env_create.sh
index f3ab1bb8b9b..8f767d04052 100755
--- a/docker/scripts/run_env_create.sh
+++ b/docker/scripts/run_env_create.sh
@@ -31,5 +31,3 @@ TAG="run-env-${TIME}"
docker build -t "${DOCKER_REPO}:${TAG}" \
-f "${APOLLO_ROOT}/docker/run_env.dockerfile" \
"${APOLLO_ROOT}"
-
-sed -i "s/run-env.*\"/${TAG}\"/g" ${APOLLO_ROOT}/apollo_docker.sh
diff --git a/docs/demo_guide/demo.bag b/docs/demo_guide/demo.bag
index fa59566345d..f531ff79021 100644
Binary files a/docs/demo_guide/demo.bag and b/docs/demo_guide/demo.bag differ
diff --git a/docs/demo_guide/demo_1.5.bag b/docs/demo_guide/demo_1.5.bag
new file mode 100644
index 00000000000..7d0eef2b56e
Binary files /dev/null and b/docs/demo_guide/demo_1.5.bag differ
diff --git a/docs/howto/how_to_add_a_new_evaluator_in_prediction_module.md b/docs/howto/how_to_add_a_new_evaluator_in_prediction_module.md
new file mode 100644
index 00000000000..a776026c983
--- /dev/null
+++ b/docs/howto/how_to_add_a_new_evaluator_in_prediction_module.md
@@ -0,0 +1,96 @@
+# How to add a new evaluator in prediction module
+
+## Introduction
+Evaluator generates features (from the raw information of obstacles and the ego vehicle) to get the model output by applying the pre-trained deep learning model.
+
+## Steps to add a new evaluator
+Please follow the steps to add a new evaluator named `NewEvaluator`.
+* Add a field in proto
+* Define a class that inherits `Evaluator`
+* Implement the class `NewEvaluator`
+* Update prediction conf
+* Upate evaluator manager
+
+### Step 1: Add a field in proto
+Assume the new evaluating result named `new_output` and also assume its type is `int32`. If the output is related directly to the obstacles, you can add it into `modules/prediction/proto/feature.proto` like this:
+```cpp
+message Feature {
+ // Other existing features
+ optional int32 new_output = 1000;
+}
+```
+If the output is related to the lane sequences, please add it into `modules/prediction/proto/lane_graph.proto` like this:
+```cpp
+message LaneSequence {
+ // Other existing features
+ optional int32 new_output = 1000;
+}
+```
+
+### Step 2: Define a class that inherits `Evaluator`
+Create a new file named `new_evaluator.h` in the folder `modules/prediction/evaluator/vehicle`. And define it like this:
+```cpp
+
+#include "modules/prediction/evaluator/evaluator.h"
+
+namespace apollo {
+namespace prediction {
+
+class MLPEvaluator : public Evaluator {
+ public:
+ MLPEvaluator();
+ virtual ~MLPEvaluator();
+ void Evaluate(Obstacle* obstacle_ptr) override;
+ // Other useful functions and fields.
+};
+
+} // namespace prediction
+} // namespace apollo
+```
+
+### Step 3 Implement the class `NewEvaluator`
+Create a new file named `new_evaluator.cc` in the same folder of `new_evaluator.h`. Implement it like this:
+```cpp
+#include "modules/prediction/evaluator/vehicle/new_evaluator.h"
+
+namespace apollo {
+namespace prediction {
+
+NewEvaluator::NewEvaluator() {
+ // Implement
+}
+
+NewEvaluator::~NewEvaluator() {
+ // Implement
+}
+
+NewEvaluator::Evaluate(Obstacle* obstacle_ptr)() {
+ // Extract features
+ // Compute new_output by applying pre-trained model
+}
+
+// Other functions
+
+} // namespace prediction
+} // namespace apollo
+
+```
+### Step 4: Update prediction conf
+In the file `modules/prediction/conf/prediction_conf.pb.txt`, update the field `evaluator_type` like this:
+```
+obstacle_conf {
+ obstacle_type: VEHICLE
+ obstacle_status: ON_LANE
+ evaluator_type: NEW_EVALUATOR
+ predictor_type: NEW_PREDICTOR
+}
+```
+
+### Step 5: Upate evaluator manager
+Update `vehicle_on_lane_evaluator_` in `modlues/prediction/evaluator/evaluator_manager.h` like this:
+```cpp
+ ObstacleConf::EvaluatorType vehicle_on_lane_evaluator_ =
+ ObstacleConf::NEW_EVALUATOR;
+```
+
+After this procedure, the new evaluator will be created.
diff --git a/docs/howto/how_to_add_a_new_predictor_in_prediction_module.md b/docs/howto/how_to_add_a_new_predictor_in_prediction_module.md
new file mode 100644
index 00000000000..10dc5f572b6
--- /dev/null
+++ b/docs/howto/how_to_add_a_new_predictor_in_prediction_module.md
@@ -0,0 +1,65 @@
+# How to add a new predictor in prediction module
+
+## Introduction
+Predictor generates the predicted trajectory for each obstacle. Here assume we want to add a new predictor for vehicle, for other types of obstacles, the procedure is very similar.
+
+## Steps to add a new predictor
+Please follow the steps to add a new predictor named `NewPredictor`.
+
+### Step 1: Define a class that inherits `Predictor`
+Create a new file named `new_predictor.h` in the folder `modules/prediction/predictor/vehicle`. And define it like this:
+```cpp
+
+#include "modules/prediction/predictor/predictor.h"
+
+namespace apollo {
+namespace prediction {
+
+class NewPredictor : public Predictor {
+ public:
+ void Predict(Obstacle* obstacle) override;
+ // Other useful functions and fields.
+};
+
+} // namespace prediction
+} // namespace apollo
+```
+
+### Step 2 Implement the class `NewPredictor`
+Create a new file named `new_predictor.cc` in the same folder of `new_predictor.h`. Implement it like this:
+```cpp
+#include "modules/prediction/predictor/vehicle/new_predictor.h"
+
+namespace apollo {
+namespace prediction {
+
+NewPredictor::Predict(Obstacle* obstacle)() {
+ // Get the results from evaluator
+ // Generate the predicted trajectory
+}
+
+// Other functions
+
+} // namespace prediction
+} // namespace apollo
+
+```
+### Step 3: Update prediction conf
+In the file `modules/prediction/conf/prediction_conf.pb.txt`, update the field `predictor_type` like this:
+```
+obstacle_conf {
+ obstacle_type: VEHICLE
+ obstacle_status: ON_LANE
+ evaluator_type: NEW_EVALUATOR
+ predictor_type: NEW_PREDICTOR
+}
+```
+
+### Step 4: Upate predictor manager
+Update `vehicle_on_lane_predictor_` in `modlues/prediction/predictor/predictor_manager.h` like this:
+```cpp
+ObstacleConf::PredictorType vehicle_on_lane_predictor_ =
+ ObstacleConf::NEW_PREDICTOR;
+```
+
+After this procedure, the new predictor will be created.
diff --git a/docs/quickstart/apollo_1_0_quick_start_cn.md b/docs/quickstart/apollo_1_0_quick_start_cn.md
index 1e8ed7d97d4..4f4bad3483c 100644
--- a/docs/quickstart/apollo_1_0_quick_start_cn.md
+++ b/docs/quickstart/apollo_1_0_quick_start_cn.md
@@ -25,14 +25,14 @@ _Apollo 快速入门指南 1.0_ 提供了所有关于了解、安装以及构建
下表列出了本文档中使用的归约:
-| **Icon** | **描述** |
+| **Icon** | **描述** |
| ----------------------------------- | ---------------------------------------- |
-| **粗体** | 重要 |
-| `等宽字体` | 代码,类型数据 |
-| _斜体_ | 文件标题,章节和标题使用的术语 |
-| ![info](images/info_icon.png) | **Info** 包含可能有用的信息。忽略信息图标没有消极的后果 |
-| ![tip](images/tip_icon.png) | **Tip**. 包括有用的提示或可能有助于您完成任务的捷径。 |
-| ![online](images/online_icon.png) | **Online**. 提供指向特定网站的链接,您可以在其中获取更多信息 |
+| **粗体** | 重要 |
+| `等宽字体` | 代码,类型数据 |
+| _斜体_ | 文件标题,章节和标题使用的术语 |
+| ![info](images/info_icon.png) | **Info** 包含可能有用的信息。忽略信息图标没有消极的后果 |
+| ![tip](images/tip_icon.png) | **Tip**. 包括有用的提示或可能有助于您完成任务的捷径。 |
+| ![online](images/online_icon.png) | **Online**. 提供指向特定网站的链接,您可以在其中获取更多信息 |
| ![warning](images/warning_icon.png) | **Warning**. 包含**不**能忽略的信息,或者执行某个任务或步骤时,您将面临失败风险 |
# 概览
@@ -140,7 +140,7 @@ bash docker/scripts/release_into.sh
[Apollo's Coordinate System](https://github.com/ApolloAuto/apollo/blob/master/docs/specs/coordination.pdf) 找到您当地的区号。例如,如果你在北京,中国,你必须设置`+zone=50`。
5. 通过修改以下文件,为GNSS驱动程序设置实时运动(RTK)基站:
- `./ros/share/gnss_driver/conf/gnss_conf_mkz.txt`
+ `./ros/share/gnss_driver/conf/gnss_conf_mkz.txt`
有关典型的RTK设置,请参阅以下示例:
@@ -191,7 +191,7 @@ bash docker/scripts/release_commit.sh
- 打开平台车辆
- 打开工业PC机(IPC).
- ![](images/ipc_power_on.png)
+ ![](images/IPC_powerbutton.png)
- 通过按住电源按钮打开调制解调器电源,直到指示灯亮起
- 设置IPC的网络配置:静态IP(例如192.168.10.6),子网掩码(例如255.255.255.0)和网关(例如192.168.10.1)
- 配置您的DNS服务器IP(例如,8.8.8.8)。
diff --git a/docs/quickstart/apollo_1_5_hardware_system_installation_guide.md b/docs/quickstart/apollo_1_5_hardware_system_installation_guide.md
new file mode 100644
index 00000000000..c1c24c0c901
--- /dev/null
+++ b/docs/quickstart/apollo_1_5_hardware_system_installation_guide.md
@@ -0,0 +1,889 @@
+# Apollo 1.5 Hardware and System Installation Guide
+
+* [About This Guide](#about-this-guide)
+ * [Document Conventions](#document-conventions)
+* [Introduction](#introduction)
+ * [Documentation](#documentation)
+* [Key Hardware Components](#key-hardware-components)
+ * [Additional Components Required](#additional-components-required)
+ * [Onboard Computer System - IPC](#onboard-computer-system---ipc)
+ * [IPC Configuration](#ipc-configuration)
+ * [IPC Front and Rear Views](#ipc-front-and-rear-views)
+ * [Controller Area Network (CAN) Card](#controller-area-network-(can)-card)
+ * [Global Positioning System (GPS) and Inertial Measurement Unit (IMU)](#global-positioning-system-(gps)-and-inertial-measurement-unit-(imu))
+
+ * [Option 1: The NovAtel SPAN-IGM-A1](#option-1:-the-novatel-span-igm-a1)
+ * [Option 2: The NovAtel SPAN ProPak6 and NovAtel IMU-IGM-A1](#option-2:-the-novatel-span-propak6-and-novatel-imu-igm-a1)
+ * [The GPS Receiver/Antenna](#the-gps-receiver/antenna)
+* [Overview of the Installation Tasks](#overview-of-the-installation-tasks)
+* [Steps for the Installation Tasks](#steps-for-the-installation-tasks)
+ * [At the Office](#at-the-office)
+ * [Preparing the IPC](#preparing-the-ipc)
+ * [Installing the Software for the IPC](#installing-the-software-for-the-ipc)
+ * [In the Vehicle](#in-the-vehicle)
+ * [Prerequisites](#prerequisites)
+ * [Diagrams of the Major Component Installations](#diagrams-of-the-major-component-installations)
+ * [Installing the GPS Receiver and Antenna](#installing-the-gps-receiver-and-antenna)
+ * [Installing the Light Detection and Ranging System (LiDAR)](#installing-the-light-detection-and-ranging-system-(lidar))
+ * [Installing the IPC](#installing-the-ipc)
+ * [Configuring the GPS and IMU](#configuring-the-gps-and-imu)
+* [Setting up the Network](#setting-up-the-network)
+ * [Recommendations](#recommendations)
+* [Additional Tasks Required](#additional-tasks-required)
+* [Next Steps](#next-steps)
+
+
+# About This Guide
+
+The *Apollo 1.5 Hardware and System Installation Guide* provides the instructions to install all of the hardware components and system software for the **Apollo Project **. The system installation information included pertains to the procedures to download and install the Apollo Linux Kernel.
+
+## Document Conventions
+
+The following table lists the conventions that are used in this document:
+
+| **Icon** | **Description** |
+| ----------------------------------- | ---------------------------------------- |
+| **Bold** | Emphasis |
+| `Mono-space font` | Code, typed data |
+| _Italic_ | Titles of documents, sections, and headings Terms used |
+| ![info](images/info_icon.png) | **Info** Contains information that might be useful. Ignoring the Info icon has no negative consequences. |
+| ![tip](images/tip_icon.png) | **Tip**. Includes helpful hints or a shortcut that might assist you in completing a task. |
+| ![online](images/online_icon.png) | **Online**. Provides a link to a particular web site where you can get more information. |
+| ![warning](images/warning_icon.png) | **Warning**. Contains information that must **not** be ignored or you risk failure when you perform a certain task or step. |
+
+# Introduction
+
+The **Apollo Project** is an initiative that provides an open, complete, and reliable software platform for Apollo partners in the automotive and autonomous driving industries. The aim of this project is to enable these entities to develop their own self-driving systems based on Apollo software stack.
+
+## Documentation
+
+The following set of documentation describes Apollo 1.5:
+
+- ***[Apollo Hardware and System Installation Guide]*** ─ Provides the instructions to install the hardware components and the system software for the vehicle:
+
+ - **Vehicle**:
+
+ - Industrial PC (IPC)
+ - Global Positioning System (GPS)
+ - Inertial Measurement Unit (IMU)
+ - Controller Area Network (CAN) card
+ - GPS Antenna
+ - GPS Receiver
+ - Light Detection and Ranging System (LiDAR)
+
+ - **Software**:
+ - Ubuntu Linux
+ - Apollo Linux Kernel
+ - Nvidia GPU Driver
+
+- ***[Apollo Quick Start Guide]*** ─ A combination tutorial and roadmap that provide the complete set of end-to-end instructions. The Quick Start Guide also provides links to additional documents that describe the conversion of a regular car to an autonomous-driving vehicle.
+
+
+# Key Hardware Components
+
+The key hardware components to install include:
+
+- Onboard computer system ─ Neousys Nuvo-6108GC
+- Controller Area Network (CAN) Card ─ ESD CAN-PCIe/402-1
+- General Positioning System (GPS) and Inertial Measurement Unit (IMU) ─
+ You can select one of the following options:
+ - NovAtel SPAN-IGM-A1
+ - NovAtel SPAN® ProPak6™ and NovAtel IMU-IGM-A1
+- Light Detection and Ranging System (LiDAR) ─ Velodyne HDL-64E S3
+
+## Additional Components Required
+
+You need to provide these additional components for the Additional Tasks Required:
+
+- A 4G router for Internet access
+- A monitor, keyboard, and mouse for debugging at the car onsite
+- Cables:a Digital Visual Interface (DVI) cable (optional), a customized cable for GPS-LiDAR time synchronization
+- Apple iPad Pro: 9.7-inch, Wi-Fi (optional)
+
+The features of the key hardware components are presented in the subsequent sections.
+
+## Onboard Computer System - IPC
+
+The onboard computer system is an industrial PC (IPC) for the autonomous vehicle and uses the **NeousysNuvo-6108GC** that is powered by a sixth-generation Intel Xeon E3 1275 V5 CPU.
+
+The Neousys Nuvo-6108GC is the central unit of the autonomous driving system (ADS).
+
+### IPC Configuration
+
+Configure the IPC as follows:
+
+- ASUS GTX1080 GPU-A8G-Gaming GPU Card
+- 32GB DDR4 RAM
+- PO-280W-OW 280W AC/DC power adapter
+- 2.5" SATA Hard Disk 1TB 7200rpm
+
+### IPC Front and Side Views
+
+The front and rear views of the IPC are shown with the Graphics Processing Unit (GPU) installed in the following pictures:
+
+The front view of the Nuvo-6108GC:
+
+![ipc_front](images/IPC-6108GC-front-side.jpg)
+
+The side view of the Nuvo-6108GC:
+
+![ipc_back](images/IPC-6108GC-left-side.jpg)
+
+For more information about the Nuvo-6108GC, see:
+
+![online](images/online_icon.png)
+Neousys Nuvo-6108GC Product Page:
+
+[http://www.neousys-tech.com/en/product/application/rugged-embedded/nuvo-6108gc-gpu-computing](http://www.neousys-tech.com/en/product/application/rugged-embedded/nuvo-6108gc-gpu-computing)
+![online](images/online_icon.png)
+
+
+Neousys Nuvo-6108GC-Manual:
+
+**[Link Unavailable yet]**
+
+## Controller Area Network (CAN) Card
+
+The CAN card to use with the IPC is **ESD** **CAN-PCIe/402**.
+
+![can_card](images/can_card.png)
+
+For more information about the CAN-PCIe/402, see:
+
+![online](images/online_icon.png) ESD CAN-PCIe/402 Product Page:
+
+[https://esd.eu/en/products/can-pcie402](https://esd.eu/en/products/can-pcie402)
+
+
+
+## Global Positioning System (GPS) and Inertial Measurement Unit (IMU)
+
+There are **two** GPS-IMU **options** available,and the choice depends upon the one that most fits your needs:
+
+- **Option 1: NovAtel SPAN-IGM-A1**
+- **Option 2: NovAtel SPAN® ProPak6™ and NovAtel IMU-IGM-A1**
+
+### Option 1: The NovAtel SPAN-IGM-A1
+
+The NovAtel SPAN-IGM-A1 is an integrated, single-box solution that offers tightly coupled Global Navigation Satellite System (GNSS) positioning and inertial navigation featuring the NovAtel OEM615 receiver.
+
+![novatel_imu](images/Novatel_imu.png)
+
+For more information about the NovAtel SPAN-IGM-A1, see:
+
+ ![online](images/online_icon.png) NovAtel SPAN-IGM-A1 Product Page:
+
+[https://www.novatel.com/products/span-gnss-inertial-systems/span-combined-systems/span-igm-a1/](https://www.novatel.com/products/span-gnss-inertial-systems/span-combined-systems/span-igm-a1/)
+
+### Option 2: The NovAtel SPAN ProPak6 and NovAtel IMU-IGM-A1
+
+NovAtel ProPak6 is a standalone GNSS receiver. It works with a separate NovAtel- supported IMU (in this case, the NovAtel IMU-IGM-A1)to provide localization.
+
+The ProPak6 provides the latest and most sophisticated enclosure product manufactured by NovAtel.
+
+The IMU-IGM-A1 is an IMU that pairs with a SPAN-enabled GNSS receiver such as the SPAN ProPak6.
+
+![novatel_pp6](images/Novatel_pp6.png)
+
+For more information about the NovAtel SPAN ProPak6 and the IMU-IGM-A1, see:
+
+ ![online](images/online_icon.png) NovAtel ProPak6 Installation & Operation Manual:
+
+[https://www.novatel.com/assets/Documents/Manuals/OM-20000148.pdf](https://www.novatel.com/assets/Documents/Manuals/OM-20000148.pdf)
+
+ ![online](images/online_icon.png)NovAtel IMU-IGM-A1 Product Page:
+
+[https://www.novatel.com/products/span-gnss-inertial-systems/span-imus/span-mems-imus/imu-igm-a1/#overview](https://www.novatel.com/products/span-gnss-inertial-systems/span-imus/span-mems-imus/imu-igm-a1/#overview)
+
+## The GPS Receiver/Antenna
+
+The GPS Receiver/Antenna used with the GPS-IMU component is the **NovAtel GPS-703-GGG-HV**.
+
+**NOTE: **The GPS NovAtelGPS-703-GGG-HV works with either model of the two GPS-IMU options that are described in the previous section, Global Positioning System (GPS) and Inertial Measurement Unit (IMU).
+
+![gps_receiver](images/gps_receiver.png)
+
+For more information about the NovAtel GPS-703-GGG-HV, see:
+
+ ![online](images/online_icon.png) NovAtel GPS-703-GGG-HV Product Page:
+
+[https://www.novatel.com/products/gnss-antennas/high-performance-gnss-antennas/gps-703-ggg-hv/](https://www.novatel.com/products/gnss-antennas/high-performance-gnss-antennas/gps-703-ggg-hv/)
+
+## Light Detection and Ranging System (LiDAR)
+The 64 line LiDAR system **HDL-64E S3** is available from Velodyne Lidars, Inc.
+
+![lidar_image](images/lidar_pic.png)
+
+**Key Features:**
+
+- 64 Channels
+- 120m range
+- 2.2 Million Points per Second
+- 360° Horizontal FOV
+- 26.9° Vertical FOV
+- 0.08° angular resolution (azimuth)
+- <2cm accuracy
+- ~0.4° Vertical Resolution
+- User selectable frame rate
+- Rugged Design
+
+![online](images/online_icon.png)Webpage for Velodyne HDL-64E S3:
+http://velodynelidar.com/hdl-64e.html
+
+# Overview of the Installation Tasks
+
+Installing the hardware and the software components involves these tasks:
+
+**AT THE OFFICE:**
+1. Prepare and then install the Controller Area Network (CAN) card by first repositioning the CAN card termination jumper before you insert the card into the slot.
+
+2. Install the hard drive (if none was pre-installed) in the IPC.
+
+ You can also choose to replace a pre-installed hard drive if you prefer.
+
+ **Recommendations** :
+ - Install a Solid-State Drive (SSD) for better reliability.
+ - Use a high-capacity drive if you need to collect driving data.
+
+3. Prepare the IPC for powering up:
+ a. Attach the power cable to the power connector (terminal block).
+ b. Connect the monitor, Ethernet, keyboard, and mouse to the IPC.
+ c. Connect the IPC to a power source.
+
+4. Install the software on the IPC (some Linux experience is required):
+ a. Install Ubuntu Linux.
+ b. Install the Apollo Linux kernel.
+
+**IN THE VEHICLE:**
+
+- Make sure that all the modifications for the vehicle, which are listed in the section Prerequisites, have been performed.
+
+- Install the major components (according to the illustrations and the instructions included in this document):
+ - GPS Antenna
+ - IPC
+ - GPS Receiver
+ - LiDAR
+
+The actual steps to install all of the hardware and software components are detailed in the section, Steps for the Installation Tasks.
+
+# Steps for the Installation Tasks
+
+This section describes the steps to install:
+
+- The key hardware and software components
+- The hardware in the vehicle
+
+## At the Office
+
+Perform these tasks:
+
+- Prepare the IPC:
+ - Install the CAN card
+ - Install or replace the hard drive
+ - Prepare the IPC for powering up
+
+- Install the software for the IPC:
+ - Ubuntu Linux
+ - Apollo Kernel
+ - Nvidia GPU Driver
+
+### Preparing the IPC
+Follow these steps:
+1. Prepare and install the Controller Area Network (CAN) card:
+ In the Neousys Nuvo-6108GC, ASUS® GTX-1080GPU-A8G-GAMING GPU card is pre-installed into one of the three PCI slots. We still need to install a CAN card into a PCI slot.
+ a. Locate and unscrew the eight screws (shown in the brown squares or pointed by brown arrows) on the side of computer:
+ ![Positions_of_Screws](images/IPC-6108GC-Screw-Positions_labeled.png)b. Remove the cover from the IPC. 3 PCI slots (one occupied by the graphic card) locate on the base:
+
+ ![removing the cover](images\Removing_the_cover.JPG)
+
+ ![Before installing the CAN card](images/Before_installing_the_can_card.png)
+
+ c. Set the CAN card termination jumper by removing the red jumper cap (shown in yellow circles) from its default location and placing it at its termination position:
+
+ ![prepare_can_card](images/prepare_can_card.png)
+
+ **![warning](images/warning_icon.png)WARNING**: The CAN card will not work if the termination jumper is not set correctly.
+
+ d. Insert the CAN card into the slot in the IPC:
+
+ ![installed CAN](images/After installing the CAN Card.png)
+
+ e. Reinstall the cover for the IPC
+
+ ![IPC-6108GC-Screw-Positions.png](images/IPC-6108GC-Screw-Positions.png)
+
+2. Prepare the IPC for powering up:
+
+ a. Attach the power cable to the power connector (terminal block) that comes with the IPC:
+
+ ![warning_icon](images/warning_icon.png)**WARNING**: Make sure that the positive(labeled **R** for red) and the negative(labeled **B** for black) wires of the power cable are inserted into the correct holes on the power terminal block.
+
+3. ![ipc_power_RB](images/ipc_power_RB.png)
+
+ b. Connect the monitor, Ethernet cable, keyboard, and mouse to the IPC:
+
+4. ![IPC-6108GC-CableConnected-overexposed.png](images/IPC-6108GC-CableConnected-overexposed.png)
+
+![warning](images/tip_icon.png)It is recommended to configure the fan speed through BIOS settings, if one or more plugin card is added to the system
+
+ - While starting up the computer, press F2 to enter BIOS setup menu.
+ - Go to [Advanced] => [Smart Fan Setting]
+ - Set [Fan Max. Trip Temp] to 50
+ - Set [Fan Start Trip Temp] to 20
+
+
+![tip_icon](images/tip_icon.png)It is recommended that you use a Digital Visual Interface (DVI) connector on the graphic card for the monitor. To set the display to the DVI port on the motherboard, following is the setting procedure:
+
+ - While starting up the computer, press F2 to enter BIOS setup menu.
+ - Go to [Advanced]=>[System Agent (SA) Configuration]=>[Graphics Configuration]=>[Primary Display]=> Set the setting to "PEG"
+![tip_icon](images/tip_icon.png)It is recommended to configure the IPC to run at maximum performance mode at all time:
+ - While starting up the computer, press F2 to enter BIOS setup menu.
+ - Go to [Power] => [SKU POWER CONFIG] => set the setting to "MAX. TDP"
+
+c. Connect the power:
+
+![IPC-6108GC-PowerCable.JPG](images/IPC-6108GC-PowerCable.JPG)
+
+
+### Installing the Software for the IPC
+
+This section describes the steps to install:
+
+- Ubuntu Linux
+- Apollo Kernel
+- Nvidia GPU Driver
+
+![tip_icon](images/tip_icon.png)It is assumed that you have experience working with Linux to successfully perform the software installation.
+
+#### Installing Ubuntu Linux
+Follow these steps:
+
+1. Create a bootable Ubuntu Linux USB flash drive:
+
+ Download Ubuntu (or a variant such as Xubuntu) and follow the online instructions to create a bootable USB flash drive.
+
+![tip_icon](images/tip_icon.png)It is recommended that you use **Ubuntu 14.04.3**.
+
+![tip_icon](images/tip_icon.png)You can type F2 during the system boot process to enter the BIOS settings. It is recommended that you disable Quick Boot and Quiet Boot in the BIOS to make it easier to catch any issues in the boot process.
+
+For more information about Ubuntu, see:
+![online_icon](images/online_icon.png) Ubuntu for Desktop web site:
+
+[https://www.ubuntu.com/desktop](https://www.ubuntu.com/desktop)
+
+2. Install Ubuntu Linux:
+
+ a. Insert the Ubuntu installation drive into a USB port and turn on the system.
+ b. Install Linux by following the on-screen instructions.
+
+3. Perform a software update and the installation:
+ a. Reboot into Linux after the installation is done.
+ b. Launch the Software Updater to update to the latest software packages (for the installed distribution) or type the following commands in a terminal program such as GNOME Terminal.
+ ```shell
+ sudo apt-get update; sudo apt-get upgrade
+ ```
+
+ c. Launch a terminal program such as GNOME Terminal and type the following command to install the Linux 4.4 kernel:
+
+```shell
+sudo apt-get install linux-generic-lts-xenial
+```
+![tip_icon](images/tip_icon.png)The IPC must have Internet access to update and install software. Make sure that the Ethernet cable is connected to a network with Internet access. You might need to configure the network for the IPC if the network that it is connected to is not using the Dynamic Host Configuration Protocol (DHCP).
+
+
+#### Installing the Apollo Kernel
+
+The Apollo runtime in the vehicle requires the [Apollo Kernel](https://github.com/ApolloAuto/apollo-kernel). You are strongly recommended to install the pre-built kernel.
+
+##### Use pre-built Apollo Kernel.
+
+You get access and install the pre-built kernel with the following commands.
+
+1. Download the release packages from the release section on github
+```
+https://github.com/ApolloAuto/apollo-kernel/releases
+```
+2. Install the kernel
+ After having the release package downloaded:
+```
+tar zxvf linux-4.4.32-apollo-1.0.0.tar.gz
+cd install
+sudo bash install_kernel.sh
+```
+3. Reboot your system by the `reboot` command
+
+4. Build the ESD CAN driver source code
+ Now you need to build the ESD CAN driver source code according to [ESDCAN-README.md](https://github.com/ApolloAuto/apollo-kernel/blob/master/linux/ESDCAN-README.md)
+
+##### Build your own kernel.
+If have modified the kernel, or the pre-built kernel is not the best for your platform, you can build your own kernel with the following steps.
+
+1. Clone the code from repository
+```
+git clone https://github.com/ApolloAuto/apollo-kernel.git
+cd apollo-kernel
+```
+2. Add the ESD CAN driver source code according to [ESDCAN-README.md](https://github.com/ApolloAuto/apollo-kernel/blob/master/linux/ESDCAN-README.md)
+
+3. Build the kernel with the following command.
+```
+bash build.sh
+```
+4. Install the kernel the same way as using a pre-built Apollo Kernel.
+
+#### Installing Nvidia GPU Driver
+
+The Apollo runtime in the vehicle requires the [Nvidia GPU Driver](http://www.nvidia.com/download/driverResults.aspx/114708/en-us). You are required to install the Nvidia GPU driver with specific options.
+
+1. Download the installation files
+```
+wget http://us.download.nvidia.com/XFree86/Linux-x86_64/375.39/NVIDIA-Linux-x86_64-375.39.run
+```
+
+2. Start the installation
+```
+sudo bash ./NVIDIA-Linux-x86_64-375.39.run --no-kernel-module --no-x-check -a -s
+```
+
+3. Reboot your system by the `sudo reboot` command
+
+##### Optional: Test the ESD CAN device node
+After rebooting the IPC with the new kernel:
+
+a. Create the CAN device node by issuing the following commands in a terminal:
+
+```shell
+cd /dev; sudo mknod –-mode=a+rw can0 c 52 0
+```
+b. Test the CAN device node using the test program that is part of the ESD CAN software package that you have acquired from ESD Electronics.
+
+
+The IPC is now ready to be mounted on the vehicle.
+
+## In the Vehicle
+
+Perform these tasks:
+
+- Make the necessary modifications to the vehicle as specified in the list of prerequisites
+- Install the major components:
+ - GPS Antenna
+ - IPC
+ - GPS Receiver
+ - LiDAR
+
+
+### Prerequisites
+
+**![warning_icon](images/warning_icon.png)WARNING**: Prior to mounting the major components (GPS Antenna, IPC, and GPS Receiver) in the vehicle, certain modifications must be performed as specified in the list of prerequisites. The instructions for making the mandatory changes in the list are outside the scope of this document.
+
+The list of prerequisites are as follows:
+
+- The vehicle must be modified for “drive-by-wire” technology by a professional service company. Also, a CAN interface hookup must be provided in the trunk where the IPC will be mounted.
+- A power panel must be installed in the trunk to provide power to the IPC and the GPS-IMU. The power panel would also service other devices in the vehicle such as a 4G LTE router. The power panel should be hooked up to the power system in the vehicle.
+- A custom-made rack must be installed to mount the GPS-IMU Antenna and the LiDAR on top of the vehicle.
+- A custom-made rack must be installed to mount the GPS-IMU in the trunk.
+- A 4G LTE router must be mounted in the trunk to provide Internet access for the IPC. The router must have built-in Wi-Fi access point (AP) capability to connect to other devices, such as an iPad, to interface with the autonomous driving (AD) system. A user would be able to use the mobile device to start AD mode or monitor AD status, for example.
+
+### Diagrams of the Major Component Installations
+
+The following two diagrams indicate the locations of where the three major components (GPS Antenna, IPC, GPS Receiver and LiDAR) should be installed on the vehicle:
+
+
+
+![major_compoment_side_view](images/Car_Sideview.png)
+
+
+
+![major_component_rear_view](images/Car_Rearview.png)
+
+
+
+### Installing the GPS Receiver and Antenna
+
+This section provides general information about installing **one** of two choices:
+
+- **Option 1:** GPS-IMU: **NovAtel SPAN-IGM-A1**
+- **Option 2:** GPS-IMU: **NovAtel SPAN® ProPak6™ and NovAtel IMU-IGM-A1**
+
+#### Option 1: Installing the NovAtel SPAN-IGM-A1
+
+The installation instructions describe the procedures to mount, connect, and take the lever arm measurements for the GPS-IMU NovAtel SPAN-IGM-A1.
+
+##### Mounting
+
+You can place the GPS-IMU NovAtel SPAN-IGM-A1 in most places in the vehicle but it is suggested that you follow these recommendations:
+
+- Place and secure the NovAtel SPAN-IGM-A1 inside the trunk with the Y-axis pointing forward.
+- Mount the NovAtel GPS-703-GGG-HV antenna in an unobscured location on top of the vehicle.
+
+##### Wiring
+
+You must connect two cables:
+
+- The antenna cable ─ Connects the GNSS antenna to the antenna port of the SPAN-IGM-A1
+- The main cable:
+ - Connects its 15-pin end to the SPAN-IGM-A1
+ - Connects its power wires to a power supply of 10-to-30V DC
+ - Connects its serial port to the IPC. If the power comes from a vehicle battery, add an auxiliary battery (recommended).
+
+
+![imu_main_cable_connection](images/imu_main_cable_connection.png)
+
+Main Cable Connections
+
+For more information, see the *SPAN-IGM™ Quick Start Guide*, page 3, for a detailed diagram:
+
+![online_icon](images/online_icon.png)SPAN-IGM™ Quick Start Guide
+
+[http://www.novatel.com/assets/Documents/Manuals/GM-14915114.pdf](http://www.novatel.com/assets/Documents/Manuals/GM-14915114.pdf)
+
+##### Taking the Lever Arm Measurement
+
+When the SPAN-IGM-A1 and the GPS Antenna are in position,the distance from the SPAN-IGM-A1 to the GPS Antenna must be measured. The distance should be measured as: X offset, Y offset, and Z offset.
+
+The error of offset must be within one centimeter to achieve high accuracy. For more information, see the *SPAN-IGM™ Quick Start Guide*, page 5, for a detailed diagram.
+
+For an additional information about the SPAN-IGM-A1, see:
+
+![online_icon](images/online_icon.png)SPAN-IGM™ User Manual:
+
+[http://www.novatel.com/assets/Documents/Manuals/OM-20000141.pdf](http://www.novatel.com/assets/Documents/Manuals/OM-20000141.pdf)
+
+
+
+#### Option 2: Installing NovAtel SPAN® ProPak6™ and NovAtel IMU-IGM-A1
+
+The installation instructions describe the procedures to mount, connect, and take the lever arm measurements for the GPS NovAtel SPAN® ProPak6™ **and** the NovAtel IMU-IGM-A1.
+
+##### Components for the Installation
+
+The components that are required for the installation include:
+
+- NovAtel GPS SPAN ProPak6
+
+- NovAtel IMU-IGM-A1
+
+- NovAtel GPS-703-GGG-HV Antenna
+
+- NovAtel GPS-C006 Cable (to connect antenna to GPS)
+
+- NovAtel 01019014 Main Cable (to connect GPS to a serial port the IPC)
+
+- Data Transport Unit (DTU) – similar to a 4G router
+
+- Magnetic adapters (for antenna and DTU)
+
+- DB9 Straight Through Cable
+
+##### Mounting
+
+You can place the two devices, the ProPak6 and the IMU in most places in the vehicle, but it is suggested that you follow these recommendations:
+
+- Place and secure the ProPak6 and the IMU side-by-side inside the trunk with the Y-axis pointing forward.
+- Mount the NovAtel GPS-703-GGG-HV antenna on top of the vehicle or on top of the trunk lid as shown:
+
+![gps_receiver_on_car](images/gps_receiver_on_car.png)
+
+- Use a magnetic adapter to tightly attach the antenna to the trunk lid.
+- Install the antenna cable in the trunk by opening the trunk and placing the cable in the space between the trunk lid and the body of the car.
+
+##### Wiring
+
+Follow these steps to connect the ProPak6 GNSS Receiver and the IMU to the Apollo system:
+
+1. Use the split cable that comes with IMU-IGM-A1 to connect the IMU Main port and theProPak6 COM3/IMU port.
+2. Use a USB-A-to-MicroUSB cable to connect the USB port of the IPC and the MicroUSB port of the ProPak6.
+3. Connect the other end of the IMU-IGM-A1 split cable to the vehicle power.
+4. Connect the GNSS antenna to Propak6.
+5. Connect the Propak6 power cable.
+
+![wiring](images/wiring.png)
+
+For more information about the NovAtel SPAN ProPak6, see:
+
+![online_icon](images/online_icon.png)NovAtel ProPak6 Installation& Operation Manual:
+
+[https://www.novatel.com/assets/Documents/Manuals/OM-20000148.pdf](https://www.novatel.com/assets/Documents/Manuals/OM-20000148.pdf)
+
+
+
+### Installing the Light Detection and Ranging System (LiDAR)
+
+This section provides descriptions on the installation procedure of HDL-64E S3 LiDAR
+
+#### Mounting
+
+A customized mounting structure is required to successfully mount an HDL64E S3 LiDAR on top of a vehicle. This structure needs to provide rigid support to the LiDAR system while raising the LiDAR to certain height above the ground to avoid the laser beams from the liDAR being blocked by the front and/or rear of the vehicle. The actual height needed for the LiDAR depends on the design of the vehicle and the mounting point of the LiDAR relative to the vehicle. The vertical tilt angle of the lasers normally ranges from +2~-24.8 degrees relative to the horizon. To fully utilize the angle range for detection, on a Lincoln MKZ, we recommend mounting the LiDAR at a minimum height of 1.8 meters (from ground to the base of the LiDAR).
+
+#### Wiring
+
+Each HDL-64E S3 LiDAR includes a cablebundle to connect the LiDAR to power supply, computer (Ethernet for data transfer, and serial port for LiDAR configuration) and GPS timesync source.
+
+![LiDAR_Cable](images/HDL64_Cable_whitened_labeled.png)
+
+1. Connection to the LiDAR
+
+ Connect the power and signal cable to the matching ports on the LiDAR
+
+ ![HDL64_Cabling](images/HDL64_Cabling.JPG)
+
+2. Connection to Power Source
+
+ The two AWG 16 wires are used to power HDL-64E S3 Lidar. It requires about 3A at 12V. To make connection to the power source, make full contact with the wires and tighten the screws.
+
+ ![HDL64_Power_Cable](images/HDL64_PowerCable.JPG)
+
+3. Conection to IPC
+
+ The connection to IPC is through an ethernet cable. Plug the ethernet connector in the cable bundle into an ethernet port on the IPC
+
+4. Connection to GPS:
+
+ HDL64E S3 LiDAR requires the Recommended minimum specific GPS/Transit data (GPRMC) and pulse per second (PPS)signal to synchronize to the GPS time. Customized connection is needed to establish the communication between the GPS receiver and the LiDAR:
+
+ a. SPAN-IGM-A1
+
+ If you configured the SPAN-IGM-A1 as specified in [Configuring the GPS and IMU](#configuring-the-gps-and-imu), the GPRMC signal is sent from the GPS receiver via the User Port cable from the Main port. The PPS signal is sent through the wire cables labeled as “PPS” and “PPS dgnd” from the Aux port. The dash-line boxes in the figure below are available connections that comes with the HDL64E S3 LiDAR and the SPAN-IGM-A1 GPS receiver. The remaining connections need to be made by the user.
+
+ ![Wiring_Schematics_IGM_A1](images/LiDAR_A1_wiring.png)
+
+ b. Propak 6 and IMU-IGM-A1
+
+ If you configured the Propak 6 as specified in [Configuring the GPS and IMU](#configuring-the-gps-and-imu), the GPRMC signal is sent from the GPS receiver via COM2 port. The PPS signal is sent through the IO port. The dash-line boxes in the figure below are available connections that comes with the HDL-64E S3 LiDAR and the Propak 6 GPS receiver. The remaining connections need to be made by the user.
+
+ ![Wiring_Schematics_PP6](images/LiDAR_PP6_wiring.png)
+
+5. Connection through serial port for LiDAR configuration
+
+ Some of the low-level parameters can be configured through serial port. Within the cable bundle provided by Velodyne Lidar, Inc., there are two pairs of red/black cables as shown in the pinout table below. The thicker pair (AWG 16) is used to power the LiDAR system. The thinner pair is used for serial connection. Connect the black wire (Serial In) to RX, the red wire to Ground of a serial cable. Connect the serial cable with a USB-serial adapter to a computer of choice.
+
+ ![pinout_table](images/pinout_table.png)
+
+ #### Configuration
+
+ By default HDL-64E S3 has the network IP address setting as 192.168.0.1. However, when we set up for Apollo, we should to change network IP address to 192.168.20.13 . We can use terminal application with termite3.2 and enter the network setting command. The IP address of HDL-64E S3 can be configured following the steps below:
+
+ 1. Connect one side of serial cable to your laptop
+
+ 2. Connect the other side of serial cable to HDL-64E S3’s serial wires
+
+ 3. COM port default setting
+
+ Baudrate: 9600
+
+ Parity: None
+
+ Data bits: 8
+
+ Stop bits: 1
+
+ 4. COM port application
+
+ Download termite3.2 from the link below and install it on your laptop (Windows)
+
+ [http://www.compuphase.com/software_termite.htm](http://www.compuphase.com/software_termite.htm)
+
+ 5. Serial cable connection for COM port between HDL-64E S3 and Laptop
+
+ ![Serial cable connected to laptop.png](images/Serial cable connected to laptop.png)
+
+ 6. Launch **Termite 3.2** from laptop
+
+ 7. Issue a serial command for setting up HDL-64E S3’s IP addresses over serial port "\#HDLIPA192168020013192168020255"
+
+ 8. The unit must be power cycled to adopt the new IP addresses
+
+ ![Issuing the serial command](images/Issuing_the_serial_command.png)
+
+ ![online_icon](images/online_icon.png)HDL-64E S3 Manual can be found on this webpage:
+
+ [http://velodynelidar.com/hdl-64e.html](http://velodynelidar.com/hdl-64e.html)
+
+### Installing the IPC
+
+Follow these steps:
+
+1. Use a voltage converter/regulator to convert the 12 VDC output from the vehicle to desired voltage to power IPC.
+
+ As recommended by Neousys, use a 12 VDC to 19 VDC converter with maximal output current of 20 A.
+
+ ![voltage_regulater_converter](images/voltage_converter2.jpg)
+
+ First, connect the two 19 VDC output wires to IPC's power connector (Green as shown below).
+
+ ![ipc_power_RB](images/ipc_power_RB.png)
+
+ Secondly, connect the two cables of 12 VDC input to the power panel in the vehicle. If the size of the wire is too thick, the wire should be splitted to several wires and connect to corresponding ports, respectively.
+
+ ![warning](images/warning_icon.png)This step is necessary. If the input voltage goes below the required limit. It is highly probable to cause system failure.
+
+
+2. Place the onboard computer system, the 6108GC, inside the trunk (recommended).
+
+ For example, Apollo 1.5 uses 4x4 self-tapping screws to bolt the 6108GC to the carpeted floor of the trunk. ![IPC-bolt_down-936x720](images/Mount_ipc_on_carpet.JPG)
+
+3. Mount the IPC so that its front and back sides(where all ports are located) face the right side (passenger) or the left side(driver) of the trunk.
+
+This positioning makes it easier to connect all of the cables.
+
+For more information, see:
+
+![online_icon](images/online_icon.png)Neousys Nuvo-6108GC – Manual:
+
+**[Link Unavailable]**
+
+4. Connect all cables, which include:
+
+- Power cable
+
+- Controller Area Network (CAN) cable
+
+- Ethernet cable from the 4G router to the IPC
+
+- GPS Receiver to the IPC
+
+- (Optional) Monitor, keyboard, mouse
+
+
+a. Connect the power cable to the IPC (as shown):
+
+b. Connect the other end of the power cable to the vehicle battery (as shown):
+
+
+![IPC-power-cable](images/IPC-power-cable.jpg)
+
+c. Connect the DB9 cable to the IPC to talk to the CAN (as shown):
+
+![DB9_cable](images/DB9_cable.png)
+
+d. Connect:
+
+- the Ethernet cable from the 4G router to the IPC
+
+- the GPS Receiver to the IPC
+
+- (optional) the monitor:
+
+![IPC-power-842x636](images/cable_connected_incar.JPG)
+
+
+
+#### Taking the Lever Arm Measurement
+
+Follow these steps:
+
+1. Before taking the measurement, turn on the IPC.
+
+
+2. When the IMU and the GPS Antenna are in position, the distance from the IMU to the GPS Antenna must be measured. The distance should be measured as: X offset, Yoffset, and Z offset. The error of offset must be within one centimeter to achieve high accuracy in positioning and localization.
+
+For an additional information, see:
+
+![online_icon](images/online_icon.png)NovAtel ProPak6 Installation & Operation Manual:
+
+[https://www.novatel.com/assets/Documents/Manuals/OM-20000148.pdf](https://www.novatel.com/assets/Documents/Manuals/OM-20000148.pdf)
+
+![online_icon](images/online_icon.png)NovAtel SPAN-IGM-A1 Product Page:
+
+[https://www.novatel.com/products/span-gnss-inertial-systems/span-combined-systems/span-igm-a1/](https://www.novatel.com/products/span-gnss-inertial-systems/span-combined-systems/span-igm-a1/)
+
+### Configuring the GPS and IMU
+
+Configure the GPS and IMU as shown:
+
+```
+WIFICONFIGSTATE OFF
+UNLOGALLTHISPORT
+SETIMUTOANTOFFSET0.00 1.10866 1.14165 0.05 0.05 0.08
+SETINSOFFSET0 0 0
+LOGCOM2 GPRMC ONTIME 1.0 0.25
+EVENTOUTCONTROLMARK2 ENABLE POSITIVE 999999990 10
+EVENTOUTCONTROLMARK1 ENABLE POSITIVE 500000000 500000000
+LOGNCOM1 GPGGA ONTIME 1.0
+
+logbestgnssposb ontime 0.5
+logbestgnssvelb ontime 0.5
+logbestposb ontime 0.5
+logINSPVASB ontime 0.01
+logCORRIMUDATASB ontime 0.01
+logINSCOVSB ontime 1
+logmark1pvab onnew
+
+logimutoantoffsetsb once
+logvehiclebodyrotationb onchanged
+
+SAVECONFIG
+```
+
+For ProPak6:
+
+```
+WIFICONFIG STATE OFF
+CONNECTIMU COM3 IMU_ADIS16488
+INSCOMMAND ENABLE
+SETIMUORIENTATION 5
+ALIGNMENTMODE AUTOMATIC
+SETIMUTOANTOFFSET 0.00 1.10866 1.14165 0.05 0.05 0.08
+VEHICLEBODYROTATION 0 0 0
+
+COM COM1 9600 N 8 1 N OFF OFF
+COM COM2 9600 N 8 1 N OFF OFF
+INTERFACEMODE COM1 NOVATEL NOVATEL OFF
+LOG COM2 GPRMC ONTIME 1 0.25
+PPSCONTROL ENABLE POSITIVE 1.0 10000
+MARKCONTROL MARK1 ENABLE POSITIVE
+EVENTINCONTROL MARK1 ENABLE POSITIVE 0 2
+
+interfacemode usb2 rtcmv3 none off
+rtksource auto any
+psrdiffsource auto any
+
+SAVECONFIG
+```
+
+**![warning_icon](images/warning_icon.png) WARNING:** Modify the **SETIMUTOANTOFFSET** line based on the actual measurement (of the antenna and the IMU offset).
+
+For example:
+
+```
+SETIMUTOANTOFFSET -0.05 0.5 0.8 0.05 0.05 0.08
+```
+
+# Setting up the Network
+
+This section provides recommendations for setting up the network.
+
+The IPC that is running the Apollo software must access the Internet to acquire the Real Time Kinematic (RTK) data for accurate localization. A mobile device also needs to connect to the IPC to run the Apollo software.
+
+## Recommendations
+
+Itis recommended that you set up your network according to the following diagram:
+
+![4G_network_setup](images/4G-LTE-setup-6108GC.png)
+
+Follow these steps:
+
+1. Install and configure a 4G LTE router with Wi-Fi Access Point (AP) capability and Gigabit Ethernet ports.
+
+
+2. Connect the IPC to the LTE router using an Ethernet cable.
+
+
+3. Configure the LTE router to access the Internet using the LTE cellular network.
+
+
+4. Configure the AP capability of the LTE router so that the iPad Pro or another mobile device can connect to the router, and, in turn, connect to the IPC.
+
+![tip_icon](images/tip_icon.png)It is recommended that you configure a fixed IP instead of using DHCP on the IPC to make it easier to connect to it from a mobile terminal.
+
+# Additional Tasks Required
+
+Youwill use the components that you were required to provide to perform the following tasks:
+
+1. Connect a monitor using the DVI or the HDMI cables and connect the keyboard and mouse to perform debugging tasks at the car onsite.
+
+2. Establish a Wi-Fi connection on the Apple iPad Pro to access the HMI and control the Apollo ADS that is running on the IPC.
+
+# Next Steps
+
+After you complete the hardware installation in the vehicle, see the [Apollo Quick Start](https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/apollo_1_5_quick_start.md) for the steps to complete the software installation.
diff --git a/docs/quickstart/apollo_1_5_lidar_calibration_guide.md b/docs/quickstart/apollo_1_5_lidar_calibration_guide.md
new file mode 100644
index 00000000000..13a4bf0efa4
--- /dev/null
+++ b/docs/quickstart/apollo_1_5_lidar_calibration_guide.md
@@ -0,0 +1,167 @@
+## Apollo Sensor Calibration Service
+
+Welcome to the Apollo sensor calibration service. This document describes the process of the extrinsic calibration service between 64-beam Light Detection And Ranging (LiDAR) and Inertial Navigation System (INS).
+
+## Apollo Sensor Calibration Catalog
+
+- Service overview
+- Preparation
+- Recording calibration data
+- Uploading calibration data and creating task
+- Obtaining calibration results
+- Error description
+
+
+
+### Overview
+
+The Apollo vehicle sensor calibration function provides the extrinsic calibration between Velodyne HDL-64ES3 and IMU. The calibration results can be used to transfer the obstacle location detected by LiDAR to the IMU coordinate system, and then to the world coordinate system. The results are provided by `.yaml` format files.
+
+### Preparation
+
+To calibrate the sensors it is important to prepare using the following steps:
+
+1.Install 64-beams LiDAR and INS supported by Apollo, and then deploy the docker running environment.
+
+2.Start up the 64-beams LiDAR and INS. The INS must be aligned when it is powered on. At this point, the car should be driven straight, then turned left and turned right in an open area, until the initialization is completed.
+
+3.Confirm that all sensor topics required by this service have output. See: [How to Check the Sensor Output?](https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/lidar_calibration/FAQ0.md)
+
+The topics required by the calibration service are shown in the following Table 1:
+
+Table 1. Sensor topics.
+
+Sensor | Topic Name | Topic Feq. (Hz)
+--- | ------- | --- |
+HDL-64ES3 | /apollo/sensor/velodyne64/VelodyneScanUnified | 10
+INS | /apollo/sensor/gnss/odometry | 100
+INS | /apollo/sensor/gnss/ins_stat | 1
+
+
+4.Confirm that the INS status is 56 when recording data. See: [How to Check INS Status?](https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/lidar_calibration/FAQ1.md)
+
+5.Choose an appropriate calibration field.
+
+An ideal calibration field requires no tall buildings around the calibration area. If buildings are near, low-rising building facades are preferred. Finally, the ground should be smooth, not rough, and it should be easy to drive the car following the trajectory that looks like the ∞ symbol as illustrated in Figure 1. An example of a good calibration field is shown in Figure 2.
+
+![](lidar_calibration/images/calibration/trajectory.png)
+
+
Figure 1. The trajectory for calibration.
+
+![](lidar_calibration/images/calibration/field.png)
+
+Figure 2. Calibration field.
+
+### Recording Calibration Data
+
+After the preparation steps are completed, drive the vehicle to the calibration field to record the calibration data.
+
+1.The recording script is `apollo/script/lidar_calibration.sh`.
+
+2.Run the following command to record data:
+
+```bash
+bash lidar_calibration.sh start_record
+```
+
+The recorded bag is under the directory `apollo/data/bag`.
+
+3.Drive the car following a ∞ symbol path, using a controlled speed of 20-40km/h, and make the turning radius as small as possible.
+ The total time length should within 3 minutes, but please make sure that your calibration drive contains at least one full ∞ symbol path.
+
+4.After recording, run the following command to stop the data recording.
+
+```bash
+bash lidar_calibration.sh stop_record
+```
+
+5.Then, the program will detect whether or not the recorded bag contains all the required topics. After passing the test, the bag will be packaged into file `lidar_calib_data.tar.gz`, including the recorded rosbag and the corresponding MD5 checksum file.
+
+### Uploading Calibration Data and Creating a Calibration Service Task
+
+After recording the calibration data, please login to the [calibration service page](https://console.bce.baidu.com/apollo/calibrator/index/list) to complete the calibration.
+
+1.Enter the calibration service page and click the **New Task** button which in **Task Management** list to create a new calibration task.
+
+2.After entering the creating new task page, you need to fill in a simple description of this task.Then click the **Upload and create a task** button and select the upload calibration file to start uploading the calibration data.
+
+3.After start uploading the data, the page will jump to the task process view. The process figure is the upload progress page. The task will start to calibrate when the upload progress reaches 100%. Please keep the network unblocked during uploading.
+
+4.When the data is uploaded, the Data Verification Process will begin, as shown in Figure 3. The validation process ensures data integrity and suitability. The validation items are:
+
+ * Decompress test
+ * MD5 checksum
+ * Data format validation
+ * ∞ symbol path validation
+ * INS status validation
+
+If validation fails, the corresponding error message is prompted. See the Error Description section below for details.
+
+![](lidar_calibration/images/calib_valid_en.png)
+Figure 3. Calibration data verification.
+
+6.After data validation, the calibration process begins, as shown in Figure 4. A detailed calibration progress page is displayed to users. Depending on the size and quality of the data, the overall calibration time lasts about 10-30 minutes. You can enter the page at any time to see the progress of the current task.
+![](lidar_calibration/images/calib_progress_en.png)
+Figure 4. Calibration progress page.
+
+7.When calibration succeeds, click the **View detail** button to display a stitched point cloud. You can confirm the quality verification by checking the sharpness of the point cloud. If you are satisfied with the calibration quality, you can click **Confirm** to keep the result and download the calibration results by clicking **Download**. This fulfills the completion of the calibration process.
+
+For additional information, see: [How to Check Point Cloud Quality?](https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/lidar_calibration/FAQ2.md)
+
+### Obtaining Calibration Results
+
+1.Before obtaining the calibration results, the service requires that you confirm the quality of the calibration results based on visualized point cloud.
+
+2.After confirming the quality of the calibration result, you can click the **Confirm** button to store the calibration result. After that, you can download the result on the task page. The **Download** button will *not* appear on the task page if the result failed to pass quality verification.
+
+3.Extrinsic file format instruction — The extrinsic is returned to you in a `.yaml` format file. Below is an example of an extrinsic file.
+
+The field meanings shown in this example are defined in Table 2 below.
+
+```bash
+header:
+ seq: 0
+ stamp:
+ secs: 1504765807
+ nsecs: 0
+ frame_id: novatel
+child_frame_id: velodyne64
+transform:
+ rotation:
+ x: 0.02883904659307384
+ y: -0.03212457531272153
+ z: 0.697030811535172
+ w: 0.7157404339725393
+ translation:
+ x: 0.000908140840832566
+ y: 1.596564931858745
+ z: 1
+```
+
+Table 2. Definition of the keys in the yaml file.
+
+Field | Meaning
+------ | -----
+`header` | Header information, including timestamps.
+`child_frame_id` | Source sensor ID in calibration. Will be HDL-64ES3 here.
+`frame_id` | Target sensor ID in calibration. Will be Novatel here.
+`rotation`| Rotation part of the extrinsic parameters. Represented by a quaternion.
+`translation`| Translation part of the extrinsic parameters.
+
+4.How to use extrinsic parameters?
+
+Enter the following command to create the calibration file directory in the apollo directory:
+
+```bash
+mkdir -p modules/calibration/data/[CAR_ID]/
+```
+
+Here, **CAR\_ID** is the vehicle ID for calibrating vehicles. Then, copy the downloaded extrinsic yaml file to the corresponding **CAR\_ID** folder. Finally, after you start HMI, select the correct **CAR\_ID** to load the corresponding calibration yaml file.
+
+### Error Description
+
+1. Data unpacking error: The uploaded data is not a valid `tar.gz` file
+2. MD5 checksum error: If the MD5 checksum of the uploaded data differs from the MD5 checksum computed by the server side, it could be caused by network transmission problems.
+3. Data format error: The uploaded data is not a rosbag, or necessary topics are missing or unexpected topics exist. The server-side calibration program failed to read it.
+4. No ∞ symbol path error: No ∞ symbol path was found in the uploaded data. Verify that the recorded data contains at least one ∞ symbol path.
+5. INS status error: In the uploaded data, the location does not meet the requirement. Ensure that the INS status is 56 during the data recording.
diff --git a/docs/quickstart/apollo_1_5_lidar_calibration_guide_cn.md b/docs/quickstart/apollo_1_5_lidar_calibration_guide_cn.md
new file mode 100644
index 00000000000..420f0e46fb3
--- /dev/null
+++ b/docs/quickstart/apollo_1_5_lidar_calibration_guide_cn.md
@@ -0,0 +1,158 @@
+欢迎使用Apollo传感器标定服务。本文档提供64线激光雷达与组合惯导之间的外参标定服务使用流程。
+
+### 文档概览
+
+1. 服务概述
+2. 准备工作
+3. 标定数据录制
+4. 标定数据上传以及任务创建
+5. 标定结果获取
+6. 错误说明
+
+### 服务概述
+
+本服务作为Apollo整车传感器标定功能中的一部分,提供Velodyne 64线激光雷达HDL-64ES3与IMU之间的外参标定功能。标定结果可用于将激光雷达检测的障碍物转换至IMU坐标系,进而转到世界坐标系下。标定结果以 `.yaml` 文件形式返回。
+
+
+### 准备工作
+
+为了更好地使用本服务,请按以下顺序进行准备工作:
+
+1.安装Apollo所支持的64线激光雷达和组合惯性导航系统,下载镜像安装docker环境。
+
+2.开机并启动64线激光雷达以及组合惯导系统。Novatel组合惯导初次上电时需要校准。此时应将车在开阔地带进行直行、左右转弯等操作,直至惯导初始化完成。
+
+3.确认本服务所需传感器数据的topic均有输出。[如何查看传感器有数据输出?](https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/lidar_calibration/FAQ0_cn.md)
+
+本服务所需的topics如下表1所示:
+
+表1. 传感器topic名称
+
+传感器 | Topic名称 | Topic发送频率(Hz)
+--- | ------- | --- |
+HDL-64ES3 | /apollo/sensor/velodyne64/VelodyneScanUnified | 10
+INS | /apollo/sensor/gnss/odometry | 100
+INS | /apollo/sensor/gnss/ins_stat | 1
+
+4.确认车辆采集标定数据时的定位状态为56。[如何查看车辆定位状态?](https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/lidar_calibration/FAQ1_cn.md)
+
+5.选择合适的标定场地。
+
+标定的地点需要选择无高楼遮挡、地面平坦、四周有平整的建筑物并且可以进行如图1所示8字轨迹行驶的地方。一个合适的标定场地如图2所示。
+
+![](lidar_calibration/images/trajectory.png)
+图1 标定所需车辆行驶的轨迹。
+
+![](lidar_calibration/images/field.png)
+图2 标定场地。
+
+### 标定数据录制
+
+准备工作完成后,将车辆驶入标定场地进行标定数据的录制。
+
+1.录制脚本工具为 `apollo/script/lidar_calibration.sh`。
+
+2.运行以下命令,开始数据录制工作:
+
+```bash
+bash lidar_calibration.sh start_record
+```
+
+所录制的bag在 `apollo/data/bag` 目录下。
+
+3.以8字形轨迹驾驶汽车,将车速控制在20-40km/h,并使转弯半径尽量小。行驶的时长3分钟即可,但要保证标定数据至少包含一个完整的8字。
+
+4.录制完成后,输入以下命令结束数据录制:
+
+```bash
+bash lidar_calibration.sh stop_record
+```
+
+5.随后,程序会检测所录制的bag中是否含有所需的所有topics。检测通过后,会将bag打包成 `lidar_calib_data.tar.gz` 文件,内容包括录制的rosbag以及对应的MD5校验和文件。
+
+### 标定数据上传以及任务创建
+
+录制好标定数据后,登录至[标定服务页面](https://console.bce.baidu.com/apollo/calibrator/index/list)以完成标定。
+
+1.进入标定服务页面,在**任务管理**列表下点击**新建任务**按钮以新建一个标定任务。
+
+2.进入新建任务页面后,需先填写简单的任务描述,然后点击**上传数据并创建任务**按钮,选择上传标定文件,则可以开始进行数据上传。
+
+3.开始上传数据后,页面将跳转至任务流程视图。流程视图图示为上传进度页面,待其到达100%后则可以开始进行标定。上传期间请保持网络畅通。
+
+4.数据上传完毕后,将开始数据校验流程,如图3所示。校验流程可以保证数据完整以及适合标定,校验项目有:
+
+* 数据包解压校验
+* MD5校验
+* 数据格式校验
+* 8字路径与GPS质量校验
+* 初始外参评估合格
+
+若数据校验失败,则会提示相应错误。错误的原因请参照错误说明。
+
+![](lidar_calibration/images/calib_valid_cn.png)
+图3 标定数据校验流程。
+
+6.校验通过后将开始标定流程,一个标定进度页面会展示给用户,如图4所示。视数据大小和质量的影响,整体标定时间大约持续10-30分钟,用户可以随时进入该页面查看当前任务的标定进度。
+
+![](lidar_calibration/images/calib_progress_cn.png)
+图4 标定进度页面。
+
+7.标定完成后,进入人工质检环节。点击[查看]按钮会弹出用于质检的拼接点云,此时可以开始人工质检。若质检通过,则可以点击**确认入库**按钮以保存标定结果。最后,点击**下载数据**按钮来下载标定结果,至此标定流程完成。[如何进行质检?](https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/lidar_calibration/FAQ2_cn.md)
+
+### 标定结果获取
+
+1.获取标定结果前,本服务需要用户根据可视化效果确认标定结果的质量。
+
+2.确认该标定结果质量合格后,用户可点击**确认入库**按钮将标定结果入库。之后可以在任务页面进行下载,未通过质检并入库的标定结果在任务页面不会出现下载地址。
+
+3.外参格式解析。外参以yaml文件形式返回给用户,下面是一个外参结果文件的样例。
+表1中说明了几个字段的含义。
+
+```bash
+header:
+ seq: 0
+ stamp:
+ secs: 1504765807
+ nsecs: 0
+ frame_id: novatel
+child_frame_id: velodyne64
+transform:
+ rotation:
+ x: 0.02883904659307384
+ y: -0.03212457531272153
+ z: 0.697030811535172
+ w: 0.7157404339725393
+ translation:
+ x: 0.000908140840832566
+ y: 1.596564931858745
+ z: 1
+```
+
+表2. 外参YAML文件字段含义
+
+字段 | 含义
+---- | ----
+header | 头信息,主要包含标定时间
+child_frame_id | 所标定的源传感器ID,此时为HDL-64ES3
+frame_id | 所标定的目标传感器ID,此时为Novatel
+rotation | 以四元数表示的外参旋转部分
+translation | 外参的平移部分
+
+4.外参使用方式
+
+首先在`/apollo`目录下输入以下命令创建标定文件目录:
+
+```bash
+mkdir -p modules/calibration/data/[CAR_ID]/
+```
+其中,**CAR\_ID**为标定车辆的车辆ID。然后将下载的外参yaml文件拷贝至对应的**CAR\_ID** 文件夹内。最后,在启动hmi后,选择需正确的**CAR\_ID**即可载入对应的标定yaml文件。
+
+### 错误说明
+
+1. 数据解包错误:上传的数据不是一个合法的 `tar.gz` 文件。
+2. MD5校验和错误:上传数据的MD5校验和与服务器端计算的MD5校验和不同,通常由网络传输问题引发。
+3. 数据格式错误:上传的数据不是一个rosbag,或者bag里缺少指定的topic或包含其他非指定的topic,服务器端标定程序读取失败。
+4. 无8字路径错误:在上传的数据中没有发现8字路径。需要确认录制的数据中是否包含至少一个8字形路径。
+5. 组合惯导定位精度不足:在上传的数据中发现定位状态不符合要求。需要确认在录制过程中的定位状态为56。
+
diff --git a/docs/quickstart/apollo_1_5_quick_start.md b/docs/quickstart/apollo_1_5_quick_start.md
new file mode 100644
index 00000000000..38180f22968
--- /dev/null
+++ b/docs/quickstart/apollo_1_5_quick_start.md
@@ -0,0 +1,46 @@
+# Apollo 1.5 Quick Start Guide
+
+This quick start focuses on Apollo 1.5 new features. For general Apollo concepts, please refer to [Apollo 1.0 Quick Start](https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/apollo_1_0_quick_start.md).
+
+Before doing the following steps, make sure you have calibrated the extrinsic parameters between the LiDAR and the GNSS/INS. For sensor calibration, please refer to [Apollo 1.5 LiDAR calibration guide](https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/apollo_1_5_lidar_calibration_guide.md).
+
+## Launch release env Docker Image
+
+Run the following commands:
+
+```bash
+cd $APOLLO_HOME
+bash docker/scripts/release_start.sh
+```
+
+When Docker starts, it creates a port mapping, which maps the Docker internal port 8887 to the host port 8887. You can then visit the HMI web service in your host machine browser:
+
+Open the Chrome browser and start the Apollo HMI by going to **localhost:8887**.
+ ![](images/hmi_setup_profile.png)
+You'll be required to setup profile before doing anything else. Click the
+dropdown menu to select your HDMap and vehicle in use. The list are defined in
+[HMI config file](https://raw.githubusercontent.com/ApolloAuto/apollo/master/modules/hmi/conf/config.pb.txt).
+
+Then your HMI comes to live!
+
+*Note: It's also possible to change profile on the right panel of HMI, but just
+remember to click "Reset All" on the top-right corner to restart the system.*
+
+ ![](images/start_hmi.png)
+
+## (*New!*) Start Auto
+
+In Apollo 1.5, we released the new feature, auto following the traffic until destination.
+
+1. To make it work, you need setup the system by clicking the "Setup"
+ button on left panel.
+
+ ![](images/hmi_setup_1.5.png)
+
+2. Make sure all modules are on and hardware is ready, and the vehicle is in a
+
+good state which is safe to enter auto mode to follow the traffic to destination.
+
+Click the "Start Auto" button, then it will drive you there!
+
+ ![](images/hmi_start_auto_following.png)
diff --git a/docs/quickstart/images/4G-LTE-setup-6108GC.png b/docs/quickstart/images/4G-LTE-setup-6108GC.png
new file mode 100644
index 00000000000..7367c916248
Binary files /dev/null and b/docs/quickstart/images/4G-LTE-setup-6108GC.png differ
diff --git a/docs/quickstart/images/After installing the CAN Card.png b/docs/quickstart/images/After installing the CAN Card.png
new file mode 100644
index 00000000000..5de4e7744c3
Binary files /dev/null and b/docs/quickstart/images/After installing the CAN Card.png differ
diff --git a/docs/quickstart/images/Before_installing_the_can_card.png b/docs/quickstart/images/Before_installing_the_can_card.png
new file mode 100644
index 00000000000..8602c76918c
Binary files /dev/null and b/docs/quickstart/images/Before_installing_the_can_card.png differ
diff --git a/docs/quickstart/images/Car_Rearview.png b/docs/quickstart/images/Car_Rearview.png
new file mode 100644
index 00000000000..2cd29541707
Binary files /dev/null and b/docs/quickstart/images/Car_Rearview.png differ
diff --git a/docs/quickstart/images/Car_Sideview.png b/docs/quickstart/images/Car_Sideview.png
new file mode 100644
index 00000000000..9129cf1943a
Binary files /dev/null and b/docs/quickstart/images/Car_Sideview.png differ
diff --git a/docs/quickstart/images/HDL64_Cable_whitened_labeled.png b/docs/quickstart/images/HDL64_Cable_whitened_labeled.png
new file mode 100644
index 00000000000..7073a63a0ab
Binary files /dev/null and b/docs/quickstart/images/HDL64_Cable_whitened_labeled.png differ
diff --git a/docs/quickstart/images/HDL64_Cabling.JPG b/docs/quickstart/images/HDL64_Cabling.JPG
new file mode 100644
index 00000000000..28144a25deb
Binary files /dev/null and b/docs/quickstart/images/HDL64_Cabling.JPG differ
diff --git a/docs/quickstart/images/HDL64_PowerCable.JPG b/docs/quickstart/images/HDL64_PowerCable.JPG
new file mode 100644
index 00000000000..e51d112fa9c
Binary files /dev/null and b/docs/quickstart/images/HDL64_PowerCable.JPG differ
diff --git a/docs/quickstart/images/IPC-6108GC-CableConnected-overexposed.png b/docs/quickstart/images/IPC-6108GC-CableConnected-overexposed.png
new file mode 100644
index 00000000000..1f3f80ea02b
Binary files /dev/null and b/docs/quickstart/images/IPC-6108GC-CableConnected-overexposed.png differ
diff --git a/docs/quickstart/images/IPC-6108GC-PowerCable.JPG b/docs/quickstart/images/IPC-6108GC-PowerCable.JPG
new file mode 100644
index 00000000000..b33483ee955
Binary files /dev/null and b/docs/quickstart/images/IPC-6108GC-PowerCable.JPG differ
diff --git a/docs/quickstart/images/IPC-6108GC-Screw-Positions.png b/docs/quickstart/images/IPC-6108GC-Screw-Positions.png
new file mode 100644
index 00000000000..b8be2184911
Binary files /dev/null and b/docs/quickstart/images/IPC-6108GC-Screw-Positions.png differ
diff --git a/docs/quickstart/images/IPC-6108GC-Screw-Positions_labeled.png b/docs/quickstart/images/IPC-6108GC-Screw-Positions_labeled.png
new file mode 100644
index 00000000000..c7f013b7265
Binary files /dev/null and b/docs/quickstart/images/IPC-6108GC-Screw-Positions_labeled.png differ
diff --git a/docs/quickstart/images/IPC-6108GC-front-side.jpg b/docs/quickstart/images/IPC-6108GC-front-side.jpg
new file mode 100644
index 00000000000..4e67052f87e
Binary files /dev/null and b/docs/quickstart/images/IPC-6108GC-front-side.jpg differ
diff --git a/docs/quickstart/images/IPC-6108GC-left-side.jpg b/docs/quickstart/images/IPC-6108GC-left-side.jpg
new file mode 100644
index 00000000000..f864a1f55d7
Binary files /dev/null and b/docs/quickstart/images/IPC-6108GC-left-side.jpg differ
diff --git a/docs/quickstart/images/IPC_powerbutton.png b/docs/quickstart/images/IPC_powerbutton.png
new file mode 100644
index 00000000000..4a0511c79e3
Binary files /dev/null and b/docs/quickstart/images/IPC_powerbutton.png differ
diff --git a/docs/quickstart/images/Issuing_the_serial_command.png b/docs/quickstart/images/Issuing_the_serial_command.png
new file mode 100644
index 00000000000..f142d0f5019
Binary files /dev/null and b/docs/quickstart/images/Issuing_the_serial_command.png differ
diff --git a/docs/quickstart/images/LiDAR_A1_wiring.png b/docs/quickstart/images/LiDAR_A1_wiring.png
new file mode 100644
index 00000000000..6e78ae71b54
Binary files /dev/null and b/docs/quickstart/images/LiDAR_A1_wiring.png differ
diff --git a/docs/quickstart/images/LiDAR_PP6_wiring.png b/docs/quickstart/images/LiDAR_PP6_wiring.png
new file mode 100644
index 00000000000..efc1171de2c
Binary files /dev/null and b/docs/quickstart/images/LiDAR_PP6_wiring.png differ
diff --git a/docs/quickstart/images/Mount_ipc_on_carpet.JPG b/docs/quickstart/images/Mount_ipc_on_carpet.JPG
new file mode 100644
index 00000000000..d55a3ba76cb
Binary files /dev/null and b/docs/quickstart/images/Mount_ipc_on_carpet.JPG differ
diff --git a/docs/quickstart/images/Removing_the_cover.JPG b/docs/quickstart/images/Removing_the_cover.JPG
new file mode 100644
index 00000000000..efa01f1e13d
Binary files /dev/null and b/docs/quickstart/images/Removing_the_cover.JPG differ
diff --git a/docs/quickstart/images/Serial cable connected to laptop.png b/docs/quickstart/images/Serial cable connected to laptop.png
new file mode 100644
index 00000000000..25279cacb5d
Binary files /dev/null and b/docs/quickstart/images/Serial cable connected to laptop.png differ
diff --git a/docs/quickstart/images/cable_connected_incar.JPG b/docs/quickstart/images/cable_connected_incar.JPG
new file mode 100644
index 00000000000..a34276f3b57
Binary files /dev/null and b/docs/quickstart/images/cable_connected_incar.JPG differ
diff --git a/docs/quickstart/images/hmi_setup_1.5.png b/docs/quickstart/images/hmi_setup_1.5.png
new file mode 100644
index 00000000000..5de39f4e424
Binary files /dev/null and b/docs/quickstart/images/hmi_setup_1.5.png differ
diff --git a/docs/quickstart/images/hmi_setup_profile.png b/docs/quickstart/images/hmi_setup_profile.png
new file mode 100644
index 00000000000..e889137c61c
Binary files /dev/null and b/docs/quickstart/images/hmi_setup_profile.png differ
diff --git a/docs/quickstart/images/hmi_start_auto_following.png b/docs/quickstart/images/hmi_start_auto_following.png
new file mode 100644
index 00000000000..4471a27f7a6
Binary files /dev/null and b/docs/quickstart/images/hmi_start_auto_following.png differ
diff --git a/docs/quickstart/images/lidar_pic.png b/docs/quickstart/images/lidar_pic.png
new file mode 100644
index 00000000000..d50ac705412
Binary files /dev/null and b/docs/quickstart/images/lidar_pic.png differ
diff --git a/docs/quickstart/images/pinout_table.png b/docs/quickstart/images/pinout_table.png
new file mode 100644
index 00000000000..8e6f864bb79
Binary files /dev/null and b/docs/quickstart/images/pinout_table.png differ
diff --git a/docs/quickstart/images/start_hmi.png b/docs/quickstart/images/start_hmi.png
index 740936d6608..0e7906b1c5c 100644
Binary files a/docs/quickstart/images/start_hmi.png and b/docs/quickstart/images/start_hmi.png differ
diff --git a/docs/quickstart/images/voltage_converter.jpg b/docs/quickstart/images/voltage_converter.jpg
new file mode 100644
index 00000000000..4412c1d65b5
Binary files /dev/null and b/docs/quickstart/images/voltage_converter.jpg differ
diff --git a/docs/quickstart/images/voltage_converter2.jpg b/docs/quickstart/images/voltage_converter2.jpg
new file mode 100644
index 00000000000..060b02432a0
Binary files /dev/null and b/docs/quickstart/images/voltage_converter2.jpg differ
diff --git a/docs/quickstart/lidar_calibration/FAQ0.md b/docs/quickstart/lidar_calibration/FAQ0.md
new file mode 100644
index 00000000000..f154c9d3b47
--- /dev/null
+++ b/docs/quickstart/lidar_calibration/FAQ0.md
@@ -0,0 +1,10 @@
+### How to Check the Sensor Output?
+
+Use the `rostopic` command. For example, type the following command to check the
+output of HDL-64ES3:
+
+```bash
+ rostopic echo /apollo/sensor/velodyne64/VelodyneScanUnified
+```
+
+If the topic data is displayed on the terminal, the LiDAR works normally.
\ No newline at end of file
diff --git a/docs/quickstart/lidar_calibration/FAQ0_cn.md b/docs/quickstart/lidar_calibration/FAQ0_cn.md
new file mode 100644
index 00000000000..e1530f070ba
--- /dev/null
+++ b/docs/quickstart/lidar_calibration/FAQ0_cn.md
@@ -0,0 +1,9 @@
+### 如何查看传感器是否有数据输出?
+
+使用 rostopic 命令。例如,查看 HDL-64ES3 的输出,可以在终端中输入:
+
+```bash
+ rostopic echo /apollo/sensor/velodyne64/VelodyneScanUnified
+```
+ 若该 topic 的数据会显示在终端上,则激光雷达工作正常。
+
diff --git a/docs/quickstart/lidar_calibration/FAQ1.md b/docs/quickstart/lidar_calibration/FAQ1.md
new file mode 100644
index 00000000000..951d9f629e1
--- /dev/null
+++ b/docs/quickstart/lidar_calibration/FAQ1.md
@@ -0,0 +1,9 @@
+### How to Check INS Status?
+
+Using Novatel INS as an example, type the following command to check the INS status:
+
+```bash
+rostopic echo /apollo/sensor/gnss/ins_stat
+```
+
+Find the `pos_type` field: If the value is 56, it has entered a good positioning status (RTK_FIXED) and can be used for calibration. If it is not 56, reliable calibration results cannot be obtained.
\ No newline at end of file
diff --git a/docs/quickstart/lidar_calibration/FAQ1_cn.md b/docs/quickstart/lidar_calibration/FAQ1_cn.md
new file mode 100644
index 00000000000..639172e87f3
--- /dev/null
+++ b/docs/quickstart/lidar_calibration/FAQ1_cn.md
@@ -0,0 +1,9 @@
+### 如何查看车辆的定位状态?
+
+以使用 Novatel 组合惯导为例,在终端中输入:
+
+```bash
+rostopic echo /apollo/sensor/gnss/ins_stat
+```
+
+找到“pos_type”字段,若该字段的值为 56,则表示进入了良好的定位状态 (RTK_FIXED),可以用于标定。若不为 56,则无法获得可靠的标定结果。
\ No newline at end of file
diff --git a/docs/quickstart/lidar_calibration/FAQ2.md b/docs/quickstart/lidar_calibration/FAQ2.md
new file mode 100644
index 00000000000..feea01b33a1
--- /dev/null
+++ b/docs/quickstart/lidar_calibration/FAQ2.md
@@ -0,0 +1,21 @@
+### How to Complete a Quality Inspection?
+
+At present, you complete the quality verification manually with a visual inspection of the results.
+
+When the calibration is completed, the point cloud stitched during the calibration process is provided. In the point cloud, details of the calibration field can be easily identified. Assess the calibration quality for clarity. Look at objects such as building facades, street lights, poles and road curbs. If the point cloud is blurry and a ghosting effect can be found, the calibration is poor. If the calibration result is good, a sharp and clear stitched point cloud is shown.
+
+Figure 1 shows the comparison between the stitched point clouds with good (a) and insufficient(b) calibration quality.
+
+![](images/good_calib.png)
+
+(a)
+
+
+![](images/poor_calib.png)
+
+(b)
+
+
+
+Figure 1. (a) a high quality calibration result (b) an insufficient one.
+
\ No newline at end of file
diff --git a/docs/quickstart/lidar_calibration/FAQ2_cn.md b/docs/quickstart/lidar_calibration/FAQ2_cn.md
new file mode 100644
index 00000000000..907f87e9b6f
--- /dev/null
+++ b/docs/quickstart/lidar_calibration/FAQ2_cn.md
@@ -0,0 +1,19 @@
+### 如何进行质检?
+
+目前进行质检方法主要通过人工来完成。标定完成后,页面会提供标定过程中拼接得到的点云。若标定结果良好,会得到锐利和清晰的拼接点云,可反映出标定场地的细节。通常质检的参照物有平整的建筑立面、路灯和电线杆以及路沿等。若标定质量较差,则会使拼接点云出现一些模糊、重影的效果。图1是两张不同标定质量的拼接点云对比。
+
+![](images/good_calib.png)
+
+
+(a)
+
+
+![](images/poor_calib.png)
+
+
+(b)
+
+
+
+图1. (a) 高质量的标定结果 (b) 质量较差的标定结果。
+
\ No newline at end of file
diff --git a/docs/quickstart/lidar_calibration/images/calib_progress_cn.png b/docs/quickstart/lidar_calibration/images/calib_progress_cn.png
new file mode 100644
index 00000000000..80906a60a53
Binary files /dev/null and b/docs/quickstart/lidar_calibration/images/calib_progress_cn.png differ
diff --git a/docs/quickstart/lidar_calibration/images/calib_progress_en.png b/docs/quickstart/lidar_calibration/images/calib_progress_en.png
new file mode 100644
index 00000000000..87b94ff6492
Binary files /dev/null and b/docs/quickstart/lidar_calibration/images/calib_progress_en.png differ
diff --git a/docs/quickstart/lidar_calibration/images/calib_valid_cn.png b/docs/quickstart/lidar_calibration/images/calib_valid_cn.png
new file mode 100644
index 00000000000..5893c3de05c
Binary files /dev/null and b/docs/quickstart/lidar_calibration/images/calib_valid_cn.png differ
diff --git a/docs/quickstart/lidar_calibration/images/calib_valid_en.png b/docs/quickstart/lidar_calibration/images/calib_valid_en.png
new file mode 100644
index 00000000000..6fc0db5dc7a
Binary files /dev/null and b/docs/quickstart/lidar_calibration/images/calib_valid_en.png differ
diff --git a/docs/quickstart/lidar_calibration/images/field.png b/docs/quickstart/lidar_calibration/images/field.png
new file mode 100644
index 00000000000..fd9bb81c72c
Binary files /dev/null and b/docs/quickstart/lidar_calibration/images/field.png differ
diff --git a/docs/quickstart/lidar_calibration/images/good_calib.png b/docs/quickstart/lidar_calibration/images/good_calib.png
new file mode 100644
index 00000000000..2a34566e1b4
Binary files /dev/null and b/docs/quickstart/lidar_calibration/images/good_calib.png differ
diff --git a/docs/quickstart/lidar_calibration/images/install.png b/docs/quickstart/lidar_calibration/images/install.png
new file mode 100644
index 00000000000..d11dacb7bd3
Binary files /dev/null and b/docs/quickstart/lidar_calibration/images/install.png differ
diff --git a/docs/quickstart/lidar_calibration/images/poor_calib.png b/docs/quickstart/lidar_calibration/images/poor_calib.png
new file mode 100644
index 00000000000..2bf45ac09d6
Binary files /dev/null and b/docs/quickstart/lidar_calibration/images/poor_calib.png differ
diff --git a/docs/quickstart/lidar_calibration/images/trajectory.png b/docs/quickstart/lidar_calibration/images/trajectory.png
new file mode 100644
index 00000000000..0474283dc77
Binary files /dev/null and b/docs/quickstart/lidar_calibration/images/trajectory.png differ
diff --git a/docs/specs/3d_obstacle_perception.md b/docs/specs/3d_obstacle_perception.md
new file mode 100644
index 00000000000..62eaa968db8
--- /dev/null
+++ b/docs/specs/3d_obstacle_perception.md
@@ -0,0 +1,399 @@
+3D Obstacle Perception
+===================
+
+The following sections describe the perception pipeline of obstacles
+that are resolved by Apollo:
+
+- HDMap Region of Interest (ROI) Filter
+
+- Convolutional Neural Networks (CNN) Segmentation
+
+- MinBox Builder
+
+- HM Object Tracker
+
+HDMap Region of Interest (ROI) Filter
+-------------------------------------
+
+The Region of Interest (ROI) specifies the drivable area that includes
+road surfaces and junctions and are retrieved from the HD
+(hi-resolution) map. The HDMap ROI filter processes LiDAR points that
+are outside ROI, removing background objects, e.g., buildings and trees
+around the road. What remains are the point cloud in the ROI for
+subsequent processing.
+
+Given a HD map, the affiliation of each LiDAR point indicates whether it
+is inside or outside the ROI. Each LiDAR point can be queried with a
+lookup table (LUT) of 2D quantization of the region around the car. The
+input and output of the HDMap ROI filter module are summarized in the
+table below.
+
+ |Input |Output |
+ |------------------------------------------------------------------------- |---------------------------------------------------------------------------|
+ |The point cloud: A set of 3D points captured from LiDAR Sensor. |The indices of input points that are inside the ROI defined by HDMap. |
+ |HDMap: A set of polygons each of which is an ordered set of points. | |
+
+
+In general, the Apollo HDMap ROI filter consists of three successive
+steps:
+
+1. Coordinate transformation
+
+2. ROI LUT construction
+
+3. Point inquiry with ROI LUT
+
+### Coordinate Transformation
+
+For the HDMap ROI filter, the data interface for HD map is defined in
+terms of a set of polygons, each of which is actually an ordered set of
+points in the world coordinate system. Running an inquiry on the points
+with the HDMap ROI requires that the point cloud and polygons are
+represented in the same coordinate system. For this purpose, Apollo
+transforms the points of input point cloud and the HDMap polygons into a
+local coordinate system that originates from the LiDAR sensor’s
+location.
+
+### ROI LUT Construction
+
+To determine an input point whether inside or outside the ROI, Apollo
+adopts a grid-wise LUT that quantifies the ROI into a birds-eye view 2D
+grid. As shown in figure 1, this LUT covers a rectangle region, bounded
+by a predefined spatial range around the general view from above in the
+boundary of HDMap. Then it represents the affiliation with the ROI for
+each cell of the grid (i.e., 1/0 represents it is inside/outside the
+ROI). For computational efficiency, Apollo uses a scan line algorithm
+and bitmap encoding to construct the ROI LUT.
+
+
+Figure 1 Illustration of ROI lookup table (LUT)
+
+The blue lines show the boundary of HDMap ROI, including road surfaces and
+junctions. The red solid dot represents the origin of the local coordinate
+system corresponding to the LiDAR sensor’s location. The 2D grid is composed
+of 8×8 cells that are shown as green squares. The cells inside the ROI are
+blue-filled squares while the ones outside the ROI are yellow-filled squares.
+
+### Point Inquiry with ROI LUT
+
+Based on the ROI LUT, the affiliation of each input point is queried
+using two-step verification. Then, Apollo conducts data compilation and
+output as described below. For the point inquiry process, Apollo:
+
+1. Checks whether the point is inside or outside the rectangle region
+ of ROI LUT.
+
+2. Queries the corresponding cell of the point in the LUT for its
+ affiliation with respect to the ROI.
+
+3. Collects all the points that belong to the ROI and output their
+ indices with respect to the input point cloud.
+
+The user-defined parameters can be set in the configuration file of
+modules/perception/model/hdmap_roi_filter.config. Please refer the
+table below on the usage of parameters for HDMap ROI Filter.
+
+ |Parameter Name |Usage |Default |
+ |------------------- |------------------------------------------------------------------------------ |------------|
+ |rectangle |The range of ROI LUT (the 2D grid) with respect to the origin (LiDAR sensor). |70.0 meters |
+ |cell_size |The size of cells for quantizing the 2D grid. |0.25 meter |
+ |extend_dist |The distance of extending the ROI from the polygon boundary. |0.0 meter |
+
+Convolutional Neural Networks (CNN) Segmentation
+------------------------------------------------
+
+After the HDMap ROI filter, Apollo obtains the filtered point cloud that
+includes *only* the points inside ROI (i.e., the drivable road and
+junction areas). Most of the background obstacles, such as buildings and
+trees around the road region, have been removed, and the point cloud
+inside ROI is fed into the segmentation module. This process detects and
+segments out foreground obstacles, e.g., cars, trucks, bicycles, and
+pedestrians.
+
+ |Input |Output |
+ |---------------------------------------------------------------------------- |---------------------------------------------------------------|
+ |The point cloud (a set of 3D points) |A set of objects corresponding to obstacles in the ROI. |
+ |The point indices indicating points inside the ROI as defined in HDMap | |
+
+
+Apollo uses a deep CNN for accurate obstacle detection and segmentation.
+The Apollo CNN segmentation consists of four successive steps:
+
+- Channel Feature Extraction
+
+- CNN-Based Obstacle Predication
+
+- Obstacle Clustering
+
+- Post-processing
+
+The following sections describe the deep CNN in detail.
+
+### Channel Feature Extraction
+
+Given a frame of point cloud, Apollo build a birds-eye view (i.e.,
+projected to the X-Y plane) 2D grid in the local coordinate system. Each
+point within a predefined range with respect to the origin (i.e., the
+LiDAR sensor) is quantized into one cell of the 2D grid based on its X
+and Y coordinates. After quantization, Apollo computes 8 statistical
+measurements of the points for each cell of the grid, which will be the
+input channel features fed into the CNN in the next step. The
+statistical measurements computed are the:
+
+1. Maximum height of points in the cell
+
+2. Intensity of the highest point in the cell
+
+3. Mean height of points in the cell
+
+4. Mean intensity of points in the cell
+
+5. Number of points in the cell
+
+6. Angle of the cell’s center with respect to the origin
+
+7. Distance between the cell’s center and the origin
+
+8. Binary value indicating whether the cell is empty or occupied
+
+### CNN-Based Obstacle Predication
+
+Based on the channel features described above, Apollo uses a deep fully
+convolutional neural network (FCNN) to predict the cell-wise obstacle
+attributes including the offset displacement with respect to the
+potential object center, called center offset, (see figure 2 below),
+objectness, positiveness, and object height. As shown in figure 2, the
+input of the network is a *W*×*H*×*C* channel image where:
+
+- *W* represents the column number of the grid.
+
+- *H* represents the row number of the grid.
+
+- *C* represents the number of channel features.
+
+The FCNN is composed of three layers:
+
+- Downstream encoding layers (feature encoder)
+
+- Upstream decoding layers (feature decoder)
+
+- Obstacle attribute prediction layers (predictor)
+
+The feature encoder takes the channel feature image as input and
+successively down-samples its spatial resolution with increasing feature
+abstraction. Then the feature decoder gradually up-samples the encoded
+feature image to the spatial resolution of the input 2D grid, which can
+recover the spatial details of feature image to facilitate the cell-wise
+obstacle attribute prediction. The down-sampling and up-sampling
+operations are implemented in terms of stacked convolution/devolution
+layers with non-linear activation (i.e., ReLu) layers.
+
+
+
+Figure 2 The FCNN for cell-wise obstacle prediction
+
+### Obstacle Clustering
+
+After the CNN-based prediction step, Apollo obtains prediction
+information for individual cells. Apollo utilizes four cell object
+attribute images that contain the:
+
+- Center offset
+
+- Objectness
+
+- Positiveness
+
+- Object height
+
+To generate obstacle objects, Apollo constructs a directed graph based
+on the cell center offset prediction and searches the connected
+components as candidate object clusters.
+
+As shown in figure 3, each cell is a node of the graph and the directed
+edge is built based on the center offset prediction of the cell, which
+points to its parent node corresponding to another cell.
+
+Given this graph, Apollo adopts a compressed Union Find algorithm to
+efficiently find the connected components, each of which is a candidate
+obstacle object cluster. The objectness is the probability of being a
+valid object for one individual cell. So Apollo defines the non-object
+cells as the ones with the objectness less than 0.5. Thus Apollo filters
+out the empty cells and non-object ones for each candidate object
+cluster.
+
+
+
+Figure 3 Illustration of obstacle clustering
+
+(a) The red arrow represents the object center offset prediction for
+ each cell. The blue mask corresponds to the object cells for which
+ the objectness probability is no less than 0.5.
+
+(b) The cells within solid red polygon compose a candidate object
+ cluster.
+
+The red filled five-pointed stars indicate the root nodes (cells) of
+sub-graphs that correspond to the connected components. One candidate
+object cluster can be composed of multiple neighboring connected
+components whose root nodes are adjacent to each other.
+
+### Post-processing
+
+After clustering, Apollo obtains a set of candidate object clusters each
+of which includes several cells. In the post-processing step, Apollo
+first computes the detection confidence score and object height for each
+candidate cluster by averaging the positiveness and object height values
+of its involved cells respectively. Then, Apollo removes the points that
+are too high with respect to the predicted object height and collects
+the points of valid cells for each candidate cluster. Finally, Apollo
+removes the candidate clusters that have either a very low confidence
+score or small number of points, to output the final obstacle
+clusters/segments.
+
+The user-defined parameters can be set in the configuration file of
+modules/perception/model/cnn\_segmentation/cnnseg.conf. The table below
+explains the parameter usage and default values for CNN Segmentation.
+
+ |Parameter Name |Usage |Default |
+ |-----------------------------------|--------------------------------------------------------------------------------------------|-----------|
+ |objectness_thresh |The threshold of objectness for filtering out non-object cells in obstacle clustering step. |0.5 |
+ |use_all_grids_for_clustering |The option of specifying whether or not to use all cells to construct the graph in the obstacle clustering step.If not, only the occupied cells will be considered. |true |
+ |confidence_thresh |The detection confidence score threshold for filtering out the candidate clusters in the post-processing step. |0.1 |
+ |height_thresh |If it is non-negative, the points that are higher than the predicted object height by height_thresh will be filtered out in the post-processing step. |0.5 meters |
+ |min_pts_num |In the post-processing step, the candidate clusters with less than min_pts_num points are removed. |3 |
+ |use_full_cloud |If it is set by true, all the points of the original point cloud will be used for extracting channel features. Otherwise only the points of input point cloud (i.e., the points after HDMap ROI filter) are used. |true |
+ |grid_id |The ID of the GPU device used in the CNN-based obstacle prediction step. |0 |
+ |feature_param {width} |The number of cells in X (column) axis of the 2D grid. |512 |
+ |feature_param {height} |The number of cells in Y (row) axis of the 2D grid. |512 |
+ |feature_param {range} |The range of the 2D grid with respect to the origin (the LiDAR sensor). |60 meters |
+
+
+
+MinBox Builder
+--------------
+
+The object builder component establishes a bounding box for the detected
+obstacles. Due to occlusions or distance to the LiDAR sensor, the point
+cloud forming an obstacle can be sparse and cover only a portion of
+surfaces. Thus, the box builder works to recover the full bounding box
+given the polygon point. The main purpose of the bounding box is to
+estimate the heading of the obstacle (e.g., vehicle) even if the point
+cloud is sparse. Equally, the bounding box is used to visualize the
+obstacles.
+
+The idea behind the algorithm is to find the all areas given an edge of
+the polygon point. In the following example, if AB is the edge, Apollo
+projects other polygon points onto AB and establishes the pair of
+intersections that has the maximum distance. That’s one of the edges
+belonging to the bounding box. Then it is straightforward to obtain the
+other edge of the bounding box. By iterating all edges in the polygon,
+in the following example as shown in figure 4, Apollo determines a
+6-edge bounding box. Apollo then selects the solution that has the
+minimum area as the final bounding box.
+
+
+
+Figure 4 Illustration of MinBox Object Builder
+
+HM Object Tracker
+-----------------
+
+The HM object tracker is designed to track obstacles detected by the
+segmentation step. In general, it forms and updates track lists by
+associating current detections with existing track lists, deletes the
+old track lists if it no longer persists, and spawns new track lists if new detections are identified. The motion state of the updated track
+lists will be estimated after association. In HM object tracker, the
+Hungarian algorithm is used for detection-to-track association, and a
+Robust Kalman Filter is adopted for motion estimation.
+
+### Detection-to-Track Association
+
+When associating detection to existing track lists, Apollo constructs a
+bipartite graph and then uses the Hungarian algorithm to find the best
+detection-to-track matching with minimum cost (distance).
+
+**Computing Association Distance Matrix**
+
+In the first step, an association distance matrix is established. The
+distance between a given detection and one track is calculated according to
+a series of association features including motion consistency,
+appearance consistency, etc. Some features used in HM tracker’s distance
+computing are shown as below:
+
+ |Association Feature Name |Description |
+ |-------------------------|----------------------------------|
+ |location_distance |Evaluating motion consistency |
+ |direction_distance |Evaluating motion consistency |
+ |bbox_size_distance |Evaluating appearance consistency |
+ |point_num_distance |Evaluating appearance consistency |
+ |histogram_distance |Evaluating appearance consistency |
+
+Besides, there are some important parameters of distance weights which are
+used for combining the above-mentioned association features into a final
+distance measurement.
+
+**Bipartite Graph Matching via Hungarian Algorithm**
+
+Given the association distance matrix, as shown in figure 5, Apollo
+constructs a bipartite graph and uses Hungarian algorithm to find the
+best detection-to-track matching via minimizing the distance cost. It
+solves the assignment problem within O(n\^3) time complexity. To boost
+its computing performance, the Hungarian algorithm is implemented after
+cutting original bipartite graph into subgraphs, by deleting vertices
+with distance greater than a reasonable maximum distance threshold.
+
+
+
+Figure 5 Illustration of Bipartite Graph Matching
+
+### Track Motion Estimation
+
+After the detection-to-track association, HM object tracker uses a
+Robust Kalman Filter to estimate the motion states of current track
+lists with a constant velocity motion model. The motion states include
+its belief anchor point and belief velocity, which correspond to the 3D
+position and its 3D velocity respectively. To overcome possible
+distraction caused from imperfect detections, Robust Statistics
+techniques are implemented in the tracker’s filtering algorithm.
+
+**Observation Redundancy**
+
+The measurement of velocity, which is the input of filtering algorithm,
+is selected among a series of redundant observations, including anchor
+point shift, bounding box center shift, bounding box corner point shift,
+etc. Redundant observations will bring extra robustness to filtering
+measurement, as the probability that all observations fail is much less
+than the one that a single observation fails.
+
+**Breakdown**
+
+Gaussian Filter algorithms always assume their noises are generated from
+Gaussian distribution. However, this hypothesis may fail in motion
+estimation problem, as the noise of its measurement may draw from
+fat-tail distributions. To overcome the over-estimation of update gain,
+a breakdown threshold is used in the process of filtering.
+
+**Update according Association Quality**
+
+The original Kalman Filter updates its states without distinguishing the
+quality of its measurements. However, the quality of measurement is a
+beneficial cue of filtering noise and somehow can be estimated. For
+instance, the distance calculated in the association step could be a
+reasonable estimate of quality of measurement. Updating the state of
+filtering algorithm according to the association quality enhances
+robustness and smoothness to the motion estimation problem.
+
+A high-level workflow of HM object tracker is given in figure 6.
+
+
+
+Figure 6 Workflow of HM Object Tracker
+
+1) Construct the tracked objects and transform them into world coordinates.
+
+2) Predict the states of existing track lists and match detections to
+ them.
+
+3) Update the motion state of updated track lists and collect the
+ tracking results.
diff --git a/docs/specs/images/3d_obstacle_perception/FCNN.png b/docs/specs/images/3d_obstacle_perception/FCNN.png
new file mode 100644
index 00000000000..7bdb35d2cd0
Binary files /dev/null and b/docs/specs/images/3d_obstacle_perception/FCNN.png differ
diff --git a/docs/specs/images/3d_obstacle_perception/bipartite_graph_matching.png b/docs/specs/images/3d_obstacle_perception/bipartite_graph_matching.png
new file mode 100644
index 00000000000..643208bc101
Binary files /dev/null and b/docs/specs/images/3d_obstacle_perception/bipartite_graph_matching.png differ
diff --git a/docs/specs/images/3d_obstacle_perception/hm_object_tracker.png b/docs/specs/images/3d_obstacle_perception/hm_object_tracker.png
new file mode 100644
index 00000000000..392967b68f1
Binary files /dev/null and b/docs/specs/images/3d_obstacle_perception/hm_object_tracker.png differ
diff --git a/docs/specs/images/3d_obstacle_perception/object_building.png b/docs/specs/images/3d_obstacle_perception/object_building.png
new file mode 100644
index 00000000000..65c488f1bfc
Binary files /dev/null and b/docs/specs/images/3d_obstacle_perception/object_building.png differ
diff --git a/docs/specs/images/3d_obstacle_perception/obstacle_clustering.png b/docs/specs/images/3d_obstacle_perception/obstacle_clustering.png
new file mode 100644
index 00000000000..1a5401190e8
Binary files /dev/null and b/docs/specs/images/3d_obstacle_perception/obstacle_clustering.png differ
diff --git a/docs/specs/images/3d_obstacle_perception/roi_lookup_table.png b/docs/specs/images/3d_obstacle_perception/roi_lookup_table.png
new file mode 100644
index 00000000000..d6db87594c1
Binary files /dev/null and b/docs/specs/images/3d_obstacle_perception/roi_lookup_table.png differ
diff --git a/docs/specs/lidar_calibration.pdf b/docs/specs/lidar_calibration.pdf
new file mode 100644
index 00000000000..7c079ef8d17
Binary files /dev/null and b/docs/specs/lidar_calibration.pdf differ
diff --git a/docs/specs/lidar_calibration_cn.pdf b/docs/specs/lidar_calibration_cn.pdf
new file mode 100644
index 00000000000..9f017351cee
Binary files /dev/null and b/docs/specs/lidar_calibration_cn.pdf differ
diff --git a/docs/specs/qp_spline_path_optimizer.md b/docs/specs/qp_spline_path_optimizer.md
new file mode 100644
index 00000000000..13710b41c13
--- /dev/null
+++ b/docs/specs/qp_spline_path_optimizer.md
@@ -0,0 +1,298 @@
+# QP-Spline-Path Optimizer
+
+Quadratic programming + Spline interpolation
+
+## 1. Objective function
+
+### 1.1 Get path length
+
+Path is defined in station-lateral coordination system. The **s** range from vehicle's current position to default planing path length.
+
+### 1.2 Get spline segments
+
+Split the path into **n** segments. each segment trajectory is defined by a polynomial.
+
+### 1.3 Define function for each spline segment
+
+Each segment ***i*** has accumulated distance $d_i$ along reference line. The trajectory for the segment is defined as a polynomial of degree five by default.
+
+$$
+l = f_i(s)
+ = a_{i0} + a_{i1} * s + a_{i2} * s^2 + a_{i3} * s^3 + a_{i4} * s^4 + a_{i5} * s^5 (0 \leq s \leq d_{i})
+$$
+
+### 1.4 Define objective function of optimization for each segment
+
+$$
+cost = \sum_{i=1}^{n} \Big( w_1 \cdot \int\limits_{0}^{d_i} (f_i')^2(s) ds + w_2 \cdot \int\limits_{0}^{d_i} (f_i'')^2(s) ds + w_3 \cdot \int\limits_{0}^{d_i} (f_i^{\prime\prime\prime})^2(s) ds \Big)
+$$
+
+### 1.5 Convert the cost function to QP formulation
+
+QP formulation:
+$$
+\frac{1}{2} \cdot x^T \cdot H \cdot x + f^T \cdot x
+\\
+s.t. LB \leq x \leq UB
+\\
+A_{eq}x = b_{eq}
+\\
+Ax \leq b
+$$
+Below is the example for converting the cost function into the QP formulaiton.
+$$
+f_i(s) =
+\begin{vmatrix} a_{i0} & a_{i1} & a_{i2} & a_{i3} & a_{i4} & a_{i5} \end{vmatrix}
+\cdot
+\begin{vmatrix} 1 \\ s \\ s^2 \\ s^3 \\ s^4 \\ s^5 \end{vmatrix}
+$$
+
+And
+$$
+f_i'(s) =
+\begin{vmatrix} a_{i0} & a_{i1} & a_{i2} & a_{i3} & a_{i4} & a_{i5} \end{vmatrix}
+\cdot
+\begin{vmatrix} 0 \\ 1 \\ s \\ s^2 \\ s^3 \\ s^4 \end{vmatrix}
+$$
+
+
+And
+$$
+f_i'(s)^2 =
+\begin{vmatrix} a_{i0} & a_{i1} & a_{i2} & a_{i3} & a_{i4} & a_{i5} \end{vmatrix}
+\cdot
+\begin{vmatrix} 0 \\ 1 \\ s \\ s^2 \\ s^3 \\ s^4 \end{vmatrix}
+\cdot
+\begin{vmatrix} 0 & 1 & s & s^2 & s^3 & s^4 \end{vmatrix}
+\cdot
+\begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix}
+$$
+And
+$$
+\int\limits_{0}^{d_i} f_i'(s)^2 ds =
+\int\limits_{0}^{d_i}
+\begin{vmatrix} a_{i0} & a_{i1} & a_{i2} & a_{i3} & a_{i4} & a_{i5} \end{vmatrix}
+\cdot
+\begin{vmatrix} 0 \\ 1 \\ s \\ s^2 \\ s^3 \\ s^4 \end{vmatrix}
+\cdot
+\begin{vmatrix} 0 & 1 & s & s^2 & s^3 & s^4 \end{vmatrix}
+\cdot
+\begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix} ds
+$$
+
+
+And
+$$
+\int\limits_{0}^{d_i} f'(s)^2 ds =
+\begin{vmatrix} a_{i0} & a_{i1} & a_{i2} & a_{i3} & a_{i4} & a_{i5} \end{vmatrix}
+\cdot
+\int\limits_{0}^{d_i}
+\begin{vmatrix} 0 \\ 1 \\ s \\ s^2 \\ s^3 \\ s^4 \end{vmatrix}
+\cdot
+\begin{vmatrix} 0 & 1 & s & s^2 & s^3 & s^4 \end{vmatrix} ds
+\cdot
+\begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix}
+$$
+
+
+And
+$$
+\int\limits_{0}^{d_i}
+f'(s)^2 ds =\begin{vmatrix} a_{i0} & a_{i1} & a_{i2} & a_{i3} & a_{i4} & a_{i5} \end{vmatrix}
+\cdot \int\limits_{0}^{d_i}
+\begin{vmatrix}
+0 & 0 &0&0&0&0\\
+0 & 1 & s & s^2 & s^3 & s^4\\
+0 & s & s^2 & s^3 & s^4 & s^5\\
+0 & s^2 & s^3 & s^4&s^5&s^6 \\
+0 & s^3 & s^4 &s^5 &s^6&s^7 \\
+0 & s^4 & s^5 & s^6 & s^7 & s^8
+\end{vmatrix} ds
+\cdot
+\begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix}
+$$
+And
+$$
+\int\limits_{0}^{d_i}
+f'_i(s)^2 ds =\begin{vmatrix} a_{i0} & a_{i1} & a_{i2} & a_{i3} & a_{i4} & a_{i5} \end{vmatrix}
+\cdot \begin{vmatrix}
+0 & 0 & 0 & 0 &0&0\\
+0 & d_i & \frac{d_i^2}{2} & \frac{d_i^3}{3} & \frac{d_i^4}{4}&\frac{d_i^5}{5}\\
+0& \frac{d_i^2}{2} & \frac{d_i^3}{3} & \frac{d_i^4}{4} & \frac{d_i^5}{5}&\frac{d_i^6}{6}\\
+0& \frac{d_i^3}{3} & \frac{d_i^4}{4} & \frac{d_i^5}{5} & \frac{d_i^6}{6}&\frac{d_i^7}{7}\\
+0& \frac{d_i^4}{4} & \frac{d_i^5}{5} & \frac{d_i^6}{6} & \frac{d_i^7}{7}&\frac{d_i^8}{8}\\
+0& \frac{d_i^5}{5} & \frac{d_i^6}{6} & \frac{d_i^7}{7} & \frac{d_i^8}{8}&\frac{d_i^9}{9}\\
+\end{vmatrix}
+\cdot
+\begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix}
+$$
+
+## 2 Constraints
+
+### 2.1 The init point constraints
+
+Assume that the first point is ($s0$, $l0$), and that $l0$ is on the planned path $f_i(s)$, $f'i(s)$, and $f_i(s)''$. Convert those constraints into QP equality constraints, using:
+$$
+A_{eq}x = b_{eq}
+$$
+Below are the steps of conversion.
+$$
+f_i(s_0) =
+\begin{vmatrix} 1 & s_0 & s_0^2 & s_0^3 & s_0^4&s_0^5 \end{vmatrix}
+\cdot
+\begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5}\end{vmatrix} = l_0
+$$
+And
+$$
+f'_i(s_0) =
+\begin{vmatrix} 0& 1 & s_0 & s_0^2 & s_0^3 & s_0^4 \end{vmatrix}
+\cdot
+\begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix} = l_0
+$$
+And
+$$
+f''_i(s_0) =
+\begin{vmatrix} 0&0& 1 & s_0 & s_0^2 & s_0^3 \end{vmatrix}
+\cdot
+\begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix} = l_0
+$$
+The $i$ is the index of segment that contains the $s_0$.
+
+Therefore the equality constraint is:
+$$
+\begin{vmatrix}
+ 1 & s_0 & s_0^2 & s_0^3 & s_0^4&s_0^5 \\
+ 0&1 & s_0 & s_0^2 & s_0^3 & s_0^4 \\
+ 0& 0&1 & s_0 & s_0^2 & s_0^3
+ \end{vmatrix}
+ \cdot
+ \begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix}
+ =
+ \begin{vmatrix}
+ l_0\\
+ l_0\\
+ l_0\\
+ \end{vmatrix}
+$$
+
+### 2.2 The end point constraints
+
+Similar to the init point, the end point $(s_e, l_e)$ is known and should produce the same constraint as described in the init point calculations.
+
+Combine the init point and end point, and show the equality constraint as:
+$$
+\begin{vmatrix}
+ 1 & s_0 & s_0^2 & s_0^3 & s_0^4&s_0^5 \\
+ 0&1 & s_0 & s_0^2 & s_0^3 & s_0^4 \\
+ 0& 0&1 & s_0 & s_0^2 & s_0^3 \\
+ 1 & s_e & s_e^2 & s_e^3 & s_e^4&s_e^5 \\
+ 0&1 & s_e & s_e^2 & s_e^3 & s_e^4 \\
+ 0& 0&1 & s_e & s_e^2 & s_e^3
+ \end{vmatrix}
+ \cdot
+ \begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix}
+ =
+ \begin{vmatrix}
+ l_0\\
+ l_0\\
+ l_0\\
+ l_e\\
+ l_e\\
+ l_e\\
+ \end{vmatrix}
+$$
+
+
+### 2.3 Joint smoothness constraints
+
+This constraint is designed to smooth the spline joint. Assume two segments $seg_k$ and $seg_{k+1}$ are connected, and the accumulated **s** of segment $seg_k$ is $s_k$. Calculate the constraint equation as:
+$$
+f_k(s_k) = f_{k+1} (s_0)
+$$
+Below are the steps of the calculation.
+$$
+\begin{vmatrix}
+ 1 & s_k & s_k^2 & s_k^3 & s_k^4&s_k^5 \\
+ \end{vmatrix}
+ \cdot
+ \begin{vmatrix}
+ a_{k0} \\ a_{k1} \\ a_{k2} \\ a_{k3} \\ a_{k4} \\ a_{k5}
+ \end{vmatrix}
+ =
+\begin{vmatrix}
+ 1 & s_{0} & s_{0}^2 & s_{0}^3 & s_{0}^4&s_{0}^5 \\
+ \end{vmatrix}
+ \cdot
+ \begin{vmatrix}
+ a_{k+1,0} \\ a_{k+1,1} \\ a_{k+1,2} \\ a_{k+1,3} \\ a_{k+1,4} \\ a_{k+1,5}
+ \end{vmatrix}
+$$
+Then
+$$
+\begin{vmatrix}
+ 1 & s_k & s_k^2 & s_k^3 & s_k^4&s_k^5 & -1 & -s_{0} & -s_{0}^2 & -s_{0}^3 & -s_{0}^4&-s_{0}^5\\
+ \end{vmatrix}
+ \cdot
+ \begin{vmatrix}
+ a_{k0} \\ a_{k1} \\ a_{k2} \\ a_{k3} \\ a_{k4} \\ a_{k5} \\ a_{k+1,0} \\ a_{k+1,1} \\ a_{k+1,2} \\ a_{k+1,3} \\ a_{k+1,4} \\ a_{k+1,5}
+ \end{vmatrix}
+ = 0
+$$
+Use $s_0$ = 0 in the equation.
+
+Similarly calculate the equality constraints for:
+$$
+f'_k(s_k) = f'_{k+1} (s_0)
+\\
+f''_k(s_k) = f''_{k+1} (s_0)
+\\
+f'''_k(s_k) = f'''_{k+1} (s_0)
+$$
+
+### 2.4 Sampled points for boundary constraint
+
+Evenly sample **m** points along the path, and check the obstacle boundary at those points. Convert the constraint into QP inequality constraints, using:
+$$
+Ax \leq b
+$$
+First find the lower boundary $l_{lb,j}$ at those points ($s_j$, $l_j$) and $j\in[0, m]$ based on the road width and surrounding obstacles. Calculate the inequality constraints as:
+$$
+\begin{vmatrix}
+ 1 & s_0 & s_0^2 & s_0^3 & s_0^4&s_0^5 \\
+ 1 & s_1 & s_1^2 & s_1^3 & s_1^4&s_1^5 \\
+ ...&...&...&...&...&... \\
+ 1 & s_m & s_m^2 & s_m^3 & s_m^4&s_m^5 \\
+ \end{vmatrix} \cdot \begin{vmatrix}a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix}
+ \leq
+ \begin{vmatrix}
+ l_{lb,0}\\
+ l_{lb,1}\\
+ ...\\
+ l_{lb,m}\\
+ \end{vmatrix}
+$$
+
+
+Similarly, for the upper boundary $l_{ub,j}$, calculate the inequality constraints as:
+$$
+\begin{vmatrix}
+ 1 & s_0 & s_0^2 & s_0^3 & s_0^4&s_0^5 \\
+ 1 & s_1 & s_1^2 & s_1^3 & s_1^4&s_1^5 \\
+ ...&...&...&...&...&... \\
+ 1 & s_m & s_m^2 & s_m^3 & s_m^4&s_m^5 \\
+ \end{vmatrix}
+ \cdot
+ \begin{vmatrix} a_{i0} \\ a_{i1} \\ a_{i2} \\ a_{i3} \\ a_{i4} \\ a_{i5} \end{vmatrix}
+ \leq
+ -1 \cdot
+ \begin{vmatrix}
+ l_{ub,0}\\
+ l_{ub,1}\\
+ ...\\
+ l_{ub,m}\\
+ \end{vmatrix}
+$$
+
+
+
+
diff --git a/docs/specs/qp_spline_st_speed_optimizer.md b/docs/specs/qp_spline_st_speed_optimizer.md
new file mode 100644
index 00000000000..ecb3b743c66
--- /dev/null
+++ b/docs/specs/qp_spline_st_speed_optimizer.md
@@ -0,0 +1,225 @@
+# QP-Spline-ST-Speed Optimizer
+
+
+
+## 1 Definition
+
+After finding a path in QP-Spline-Path, Apollo converts all obstacles on the path and the ADV (autonomous driving vehicle) into an ST graph, which represents the station changes over time along the path. The speed optimization task is to find a path on the ST graph that is collision-free and safe.
+
+Apollo uses spline to define the path. To find the best path, Apollo leverages Quadratic programming with a set of conditions. The QP formulation is defined as:
+$$
+\frac{1}{2} \cdot x^T \cdot H \cdot x + f^T \cdot x
+\\
+s.t. LB \leq x \leq UB
+\\
+A_{eq}x = b_{eq}
+\\
+Ax \leq b
+$$
+
+## 2 Objective function
+
+### 1.1 Get spline segments
+
+Split the path into **n** segments. Each segment trajectory is defined by a polynomial.
+
+### 1.2 Define function for each spline segment
+
+Each segment ***i*** has accumulated distance $d_i$ along a reference line. And the trajectory for the segment is defined as a polynomial of degree five by default.
+
+$$
+s = f_i(t)
+ = a_{0i} + a_{1i} \cdot t + a_{2i} \cdot t^2 + a_{3i} \cdot t^3 + a_{4i} \cdot t^4 + a_{5i} \cdot t^5
+$$
+
+### 1.3 Define objective function of optimization for each segment
+
+Apollo first defines $cost_1$ to make the trajectory smooth:
+$$
+cost_1 = \sum_{i=1}^{n} \Big( w_1 \cdot \int\limits_{0}^{d_i} (f_i')^2(s) ds + w_2 \cdot \int\limits_{0}^{d_i} (f_i'')^2(s) ds + w_3 \cdot \int\limits_{0}^{d_i} (f_i^{\prime\prime\prime})^2(s) ds \Big)
+$$
+
+Then Apollo defines $cost_2$ as the difference between the final ST trajectory and the cruise ST trajectory (with given speed limits — m points):
+$$
+cost_2 = \sum_{i=1}^{n}\sum_{j=1}^{m}\Big(f_i(t_j)- s_j\Big)^2
+$$
+Similarly, Apollo defines $cost_3$ that is the difference between the first ST path and the follow ST path (o points):
+$$
+cost_3 = \sum_{i=1}^{n}\sum_{j=1}^{o}\Big(f_i(t_j)- s_j\Big)^2
+$$
+Finally, the objective function is defined as:
+$$
+cost = cost_1 + cost_2 + cost_3
+$$
+
+## 3 Constraints
+
+### 3.1 The init point constraints
+
+Given the assumption that the the first point is ($t0$, $s0$), and $s0$ is on the planned path $f_i(t)$, $f'i(t)$, and $f_i(t)''$ (position, velocity, acceleration). Apollo converts those constraint into QP equality constraints:
+$$
+A_{eq}x = b_{eq}
+$$
+
+### 3.2 Monotone constraint
+
+The path must be monotone, e.g., the vehicle can only drive forward.
+
+Sample **m** points on the path, for each $j$ and $j-1$ point pairs ($j\in[1,...,m]$):
+
+If the two points on the same spline $k$:
+$$
+\begin{vmatrix} 1 & t_j & t_j^2 & t_j^3 & t_j^4&t_j^5 \\ \end{vmatrix}
+\cdot
+\begin{vmatrix} a_k \\ b_k \\ c_k \\ d_k \\ e_k \\ f_k \end{vmatrix}
+>
+\begin{vmatrix} 1 & t_{j-1} & t_{j-1}^2 & t_{j-1}^3 & t_{j-1}^4&t_{j-1}^5 \\ \end{vmatrix}
+\cdot
+\begin{vmatrix} a_{k} \\ b_{k} \\ c_{k} \\ d_{k} \\ e_{k} \\ f_{k} \end{vmatrix}
+$$
+ If the two points on the different spline $k$ and $l$:
+$$
+\begin{vmatrix} 1 & t_j & t_j^2 & t_j^3 & t_j^4&t_j^5 \\ \end{vmatrix}
+\cdot
+\begin{vmatrix} a_k \\ b_k \\ c_k \\ d_k \\ e_k \\ f_k \end{vmatrix}
+>
+\begin{vmatrix} 1 & t_{j-1} & t_{j-1}^2 & t_{j-1}^3 & t_{j-1}^4&t_{j-1}^5 \\ \end{vmatrix}
+\cdot
+\begin{vmatrix} a_{l} \\ b_{l} \\ c_{l} \\ d_{l} \\ e_{l} \\ f_{l} \end{vmatrix}
+$$
+
+
+
+### 3.3 Joint smoothness constraints
+
+This constraint is designed to smooth the spline joint. Given the assumption that two segments, $seg_k$ and $seg_{k+1}$, are connected, and the accumulated **s** of segment is $seg_k$ is $s_k$, Apollo calculates the constraint equation as:
+$$
+f_k(t_k) = f_{k+1} (t_0)
+$$
+Namely:
+$$
+\begin{vmatrix}
+ 1 & t_k & t_k^2 & t_k^3 & t_k^4&t_k^5 \\
+ \end{vmatrix}
+ \cdot
+ \begin{vmatrix}
+ a_{k0} \\ a_{k1} \\ a_{k2} \\ a_{k3} \\ a_{k4} \\ a_{k5}
+ \end{vmatrix}
+ =
+\begin{vmatrix}
+ 1 & t_{0} & t_{0}^2 & t_{0}^3 & t_{0}^4&t_{0}^5 \\
+ \end{vmatrix}
+ \cdot
+ \begin{vmatrix}
+ a_{k+1,0} \\ a_{k+1,1} \\ a_{k+1,2} \\ a_{k+1,3} \\ a_{k+1,4} \\ a_{k+1,5}
+ \end{vmatrix}
+$$
+Then
+$$
+\begin{vmatrix}
+ 1 & t_k & t_k^2 & t_k^3 & t_k^4&t_k^5 & -1 & -t_{0} & -t_{0}^2 & -t_{0}^3 & -t_{0}^4&-t_{0}^5\\
+ \end{vmatrix}
+ \cdot
+ \begin{vmatrix}
+ a_{k0} \\ a_{k1} \\ a_{k2} \\ a_{k3} \\ a_{k4} \\ a_{k5} \\ a_{k+1,0} \\ a_{k+1,1} \\ a_{k+1,2} \\ a_{k+1,3} \\ a_{k+1,4} \\ a_{k+1,5}
+ \end{vmatrix}
+ = 0
+$$
+The result is $t_0$ = 0 in the equation.
+
+Similarly calculate the equality constraints for
+$$
+f'_k(t_k) = f'_{k+1} (t_0)
+\\
+f''_k(t_k) = f''_{k+1} (t_0)
+\\
+f'''_k(t_k) = f'''_{k+1} (t_0)
+$$
+
+### 3.4 Sampled points for boundary constraint
+
+Evenly sample **m** points along the path, and check the obstacle boundary at those points. Convert the constraint into QP inequality constraints, using:
+$$
+Ax \leq b
+$$
+Apollo first finds the lower boundary $l_{lb,j}$ at those points ($s_j$, $l_j$) and $j\in[0, m]$ based on the road width and surrounding obstacles. Then it calculates the inequality constraints as:
+$$
+\begin{vmatrix}
+ 1 & t_0 & t_0^2 & t_0^3 & t_0^4&t_0^5 \\
+ 1 & t_1 & t_1^2 & t_1^3 & t_1^4&t_1^5 \\
+ ...&...&...&...&...&... \\
+ 1 & t_m & t_m^2 & t_m^3 & t_m^4&t_m^5 \\
+ \end{vmatrix} \cdot \begin{vmatrix} a_i \\ b_i \\ c_i \\ d_i \\ e_i \\ f_i \end{vmatrix}
+ \leq
+ \begin{vmatrix}
+ l_{lb,0}\\
+ l_{lb,1}\\
+ ...\\
+ l_{lb,m}\\
+ \end{vmatrix}
+$$
+
+
+Similarly, for upper boundary $l_{ub,j}$, Apollo calculates the inequality constraints as:
+$$
+\begin{vmatrix}
+ 1 & t_0 & t_0^2 & t_0^3 & t_0^4&t_0^5 \\
+ 1 & t_1 & t_1^2 & t_1^3 & t_1^4&t_1^5 \\
+ ...&...&...&...&...&... \\
+ 1 & t_m & t_m^2 & t_m^3 & t_m^4&t_m^5 \\
+ \end{vmatrix} \cdot \begin{vmatrix} a_i \\ b_i \\ c_i \\ d_i \\ e_i \\ f_i \end{vmatrix}
+ \leq
+ -1 \cdot
+ \begin{vmatrix}
+ l_{ub,0}\\
+ l_{ub,1}\\
+ ...\\
+ l_{ub,m}\\
+ \end{vmatrix}
+$$
+
+
+
+### 3.5 Speed Boundary constraint
+
+Apollo establishes a speed limit boundary as well.
+
+Sample **m** points on the st curve, and get speed limits defined as an upper boundary and a lower boundary for each point $j$, e.g., $v{ub,j}$ and $v{lb,j}$ . The constraints are defined as:
+$$
+f'(t_j) \geq v_{lb,j}
+$$
+Namely
+$$
+\begin{vmatrix}
+0& 1 & t_0 & t_0^2 & t_0^3 & t_0^4 \\
+0 & 1 & t_1 & t_1^2 & t_1^3 & t_1^4 \\
+...&...&...&...&...&... \\
+0& 1 & t_m & t_m^2 & t_m^3 & t_m^4 \\
+\end{vmatrix}
+\cdot
+\begin{vmatrix}
+a_i \\ b_i \\ c_i \\ d_i \\ e_i \\ f_i
+\end{vmatrix}
+\geq
+\begin{vmatrix} v_{lb,0}\\ v_{lb,1}\\ ...\\ v_{lb,m}\\ \end{vmatrix}
+$$
+And
+$$
+f'(t_j) \leq v_{ub,j}
+$$
+Namely
+$$
+\begin{vmatrix}
+ 0& 1 & t_0 & t_0^2 & t_0^3 & t_0^4 \\
+ 0 & 1 & t_1 & t_1^2 & t_1^3 & t_1^4 \\
+ ...&...&...&...&...&... \\
+ 0 &1 & t_m & t_m^2 & t_m^3 & t_m^4 \\
+ \end{vmatrix} \cdot \begin{vmatrix} a_i \\ b_i \\ c_i \\ d_i \\ e_i \\ f_i \end{vmatrix}
+ \leq
+ \begin{vmatrix}
+ v_{ub,0}\\
+ v_{ub,1}\\
+ ...\\
+ v_{ub,m}\\
+ \end{vmatrix}
+$$
diff --git a/docs/specs/reference_line_smoother.md b/docs/specs/reference_line_smoother.md
new file mode 100644
index 00000000000..37c0b9369eb
--- /dev/null
+++ b/docs/specs/reference_line_smoother.md
@@ -0,0 +1,79 @@
+# reference line smoother
+
+Quadratic programming + Spline interpolation
+
+## 1. Objective function
+
+### 1.1 Segment routing path
+
+Segment routing path into **n** segments. each segment trajectory is defined by two polynomials:
+
+$$
+x = f_i(t)
+ = a_{i0} + a_{i1} * t + a_{i2} * t^2 + a_{i3} * t^3 + a_{i4} * t^4 + a_{i5} * t^5
+$$
+
+$$
+y = g_i(t) = b_{i0} + b_{i1} * t + b_{i2} * t^2 + b_{i3} * t^3 + b_{i4} * t^4 + b_{i5} * t^5
+$$
+
+### 1.2 Define objective function of optimization for each segment
+
+$$
+cost =
+\sum_{i=1}^{n}
+\Big(
+\int\limits_{0}^{t_i} (f_i''')^2(t) dt
++ \int\limits_{0}^{t_i} (g_i''')^2(t) dt
+\Big)
+$$
+
+### 1.3 Convert the cost function to QP formulation
+
+QP formulation:
+$$
+\frac{1}{2} \cdot x^T \cdot H \cdot x + f^T \cdot x
+\\
+s.t. LB \leq x \leq UB
+\\
+A_{eq}x = b_{eq}
+\\
+Ax \leq b
+$$
+
+
+## 2 Constraints
+
+
+### 2.1 Joint smoothness constraints
+
+This constraint smoothes the spline joint. Let's assume two segments, $seg_k$ and $seg_{k+1}$, are connected and the accumulated **s** of segment $seg_k$ is $s_k$. Calculate the constraint equation as:
+$$
+f_k(s_k) = f_{k+1} (s_0)
+$$
+Similarly the formula works for the equality constraints, such as:
+$$
+f'_k(s_k) = f'_{k+1} (s_0)
+\\
+f''_k(s_k) = f''_{k+1} (s_0)
+\\
+f'''_k(s_k) = f'''_{k+1} (s_0)
+\\
+g_k(s_k) = g_{k+1} (s_0)
+\\
+g'_k(s_k) = g'_{k+1} (s_0)
+\\
+g''_k(s_k) = g''_{k+1} (s_0)
+\\
+g'''_k(s_k) = g'''_{k+1} (s_0)
+$$
+
+### 2.2 Sampled points for boundary constraint
+
+Evenly sample **m** points along the path and check the predefined boundaries at those points.
+$$
+f_i(t_l) - x_l< boundary
+\\
+g_i(t_l) - y_l< boundary
+$$
+
diff --git a/modules/calibration/data/beijing_mkz/64E_S3_calibration_example.yaml b/modules/calibration/data/beijing_mkz/64E_S3_calibration_example.yaml
new file mode 100644
index 00000000000..a02c68421c5
--- /dev/null
+++ b/modules/calibration/data/beijing_mkz/64E_S3_calibration_example.yaml
@@ -0,0 +1,243 @@
+lasers:
+- {dist_correction: 1.3280478, dist_correction_x: 1.3733278999999998, dist_correction_y: 1.3565268000000001,
+ focal_distance: 12.0, focal_slope: 0.75, horiz_offset_correction: 0.025999999, laser_id: 0,
+ min_intensity: 5, rot_correction: -0.08042396035379652, vert_correction: -0.12376696608832838,
+ vert_offset_correction: 0.21551828}
+- {dist_correction: 1.4387065, dist_correction_x: 1.4772083, dist_correction_y: 1.4930743000000002,
+ focal_distance: 18.5, focal_slope: 1.1, horiz_offset_correction: -0.025999999, laser_id: 1,
+ min_intensity: 40, rot_correction: -0.043931143295210404, vert_correction: -0.11852979325378328,
+ vert_offset_correction: 0.21513613}
+- {dist_correction: 1.4198532000000001, dist_correction_x: 1.4513388, dist_correction_y: 1.4459473,
+ focal_distance: 17.0, focal_slope: 1.25, horiz_offset_correction: 0.025999999, laser_id: 2,
+ min_intensity: 40, rot_correction: 0.05671893510512383, vert_correction: 0.006831742116548479,
+ vert_offset_correction: 0.20608189}
+- {dist_correction: 1.432045, dist_correction_x: 1.4576363, dist_correction_y: 1.5053079,
+ focal_distance: 24.0, focal_slope: 0.94999999, horiz_offset_correction: -0.025999999,
+ laser_id: 3, min_intensity: 40, rot_correction: 0.09507418428186684, vert_correction: 0.011737269755557637,
+ vert_offset_correction: 0.2057291}
+- {dist_correction: 1.3768561, dist_correction_x: 1.4095345000000001, dist_correction_y: 1.4140973,
+ focal_distance: 24.0, focal_slope: 0.60000002, horiz_offset_correction: 0.025999999,
+ laser_id: 4, min_intensity: 40, rot_correction: -0.0052020566354620415, vert_correction: -0.11207511538496126,
+ vert_offset_correction: 0.21466578}
+- {dist_correction: 1.4579066, dist_correction_x: 1.5030013, dist_correction_y: 1.5402745,
+ focal_distance: 23.0, focal_slope: 0.80000001, horiz_offset_correction: -0.025999999,
+ laser_id: 5, min_intensity: 40, rot_correction: 0.034271327080062704, vert_correction: -0.10662164389621649,
+ vert_offset_correction: 0.21426891}
+- {dist_correction: 1.4042904999999999, dist_correction_x: 1.4512584000000002, dist_correction_y: 1.4358795000000002,
+ focal_distance: 24.0, focal_slope: 0.80000001, horiz_offset_correction: 0.025999999,
+ laser_id: 6, min_intensity: 40, rot_correction: -0.019350118096339984, vert_correction: -0.14744596324186607,
+ vert_offset_correction: 0.21725271}
+- {dist_correction: 1.4530759, dist_correction_x: 1.4934110999999999, dist_correction_y: 1.4934732,
+ focal_distance: 16.5, focal_slope: 0.80000001, horiz_offset_correction: -0.025999999,
+ laser_id: 7, min_intensity: 40, rot_correction: 0.019696635766030937, vert_correction: -0.1420415773930044,
+ vert_offset_correction: 0.21685585}
+- {dist_correction: 1.3928452999999998, dist_correction_x: 1.4412779, dist_correction_y: 1.4351759000000002,
+ focal_distance: 24.0, focal_slope: 0.64999998, horiz_offset_correction: 0.025999999,
+ laser_id: 8, min_intensity: 10, rot_correction: 0.06977400140069993, vert_correction: -0.10055477120587059,
+ vert_offset_correction: 0.21382797}
+- {dist_correction: 1.4649026, dist_correction_x: 1.4811482, dist_correction_y: 1.5390858,
+ focal_distance: 16.5, focal_slope: 1.2, horiz_offset_correction: -0.025999999, laser_id: 9,
+ min_intensity: 40, rot_correction: 0.10867481606700684, vert_correction: -0.09508820800240662,
+ vert_offset_correction: 0.21343111}
+- {dist_correction: 1.3307669000000002, dist_correction_x: 1.3797191000000002, dist_correction_y: 1.3716772000000002,
+ focal_distance: 24.0, focal_slope: 0.85000002, horiz_offset_correction: 0.025999999,
+ laser_id: 10, min_intensity: 40, rot_correction: 0.05614793318704137, vert_correction: -0.13622757149534595,
+ vert_offset_correction: 0.2164296}
+- {dist_correction: 1.3771700999999998, dist_correction_x: 1.4101131, dist_correction_y: 1.4538571,
+ focal_distance: 15.0, focal_slope: 1.35, horiz_offset_correction: -0.025999999,
+ laser_id: 11, min_intensity: 40, rot_correction: 0.09458836664858647, vert_correction: -0.13060523940147076,
+ vert_offset_correction: 0.21601805}
+- {dist_correction: 1.3797005, dist_correction_x: 1.4142267000000002, dist_correction_y: 1.4085233,
+ focal_distance: 10.0, focal_slope: 1.2, horiz_offset_correction: 0.025999999, laser_id: 12,
+ min_intensity: 10, rot_correction: -0.08058553944528767, vert_correction: -0.05321597901122562,
+ vert_offset_correction: 0.21040320999999998}
+- {dist_correction: 1.3646324, dist_correction_x: 1.3887102, dist_correction_y: 1.4070561000000001,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: -0.025999999, laser_id: 13,
+ min_intensity: 40, rot_correction: -0.04053784798354424, vert_correction: -0.04669103069605979,
+ vert_offset_correction: 0.20993286000000003}
+- {dist_correction: 1.3809781, dist_correction_x: 1.4282532000000001, dist_correction_y: 1.4207353,
+ focal_distance: 15.0, focal_slope: 1.3, horiz_offset_correction: 0.025999999, laser_id: 14,
+ min_intensity: 40, rot_correction: -0.09419900463641756, vert_correction: -0.08758781436692292,
+ vert_offset_correction: 0.21288727000000002}
+- {dist_correction: 1.3950202999999999, dist_correction_x: 1.4285829, dist_correction_y: 1.4621552,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: -0.025999999, laser_id: 15,
+ min_intensity: 40, rot_correction: -0.054354701628396805, vert_correction: -0.08292035016148458,
+ vert_offset_correction: 0.21254919000000003}
+- {dist_correction: 1.2988774, dist_correction_x: 1.3749954, dist_correction_y: 1.3734656,
+ focal_distance: 24.0, focal_slope: 0.64999998, horiz_offset_correction: 0.025999999,
+ laser_id: 16, min_intensity: 40, rot_correction: -0.005133124856654525, vert_correction: -0.04077432787988471,
+ vert_offset_correction: 0.20950663}
+- {dist_correction: 1.4723137, dist_correction_x: 1.5056056000000002, dist_correction_y: 1.5041873000000001,
+ focal_distance: 24.0, focal_slope: 1.0, horiz_offset_correction: -0.025999999, laser_id: 17,
+ min_intensity: 20, rot_correction: 0.033464606229193644, vert_correction: -0.03526310344619148,
+ vert_offset_correction: 0.20910976000000003}
+- {dist_correction: 1.3093359000000002, dist_correction_x: 1.4065028000000002, dist_correction_y: 1.3988147000000002,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: 0.025999999, laser_id: 18,
+ min_intensity: 20, rot_correction: -0.01912024950720607, vert_correction: -0.07662373803636939,
+ vert_offset_correction: 0.21209354000000002}
+- {dist_correction: 1.4292241, dist_correction_x: 1.4580751, dist_correction_y: 1.4810971000000002,
+ focal_distance: 24.0, focal_slope: 1.2, horiz_offset_correction: -0.025999999, laser_id: 19,
+ min_intensity: 15, rot_correction: 0.0202102704569296, vert_correction: -0.07052442491121666,
+ vert_offset_correction: 0.21165258}
+- {dist_correction: 1.3831145, dist_correction_x: 1.4038123999999998, dist_correction_y: 1.3966234,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: 0.025999999, laser_id: 20,
+ min_intensity: 30, rot_correction: 0.06874179273711946, vert_correction: -0.029137015224983895,
+ vert_offset_correction: 0.2086688}
+- {dist_correction: 1.402925, dist_correction_x: 1.4443744, dist_correction_y: 1.471532,
+ focal_distance: 17.0, focal_slope: 1.4, horiz_offset_correction: -0.025999999, laser_id: 21,
+ min_intensity: 5, rot_correction: 0.10747970535236223, vert_correction: -0.02341734437339572,
+ vert_offset_correction: 0.20825726}
+- {dist_correction: 1.4234489, dist_correction_x: 1.4673076, dist_correction_y: 1.4543761000000002,
+ focal_distance: 24.0, focal_slope: 0.55000001, horiz_offset_correction: 0.025999999,
+ laser_id: 22, min_intensity: 5, rot_correction: 0.05514045060297391, vert_correction: -0.0642162831410628,
+ vert_offset_correction: 0.21119694}
+- {dist_correction: 1.470387, dist_correction_x: 1.4879053, dist_correction_y: 1.5217740000000002,
+ focal_distance: 24.0, focal_slope: 1.3, horiz_offset_correction: -0.025999999, laser_id: 23,
+ min_intensity: 30, rot_correction: 0.09433926976708334, vert_correction: -0.05892161916095702,
+ vert_offset_correction: 0.21081478}
+- {dist_correction: 1.3722501, dist_correction_x: 1.4119496, dist_correction_y: 1.4214716,
+ focal_distance: 24.0, focal_slope: 1.0, horiz_offset_correction: 0.025999999, laser_id: 24,
+ min_intensity: 20, rot_correction: -0.08011834622045531, vert_correction: 0.01868575851656834,
+ vert_offset_correction: 0.20522938000000002}
+- {dist_correction: 1.4577922, dist_correction_x: 1.4821321, dist_correction_y: 1.4774638,
+ focal_distance: 20.0, focal_slope: 0.69999999, horiz_offset_correction: -0.025999999,
+ laser_id: 25, min_intensity: 10, rot_correction: -0.0415592740030059, vert_correction: 0.023180922072920565,
+ vert_offset_correction: 0.20490601000000003}
+- {dist_correction: 1.4175369, dist_correction_x: 1.4441992, dist_correction_y: 1.4484555000000001,
+ focal_distance: 12.0, focal_slope: 1.5, horiz_offset_correction: 0.025999999, laser_id: 26,
+ min_intensity: 20, rot_correction: -0.09469728915654493, vert_correction: -0.01647002637924725,
+ vert_offset_correction: 0.20775749000000002}
+- {dist_correction: 1.4383292, dist_correction_x: 1.4573476, dist_correction_y: 1.4790007,
+ focal_distance: 7.0, focal_slope: 1.3, horiz_offset_correction: -0.025999999, laser_id: 27,
+ min_intensity: 10, rot_correction: -0.055555304894197445, vert_correction: -0.011156249123969949,
+ vert_offset_correction: 0.20737534000000002}
+- {dist_correction: 1.3976639, dist_correction_x: 1.434787, dist_correction_y: 1.4289362,
+ focal_distance: 24.0, focal_slope: 0.85000002, horiz_offset_correction: 0.025999999,
+ laser_id: 28, min_intensity: 40, rot_correction: -0.0056653665027087, vert_correction: 0.030126075858796564,
+ vert_offset_correction: 0.20440624}
+- {dist_correction: 1.5147818000000002, dist_correction_x: 1.5457281, dist_correction_y: 1.5337862000000002,
+ focal_distance: 16.0, focal_slope: 1.4, horiz_offset_correction: -0.025999999, laser_id: 29,
+ min_intensity: 10, rot_correction: 0.032454556265796485, vert_correction: 0.03461850099355241,
+ vert_offset_correction: 0.20408289000000002}
+- {dist_correction: 1.4410570999999999, dist_correction_x: 1.4812628, dist_correction_y: 1.4802063,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: 0.025999999, laser_id: 30,
+ min_intensity: 20, rot_correction: -0.019155442326243284, vert_correction: -0.004819796717085346,
+ vert_offset_correction: 0.20691969000000002}
+- {dist_correction: 1.5121419, dist_correction_x: 1.525024, dist_correction_y: 1.5161595,
+ focal_distance: 19.5, focal_slope: 1.15, horiz_offset_correction: -0.025999999,
+ laser_id: 31, rot_correction: 0.019031284839244163, vert_correction: 0.0006993883727657528,
+ vert_offset_correction: 0.20652283000000002}
+- {dist_correction: 1.4162563000000001, dist_correction_x: 1.4498225, dist_correction_y: 1.4345399,
+ focal_distance: 8.5, focal_slope: 1.65, horiz_offset_correction: 0.025999999, laser_id: 32,
+ rot_correction: -0.1322630822793796, vert_correction: -0.39265743814277154, vert_offset_correction: 0.1598857}
+- {dist_correction: 1.3670056, dist_correction_x: 1.3952693, dist_correction_y: 1.4121672,
+ focal_distance: 0.25, focal_slope: 1.05, horiz_offset_correction: -0.025999999,
+ laser_id: 33, rot_correction: -0.07110342218260252, vert_correction: -0.38671040324952605,
+ vert_offset_correction: 0.15945383}
+- {dist_correction: 1.4511356000000002, dist_correction_x: 1.4689107000000001, dist_correction_y: 1.4972537,
+ focal_distance: 4.0, focal_slope: 0.64999998, horiz_offset_correction: 0.025999999,
+ laser_id: 34, rot_correction: 0.08401589158763215, vert_correction: -0.1973354249839361,
+ vert_offset_correction: 0.14657393000000002}
+- {dist_correction: 1.3593520000000001, dist_correction_x: 1.3602931, dist_correction_y: 1.3982458,
+ focal_distance: 10.0, focal_slope: 1.75, horiz_offset_correction: -0.025999999,
+ laser_id: 35, rot_correction: 0.14363965670666648, vert_correction: -0.19024942312742418,
+ vert_offset_correction: 0.14611665000000001}
+- {dist_correction: 1.4114377, dist_correction_x: 1.4772849, dist_correction_y: 1.4348904,
+ focal_distance: 17.0, focal_slope: 0.69999999, horiz_offset_correction: 0.025999999,
+ laser_id: 36, rot_correction: -0.011690171347560868, vert_correction: -0.376852242582194,
+ vert_offset_correction: 0.15874252}
+- {dist_correction: 1.307847, dist_correction_x: 1.3645581000000002, dist_correction_y: 1.376617,
+ focal_distance: 6.0, focal_slope: 1.3, horiz_offset_correction: -0.025999999, laser_id: 37,
+ rot_correction: 0.049492148009829026, vert_correction: -0.3699409132772216, vert_offset_correction: 0.15824712999999999}
+- {dist_correction: 1.4213585, dist_correction_x: 1.4421179000000002, dist_correction_y: 1.4552965,
+ focal_distance: 0.25, focal_slope: 0.94999999, horiz_offset_correction: 0.025999999,
+ laser_id: 38, rot_correction: -0.03418474478652977, vert_correction: -0.4311006362058518,
+ vert_offset_correction: 0.16273095999999998}
+- {dist_correction: 1.3356409, dist_correction_x: 1.3397028, dist_correction_y: 1.3601659000000001,
+ focal_distance: 0.25, focal_slope: 1.05, horiz_offset_correction: -0.025999999,
+ laser_id: 39, rot_correction: 0.026626332916051272, vert_correction: -0.4231418824568801,
+ vert_offset_correction: 0.16213396}
+- {dist_correction: 1.3662766, dist_correction_x: 1.4298528, dist_correction_y: 1.4232704,
+ focal_distance: 0.25, focal_slope: 0.85000002, horiz_offset_correction: 0.025999999,
+ laser_id: 40, rot_correction: 0.1092471200007113, vert_correction: -0.35798081768512774,
+ vert_offset_correction: 0.15739609}
+- {dist_correction: 1.2853244000000001, dist_correction_x: 1.3026004, dist_correction_y: 1.3116373,
+ focal_distance: 8.0, focal_slope: 1.5, horiz_offset_correction: -0.025999999, laser_id: 41,
+ rot_correction: 0.16893982038921165, vert_correction: -0.3493458884773484, vert_offset_correction: 0.1567864}
+- {dist_correction: 1.4113557, dist_correction_x: 1.4361624000000002, dist_correction_y: 1.4260374,
+ focal_distance: 0.25, focal_slope: 1.05, horiz_offset_correction: 0.025999999, laser_id: 42,
+ rot_correction: 0.08876389924739155, vert_correction: -0.41221208962882355, vert_offset_correction: 0.16132105}
+- {dist_correction: 1.3126003, dist_correction_x: 1.3216837000000001, dist_correction_y: 1.3253735,
+ focal_distance: 0.25, focal_slope: 1.15, horiz_offset_correction: -0.025999999,
+ laser_id: 43, rot_correction: 0.15014050027953305, vert_correction: -0.40135006793562183,
+ vert_offset_correction: 0.1605208}
+- {dist_correction: 1.4849261000000002, dist_correction_x: 1.5387573, dist_correction_y: 1.5140117000000002,
+ focal_distance: 8.0, focal_slope: 1.45, horiz_offset_correction: 0.025999999, laser_id: 44,
+ rot_correction: -0.1289198918798797, vert_correction: -0.285349621541792, vert_offset_correction: 0.15237877}
+- {dist_correction: 1.3467159000000002, dist_correction_x: 1.385616, dist_correction_y: 1.398739,
+ focal_distance: 4.0, focal_slope: 0.75, horiz_offset_correction: -0.025999999, laser_id: 45,
+ rot_correction: -0.06875650237205527, vert_correction: -0.27837142867317577, vert_offset_correction: 0.1519088}
+- {dist_correction: 1.4548677, dist_correction_x: 1.5237317, dist_correction_y: 1.4852321000000002,
+ focal_distance: 8.0, focal_slope: 1.55, horiz_offset_correction: 0.025999999, laser_id: 46,
+ rot_correction: -0.15456063213134205, vert_correction: -0.3373837683033222, vert_offset_correction: 0.15594806}
+- {dist_correction: 1.2609565999999999, dist_correction_x: 1.3084103, dist_correction_y: 1.3194104,
+ focal_distance: 0.25, focal_slope: 0.85000002, horiz_offset_correction: -0.025999999,
+ laser_id: 47, rot_correction: -0.0921635423215472, vert_correction: -0.329718648747706,
+ vert_offset_correction: 0.15541457}
+- {dist_correction: 1.2807050000000002, dist_correction_x: 1.3367023, dist_correction_y: 1.3303235000000002,
+ focal_distance: 24.0, focal_slope: 0.40000001, horiz_offset_correction: 0.025999999,
+ laser_id: 48, rot_correction: -0.01087391977724544, vert_correction: -0.2702265530127714,
+ vert_offset_correction: 0.15136261}
+- {dist_correction: 1.3420832999999999, dist_correction_x: 1.3902283, dist_correction_y: 1.3959544,
+ focal_distance: 15.0, focal_slope: 0.69999999, horiz_offset_correction: -0.025999999,
+ laser_id: 49, rot_correction: 0.04819382026855073, vert_correction: -0.2603276912672828,
+ vert_offset_correction: 0.1507021}
+- {dist_correction: 1.4451799, dist_correction_x: 1.5144832, dist_correction_y: 1.4737889000000002,
+ focal_distance: 20.0, focal_slope: 0.5, horiz_offset_correction: 0.025999999, laser_id: 50,
+ rot_correction: -0.033916384706072375, vert_correction: -0.3244024456593014, vert_offset_correction: 0.15504621000000002}
+- {dist_correction: 1.2771001, dist_correction_x: 1.3374065, dist_correction_y: 1.339816,
+ focal_distance: 8.0, focal_slope: 1.3, horiz_offset_correction: -0.025999999, laser_id: 51,
+ rot_correction: 0.027376620290886354, vert_correction: -0.3166693629826125, vert_offset_correction: 0.15451272}
+- {dist_correction: 1.3977615, dist_correction_x: 1.4442108, dist_correction_y: 1.4371663000000001,
+ focal_distance: 0.25, focal_slope: 0.44999999, horiz_offset_correction: 0.025999999,
+ laser_id: 52, rot_correction: 0.10492072454703917, vert_correction: -0.25133544080174264,
+ vert_offset_correction: 0.1501051}
+- {dist_correction: 1.3425783999999998, dist_correction_x: 1.3483524, dist_correction_y: 1.3818097,
+ focal_distance: 11.0, focal_slope: 1.9, horiz_offset_correction: -0.025999999, laser_id: 53,
+ rot_correction: 0.16284451104936298, vert_correction: -0.23979553322706634, vert_offset_correction: 0.14934298000000001}
+- {dist_correction: 1.4382911999999999, dist_correction_x: 1.4900905, dist_correction_y: 1.4804431,
+ focal_distance: 8.0, focal_slope: 0.40000001, horiz_offset_correction: 0.025999999,
+ laser_id: 54, rot_correction: 0.08525729890601516, vert_correction: -0.30499605989320633,
+ vert_offset_correction: 0.15371249}
+- {dist_correction: 1.2974651, dist_correction_x: 1.3356235, dist_correction_y: 1.342494,
+ focal_distance: 11.0, focal_slope: 2.0, horiz_offset_correction: -0.025999999, laser_id: 55,
+ rot_correction: 0.14474094026605314, vert_correction: -0.29379823685192097, vert_offset_correction: 0.15295037}
+- {dist_correction: 1.500197, dist_correction_x: 1.5058761999999999, dist_correction_y: 1.5183740000000001,
+ focal_distance: 6.0, focal_slope: 1.4, horiz_offset_correction: 0.025999999, laser_id: 56,
+ rot_correction: -0.1271355405564693, vert_correction: -0.1783966652843279, vert_offset_correction: 0.14535453}
+- {dist_correction: 1.3739523, dist_correction_x: 1.3909152, dist_correction_y: 1.4026927,
+ focal_distance: 0.25, focal_slope: 0.94999999, horiz_offset_correction: -0.025999999,
+ laser_id: 57, rot_correction: -0.06914267741301003, vert_correction: -0.17006926832673774,
+ vert_offset_correction: 0.14482104}
+- {dist_correction: 1.5294423000000001, dist_correction_x: 1.5526985, dist_correction_y: 1.5286189,
+ focal_distance: 10.0, focal_slope: 1.6, horiz_offset_correction: 0.025999999, laser_id: 58,
+ rot_correction: -0.14952992127533238, vert_correction: -0.23167847811493877, vert_offset_correction: 0.14880949}
+- {dist_correction: 1.356432, dist_correction_x: 1.3750079, dist_correction_y: 1.3956981,
+ focal_distance: 0.25, focal_slope: 0.5, horiz_offset_correction: -0.025999999, laser_id: 59,
+ rot_correction: -0.08941942047983109, vert_correction: -0.22430756871133128, vert_offset_correction: 0.14832681}
+- {dist_correction: 1.4812624, dist_correction_x: 1.5439316, dist_correction_y: 1.5051659000000002,
+ focal_distance: 0.25, focal_slope: 0.69999999, horiz_offset_correction: 0.025999999,
+ laser_id: 60, rot_correction: -0.012020974421732715, vert_correction: -0.16291245497181386,
+ vert_offset_correction: 0.14436376}
+- {dist_correction: 1.3555016, dist_correction_x: 1.3739404, dist_correction_y: 1.3961284,
+ focal_distance: 0.25, focal_slope: 1.1, horiz_offset_correction: -0.025999999, laser_id: 61,
+ rot_correction: 0.045806682836049765, vert_correction: -0.154741111393303, vert_offset_correction: 0.14384298}
+- {dist_correction: 1.5067404, dist_correction_x: 1.5184990999999999, dist_correction_y: 1.5367628,
+ focal_distance: 5.0, focal_slope: 0.40000001, horiz_offset_correction: 0.025999999,
+ laser_id: 62, rot_correction: -0.03255746436915258, vert_correction: -0.21418087168528735,
+ vert_offset_correction: 0.1476663}
+- {dist_correction: 1.3463322, dist_correction_x: 1.356904, dist_correction_y: 1.3849588,
+ focal_distance: 8.0, focal_slope: 0.40000001, horiz_offset_correction: -0.025999999,
+ laser_id: 63, rot_correction: 0.02613443455565695, vert_correction: -0.2063605225459988,
+ vert_offset_correction: 0.14715822}
+num_lasers: 64
diff --git a/modules/calibration/data/beijing_mkz/velodyne64_novatel_extrinsics_example.yaml b/modules/calibration/data/beijing_mkz/velodyne64_novatel_extrinsics_example.yaml
new file mode 100644
index 00000000000..232e4cdbeb2
--- /dev/null
+++ b/modules/calibration/data/beijing_mkz/velodyne64_novatel_extrinsics_example.yaml
@@ -0,0 +1,17 @@
+header:
+ seq: 0
+ stamp:
+ secs: 1504071530
+ nsecs: 0
+ frame_id: novatel
+transform:
+ rotation:
+ x: 0.02586839453030634
+ y: -0.03004435225954187
+ z: 0.6994715770653714
+ w: 0.7135598614968552
+ translation:
+ x: 0.001596842549225523
+ y: 1.586873016593748
+ z: 1
+child_frame_id: velodyne64
diff --git a/modules/calibration/data/mkz8/64E_S3_calibration_example.yaml b/modules/calibration/data/mkz8/64E_S3_calibration_example.yaml
new file mode 100644
index 00000000000..a02c68421c5
--- /dev/null
+++ b/modules/calibration/data/mkz8/64E_S3_calibration_example.yaml
@@ -0,0 +1,243 @@
+lasers:
+- {dist_correction: 1.3280478, dist_correction_x: 1.3733278999999998, dist_correction_y: 1.3565268000000001,
+ focal_distance: 12.0, focal_slope: 0.75, horiz_offset_correction: 0.025999999, laser_id: 0,
+ min_intensity: 5, rot_correction: -0.08042396035379652, vert_correction: -0.12376696608832838,
+ vert_offset_correction: 0.21551828}
+- {dist_correction: 1.4387065, dist_correction_x: 1.4772083, dist_correction_y: 1.4930743000000002,
+ focal_distance: 18.5, focal_slope: 1.1, horiz_offset_correction: -0.025999999, laser_id: 1,
+ min_intensity: 40, rot_correction: -0.043931143295210404, vert_correction: -0.11852979325378328,
+ vert_offset_correction: 0.21513613}
+- {dist_correction: 1.4198532000000001, dist_correction_x: 1.4513388, dist_correction_y: 1.4459473,
+ focal_distance: 17.0, focal_slope: 1.25, horiz_offset_correction: 0.025999999, laser_id: 2,
+ min_intensity: 40, rot_correction: 0.05671893510512383, vert_correction: 0.006831742116548479,
+ vert_offset_correction: 0.20608189}
+- {dist_correction: 1.432045, dist_correction_x: 1.4576363, dist_correction_y: 1.5053079,
+ focal_distance: 24.0, focal_slope: 0.94999999, horiz_offset_correction: -0.025999999,
+ laser_id: 3, min_intensity: 40, rot_correction: 0.09507418428186684, vert_correction: 0.011737269755557637,
+ vert_offset_correction: 0.2057291}
+- {dist_correction: 1.3768561, dist_correction_x: 1.4095345000000001, dist_correction_y: 1.4140973,
+ focal_distance: 24.0, focal_slope: 0.60000002, horiz_offset_correction: 0.025999999,
+ laser_id: 4, min_intensity: 40, rot_correction: -0.0052020566354620415, vert_correction: -0.11207511538496126,
+ vert_offset_correction: 0.21466578}
+- {dist_correction: 1.4579066, dist_correction_x: 1.5030013, dist_correction_y: 1.5402745,
+ focal_distance: 23.0, focal_slope: 0.80000001, horiz_offset_correction: -0.025999999,
+ laser_id: 5, min_intensity: 40, rot_correction: 0.034271327080062704, vert_correction: -0.10662164389621649,
+ vert_offset_correction: 0.21426891}
+- {dist_correction: 1.4042904999999999, dist_correction_x: 1.4512584000000002, dist_correction_y: 1.4358795000000002,
+ focal_distance: 24.0, focal_slope: 0.80000001, horiz_offset_correction: 0.025999999,
+ laser_id: 6, min_intensity: 40, rot_correction: -0.019350118096339984, vert_correction: -0.14744596324186607,
+ vert_offset_correction: 0.21725271}
+- {dist_correction: 1.4530759, dist_correction_x: 1.4934110999999999, dist_correction_y: 1.4934732,
+ focal_distance: 16.5, focal_slope: 0.80000001, horiz_offset_correction: -0.025999999,
+ laser_id: 7, min_intensity: 40, rot_correction: 0.019696635766030937, vert_correction: -0.1420415773930044,
+ vert_offset_correction: 0.21685585}
+- {dist_correction: 1.3928452999999998, dist_correction_x: 1.4412779, dist_correction_y: 1.4351759000000002,
+ focal_distance: 24.0, focal_slope: 0.64999998, horiz_offset_correction: 0.025999999,
+ laser_id: 8, min_intensity: 10, rot_correction: 0.06977400140069993, vert_correction: -0.10055477120587059,
+ vert_offset_correction: 0.21382797}
+- {dist_correction: 1.4649026, dist_correction_x: 1.4811482, dist_correction_y: 1.5390858,
+ focal_distance: 16.5, focal_slope: 1.2, horiz_offset_correction: -0.025999999, laser_id: 9,
+ min_intensity: 40, rot_correction: 0.10867481606700684, vert_correction: -0.09508820800240662,
+ vert_offset_correction: 0.21343111}
+- {dist_correction: 1.3307669000000002, dist_correction_x: 1.3797191000000002, dist_correction_y: 1.3716772000000002,
+ focal_distance: 24.0, focal_slope: 0.85000002, horiz_offset_correction: 0.025999999,
+ laser_id: 10, min_intensity: 40, rot_correction: 0.05614793318704137, vert_correction: -0.13622757149534595,
+ vert_offset_correction: 0.2164296}
+- {dist_correction: 1.3771700999999998, dist_correction_x: 1.4101131, dist_correction_y: 1.4538571,
+ focal_distance: 15.0, focal_slope: 1.35, horiz_offset_correction: -0.025999999,
+ laser_id: 11, min_intensity: 40, rot_correction: 0.09458836664858647, vert_correction: -0.13060523940147076,
+ vert_offset_correction: 0.21601805}
+- {dist_correction: 1.3797005, dist_correction_x: 1.4142267000000002, dist_correction_y: 1.4085233,
+ focal_distance: 10.0, focal_slope: 1.2, horiz_offset_correction: 0.025999999, laser_id: 12,
+ min_intensity: 10, rot_correction: -0.08058553944528767, vert_correction: -0.05321597901122562,
+ vert_offset_correction: 0.21040320999999998}
+- {dist_correction: 1.3646324, dist_correction_x: 1.3887102, dist_correction_y: 1.4070561000000001,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: -0.025999999, laser_id: 13,
+ min_intensity: 40, rot_correction: -0.04053784798354424, vert_correction: -0.04669103069605979,
+ vert_offset_correction: 0.20993286000000003}
+- {dist_correction: 1.3809781, dist_correction_x: 1.4282532000000001, dist_correction_y: 1.4207353,
+ focal_distance: 15.0, focal_slope: 1.3, horiz_offset_correction: 0.025999999, laser_id: 14,
+ min_intensity: 40, rot_correction: -0.09419900463641756, vert_correction: -0.08758781436692292,
+ vert_offset_correction: 0.21288727000000002}
+- {dist_correction: 1.3950202999999999, dist_correction_x: 1.4285829, dist_correction_y: 1.4621552,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: -0.025999999, laser_id: 15,
+ min_intensity: 40, rot_correction: -0.054354701628396805, vert_correction: -0.08292035016148458,
+ vert_offset_correction: 0.21254919000000003}
+- {dist_correction: 1.2988774, dist_correction_x: 1.3749954, dist_correction_y: 1.3734656,
+ focal_distance: 24.0, focal_slope: 0.64999998, horiz_offset_correction: 0.025999999,
+ laser_id: 16, min_intensity: 40, rot_correction: -0.005133124856654525, vert_correction: -0.04077432787988471,
+ vert_offset_correction: 0.20950663}
+- {dist_correction: 1.4723137, dist_correction_x: 1.5056056000000002, dist_correction_y: 1.5041873000000001,
+ focal_distance: 24.0, focal_slope: 1.0, horiz_offset_correction: -0.025999999, laser_id: 17,
+ min_intensity: 20, rot_correction: 0.033464606229193644, vert_correction: -0.03526310344619148,
+ vert_offset_correction: 0.20910976000000003}
+- {dist_correction: 1.3093359000000002, dist_correction_x: 1.4065028000000002, dist_correction_y: 1.3988147000000002,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: 0.025999999, laser_id: 18,
+ min_intensity: 20, rot_correction: -0.01912024950720607, vert_correction: -0.07662373803636939,
+ vert_offset_correction: 0.21209354000000002}
+- {dist_correction: 1.4292241, dist_correction_x: 1.4580751, dist_correction_y: 1.4810971000000002,
+ focal_distance: 24.0, focal_slope: 1.2, horiz_offset_correction: -0.025999999, laser_id: 19,
+ min_intensity: 15, rot_correction: 0.0202102704569296, vert_correction: -0.07052442491121666,
+ vert_offset_correction: 0.21165258}
+- {dist_correction: 1.3831145, dist_correction_x: 1.4038123999999998, dist_correction_y: 1.3966234,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: 0.025999999, laser_id: 20,
+ min_intensity: 30, rot_correction: 0.06874179273711946, vert_correction: -0.029137015224983895,
+ vert_offset_correction: 0.2086688}
+- {dist_correction: 1.402925, dist_correction_x: 1.4443744, dist_correction_y: 1.471532,
+ focal_distance: 17.0, focal_slope: 1.4, horiz_offset_correction: -0.025999999, laser_id: 21,
+ min_intensity: 5, rot_correction: 0.10747970535236223, vert_correction: -0.02341734437339572,
+ vert_offset_correction: 0.20825726}
+- {dist_correction: 1.4234489, dist_correction_x: 1.4673076, dist_correction_y: 1.4543761000000002,
+ focal_distance: 24.0, focal_slope: 0.55000001, horiz_offset_correction: 0.025999999,
+ laser_id: 22, min_intensity: 5, rot_correction: 0.05514045060297391, vert_correction: -0.0642162831410628,
+ vert_offset_correction: 0.21119694}
+- {dist_correction: 1.470387, dist_correction_x: 1.4879053, dist_correction_y: 1.5217740000000002,
+ focal_distance: 24.0, focal_slope: 1.3, horiz_offset_correction: -0.025999999, laser_id: 23,
+ min_intensity: 30, rot_correction: 0.09433926976708334, vert_correction: -0.05892161916095702,
+ vert_offset_correction: 0.21081478}
+- {dist_correction: 1.3722501, dist_correction_x: 1.4119496, dist_correction_y: 1.4214716,
+ focal_distance: 24.0, focal_slope: 1.0, horiz_offset_correction: 0.025999999, laser_id: 24,
+ min_intensity: 20, rot_correction: -0.08011834622045531, vert_correction: 0.01868575851656834,
+ vert_offset_correction: 0.20522938000000002}
+- {dist_correction: 1.4577922, dist_correction_x: 1.4821321, dist_correction_y: 1.4774638,
+ focal_distance: 20.0, focal_slope: 0.69999999, horiz_offset_correction: -0.025999999,
+ laser_id: 25, min_intensity: 10, rot_correction: -0.0415592740030059, vert_correction: 0.023180922072920565,
+ vert_offset_correction: 0.20490601000000003}
+- {dist_correction: 1.4175369, dist_correction_x: 1.4441992, dist_correction_y: 1.4484555000000001,
+ focal_distance: 12.0, focal_slope: 1.5, horiz_offset_correction: 0.025999999, laser_id: 26,
+ min_intensity: 20, rot_correction: -0.09469728915654493, vert_correction: -0.01647002637924725,
+ vert_offset_correction: 0.20775749000000002}
+- {dist_correction: 1.4383292, dist_correction_x: 1.4573476, dist_correction_y: 1.4790007,
+ focal_distance: 7.0, focal_slope: 1.3, horiz_offset_correction: -0.025999999, laser_id: 27,
+ min_intensity: 10, rot_correction: -0.055555304894197445, vert_correction: -0.011156249123969949,
+ vert_offset_correction: 0.20737534000000002}
+- {dist_correction: 1.3976639, dist_correction_x: 1.434787, dist_correction_y: 1.4289362,
+ focal_distance: 24.0, focal_slope: 0.85000002, horiz_offset_correction: 0.025999999,
+ laser_id: 28, min_intensity: 40, rot_correction: -0.0056653665027087, vert_correction: 0.030126075858796564,
+ vert_offset_correction: 0.20440624}
+- {dist_correction: 1.5147818000000002, dist_correction_x: 1.5457281, dist_correction_y: 1.5337862000000002,
+ focal_distance: 16.0, focal_slope: 1.4, horiz_offset_correction: -0.025999999, laser_id: 29,
+ min_intensity: 10, rot_correction: 0.032454556265796485, vert_correction: 0.03461850099355241,
+ vert_offset_correction: 0.20408289000000002}
+- {dist_correction: 1.4410570999999999, dist_correction_x: 1.4812628, dist_correction_y: 1.4802063,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: 0.025999999, laser_id: 30,
+ min_intensity: 20, rot_correction: -0.019155442326243284, vert_correction: -0.004819796717085346,
+ vert_offset_correction: 0.20691969000000002}
+- {dist_correction: 1.5121419, dist_correction_x: 1.525024, dist_correction_y: 1.5161595,
+ focal_distance: 19.5, focal_slope: 1.15, horiz_offset_correction: -0.025999999,
+ laser_id: 31, rot_correction: 0.019031284839244163, vert_correction: 0.0006993883727657528,
+ vert_offset_correction: 0.20652283000000002}
+- {dist_correction: 1.4162563000000001, dist_correction_x: 1.4498225, dist_correction_y: 1.4345399,
+ focal_distance: 8.5, focal_slope: 1.65, horiz_offset_correction: 0.025999999, laser_id: 32,
+ rot_correction: -0.1322630822793796, vert_correction: -0.39265743814277154, vert_offset_correction: 0.1598857}
+- {dist_correction: 1.3670056, dist_correction_x: 1.3952693, dist_correction_y: 1.4121672,
+ focal_distance: 0.25, focal_slope: 1.05, horiz_offset_correction: -0.025999999,
+ laser_id: 33, rot_correction: -0.07110342218260252, vert_correction: -0.38671040324952605,
+ vert_offset_correction: 0.15945383}
+- {dist_correction: 1.4511356000000002, dist_correction_x: 1.4689107000000001, dist_correction_y: 1.4972537,
+ focal_distance: 4.0, focal_slope: 0.64999998, horiz_offset_correction: 0.025999999,
+ laser_id: 34, rot_correction: 0.08401589158763215, vert_correction: -0.1973354249839361,
+ vert_offset_correction: 0.14657393000000002}
+- {dist_correction: 1.3593520000000001, dist_correction_x: 1.3602931, dist_correction_y: 1.3982458,
+ focal_distance: 10.0, focal_slope: 1.75, horiz_offset_correction: -0.025999999,
+ laser_id: 35, rot_correction: 0.14363965670666648, vert_correction: -0.19024942312742418,
+ vert_offset_correction: 0.14611665000000001}
+- {dist_correction: 1.4114377, dist_correction_x: 1.4772849, dist_correction_y: 1.4348904,
+ focal_distance: 17.0, focal_slope: 0.69999999, horiz_offset_correction: 0.025999999,
+ laser_id: 36, rot_correction: -0.011690171347560868, vert_correction: -0.376852242582194,
+ vert_offset_correction: 0.15874252}
+- {dist_correction: 1.307847, dist_correction_x: 1.3645581000000002, dist_correction_y: 1.376617,
+ focal_distance: 6.0, focal_slope: 1.3, horiz_offset_correction: -0.025999999, laser_id: 37,
+ rot_correction: 0.049492148009829026, vert_correction: -0.3699409132772216, vert_offset_correction: 0.15824712999999999}
+- {dist_correction: 1.4213585, dist_correction_x: 1.4421179000000002, dist_correction_y: 1.4552965,
+ focal_distance: 0.25, focal_slope: 0.94999999, horiz_offset_correction: 0.025999999,
+ laser_id: 38, rot_correction: -0.03418474478652977, vert_correction: -0.4311006362058518,
+ vert_offset_correction: 0.16273095999999998}
+- {dist_correction: 1.3356409, dist_correction_x: 1.3397028, dist_correction_y: 1.3601659000000001,
+ focal_distance: 0.25, focal_slope: 1.05, horiz_offset_correction: -0.025999999,
+ laser_id: 39, rot_correction: 0.026626332916051272, vert_correction: -0.4231418824568801,
+ vert_offset_correction: 0.16213396}
+- {dist_correction: 1.3662766, dist_correction_x: 1.4298528, dist_correction_y: 1.4232704,
+ focal_distance: 0.25, focal_slope: 0.85000002, horiz_offset_correction: 0.025999999,
+ laser_id: 40, rot_correction: 0.1092471200007113, vert_correction: -0.35798081768512774,
+ vert_offset_correction: 0.15739609}
+- {dist_correction: 1.2853244000000001, dist_correction_x: 1.3026004, dist_correction_y: 1.3116373,
+ focal_distance: 8.0, focal_slope: 1.5, horiz_offset_correction: -0.025999999, laser_id: 41,
+ rot_correction: 0.16893982038921165, vert_correction: -0.3493458884773484, vert_offset_correction: 0.1567864}
+- {dist_correction: 1.4113557, dist_correction_x: 1.4361624000000002, dist_correction_y: 1.4260374,
+ focal_distance: 0.25, focal_slope: 1.05, horiz_offset_correction: 0.025999999, laser_id: 42,
+ rot_correction: 0.08876389924739155, vert_correction: -0.41221208962882355, vert_offset_correction: 0.16132105}
+- {dist_correction: 1.3126003, dist_correction_x: 1.3216837000000001, dist_correction_y: 1.3253735,
+ focal_distance: 0.25, focal_slope: 1.15, horiz_offset_correction: -0.025999999,
+ laser_id: 43, rot_correction: 0.15014050027953305, vert_correction: -0.40135006793562183,
+ vert_offset_correction: 0.1605208}
+- {dist_correction: 1.4849261000000002, dist_correction_x: 1.5387573, dist_correction_y: 1.5140117000000002,
+ focal_distance: 8.0, focal_slope: 1.45, horiz_offset_correction: 0.025999999, laser_id: 44,
+ rot_correction: -0.1289198918798797, vert_correction: -0.285349621541792, vert_offset_correction: 0.15237877}
+- {dist_correction: 1.3467159000000002, dist_correction_x: 1.385616, dist_correction_y: 1.398739,
+ focal_distance: 4.0, focal_slope: 0.75, horiz_offset_correction: -0.025999999, laser_id: 45,
+ rot_correction: -0.06875650237205527, vert_correction: -0.27837142867317577, vert_offset_correction: 0.1519088}
+- {dist_correction: 1.4548677, dist_correction_x: 1.5237317, dist_correction_y: 1.4852321000000002,
+ focal_distance: 8.0, focal_slope: 1.55, horiz_offset_correction: 0.025999999, laser_id: 46,
+ rot_correction: -0.15456063213134205, vert_correction: -0.3373837683033222, vert_offset_correction: 0.15594806}
+- {dist_correction: 1.2609565999999999, dist_correction_x: 1.3084103, dist_correction_y: 1.3194104,
+ focal_distance: 0.25, focal_slope: 0.85000002, horiz_offset_correction: -0.025999999,
+ laser_id: 47, rot_correction: -0.0921635423215472, vert_correction: -0.329718648747706,
+ vert_offset_correction: 0.15541457}
+- {dist_correction: 1.2807050000000002, dist_correction_x: 1.3367023, dist_correction_y: 1.3303235000000002,
+ focal_distance: 24.0, focal_slope: 0.40000001, horiz_offset_correction: 0.025999999,
+ laser_id: 48, rot_correction: -0.01087391977724544, vert_correction: -0.2702265530127714,
+ vert_offset_correction: 0.15136261}
+- {dist_correction: 1.3420832999999999, dist_correction_x: 1.3902283, dist_correction_y: 1.3959544,
+ focal_distance: 15.0, focal_slope: 0.69999999, horiz_offset_correction: -0.025999999,
+ laser_id: 49, rot_correction: 0.04819382026855073, vert_correction: -0.2603276912672828,
+ vert_offset_correction: 0.1507021}
+- {dist_correction: 1.4451799, dist_correction_x: 1.5144832, dist_correction_y: 1.4737889000000002,
+ focal_distance: 20.0, focal_slope: 0.5, horiz_offset_correction: 0.025999999, laser_id: 50,
+ rot_correction: -0.033916384706072375, vert_correction: -0.3244024456593014, vert_offset_correction: 0.15504621000000002}
+- {dist_correction: 1.2771001, dist_correction_x: 1.3374065, dist_correction_y: 1.339816,
+ focal_distance: 8.0, focal_slope: 1.3, horiz_offset_correction: -0.025999999, laser_id: 51,
+ rot_correction: 0.027376620290886354, vert_correction: -0.3166693629826125, vert_offset_correction: 0.15451272}
+- {dist_correction: 1.3977615, dist_correction_x: 1.4442108, dist_correction_y: 1.4371663000000001,
+ focal_distance: 0.25, focal_slope: 0.44999999, horiz_offset_correction: 0.025999999,
+ laser_id: 52, rot_correction: 0.10492072454703917, vert_correction: -0.25133544080174264,
+ vert_offset_correction: 0.1501051}
+- {dist_correction: 1.3425783999999998, dist_correction_x: 1.3483524, dist_correction_y: 1.3818097,
+ focal_distance: 11.0, focal_slope: 1.9, horiz_offset_correction: -0.025999999, laser_id: 53,
+ rot_correction: 0.16284451104936298, vert_correction: -0.23979553322706634, vert_offset_correction: 0.14934298000000001}
+- {dist_correction: 1.4382911999999999, dist_correction_x: 1.4900905, dist_correction_y: 1.4804431,
+ focal_distance: 8.0, focal_slope: 0.40000001, horiz_offset_correction: 0.025999999,
+ laser_id: 54, rot_correction: 0.08525729890601516, vert_correction: -0.30499605989320633,
+ vert_offset_correction: 0.15371249}
+- {dist_correction: 1.2974651, dist_correction_x: 1.3356235, dist_correction_y: 1.342494,
+ focal_distance: 11.0, focal_slope: 2.0, horiz_offset_correction: -0.025999999, laser_id: 55,
+ rot_correction: 0.14474094026605314, vert_correction: -0.29379823685192097, vert_offset_correction: 0.15295037}
+- {dist_correction: 1.500197, dist_correction_x: 1.5058761999999999, dist_correction_y: 1.5183740000000001,
+ focal_distance: 6.0, focal_slope: 1.4, horiz_offset_correction: 0.025999999, laser_id: 56,
+ rot_correction: -0.1271355405564693, vert_correction: -0.1783966652843279, vert_offset_correction: 0.14535453}
+- {dist_correction: 1.3739523, dist_correction_x: 1.3909152, dist_correction_y: 1.4026927,
+ focal_distance: 0.25, focal_slope: 0.94999999, horiz_offset_correction: -0.025999999,
+ laser_id: 57, rot_correction: -0.06914267741301003, vert_correction: -0.17006926832673774,
+ vert_offset_correction: 0.14482104}
+- {dist_correction: 1.5294423000000001, dist_correction_x: 1.5526985, dist_correction_y: 1.5286189,
+ focal_distance: 10.0, focal_slope: 1.6, horiz_offset_correction: 0.025999999, laser_id: 58,
+ rot_correction: -0.14952992127533238, vert_correction: -0.23167847811493877, vert_offset_correction: 0.14880949}
+- {dist_correction: 1.356432, dist_correction_x: 1.3750079, dist_correction_y: 1.3956981,
+ focal_distance: 0.25, focal_slope: 0.5, horiz_offset_correction: -0.025999999, laser_id: 59,
+ rot_correction: -0.08941942047983109, vert_correction: -0.22430756871133128, vert_offset_correction: 0.14832681}
+- {dist_correction: 1.4812624, dist_correction_x: 1.5439316, dist_correction_y: 1.5051659000000002,
+ focal_distance: 0.25, focal_slope: 0.69999999, horiz_offset_correction: 0.025999999,
+ laser_id: 60, rot_correction: -0.012020974421732715, vert_correction: -0.16291245497181386,
+ vert_offset_correction: 0.14436376}
+- {dist_correction: 1.3555016, dist_correction_x: 1.3739404, dist_correction_y: 1.3961284,
+ focal_distance: 0.25, focal_slope: 1.1, horiz_offset_correction: -0.025999999, laser_id: 61,
+ rot_correction: 0.045806682836049765, vert_correction: -0.154741111393303, vert_offset_correction: 0.14384298}
+- {dist_correction: 1.5067404, dist_correction_x: 1.5184990999999999, dist_correction_y: 1.5367628,
+ focal_distance: 5.0, focal_slope: 0.40000001, horiz_offset_correction: 0.025999999,
+ laser_id: 62, rot_correction: -0.03255746436915258, vert_correction: -0.21418087168528735,
+ vert_offset_correction: 0.1476663}
+- {dist_correction: 1.3463322, dist_correction_x: 1.356904, dist_correction_y: 1.3849588,
+ focal_distance: 8.0, focal_slope: 0.40000001, horiz_offset_correction: -0.025999999,
+ laser_id: 63, rot_correction: 0.02613443455565695, vert_correction: -0.2063605225459988,
+ vert_offset_correction: 0.14715822}
+num_lasers: 64
diff --git a/modules/calibration/data/mkz8/velodyne64_novatel_extrinsics_example.yaml b/modules/calibration/data/mkz8/velodyne64_novatel_extrinsics_example.yaml
new file mode 100644
index 00000000000..232e4cdbeb2
--- /dev/null
+++ b/modules/calibration/data/mkz8/velodyne64_novatel_extrinsics_example.yaml
@@ -0,0 +1,17 @@
+header:
+ seq: 0
+ stamp:
+ secs: 1504071530
+ nsecs: 0
+ frame_id: novatel
+transform:
+ rotation:
+ x: 0.02586839453030634
+ y: -0.03004435225954187
+ z: 0.6994715770653714
+ w: 0.7135598614968552
+ translation:
+ x: 0.001596842549225523
+ y: 1.586873016593748
+ z: 1
+child_frame_id: velodyne64
diff --git a/modules/calibration/data/mkz9/64E_S3_calibration_example.yaml b/modules/calibration/data/mkz9/64E_S3_calibration_example.yaml
new file mode 100644
index 00000000000..a84564e0549
--- /dev/null
+++ b/modules/calibration/data/mkz9/64E_S3_calibration_example.yaml
@@ -0,0 +1,246 @@
+lasers:
+- {dist_correction: 1.2752063, dist_correction_x: 1.3139189, dist_correction_y: 1.3201204000000002,
+ focal_distance: 23.0, focal_slope: 0.80000001, horiz_offset_correction: 0.025999999,
+ laser_id: 0, min_intensity: 40, rot_correction: -0.07883297231288532, vert_correction: -0.1225589730984748,
+ vert_offset_correction: 0.21543011}
+- {dist_correction: 1.354117, dist_correction_x: 1.3893244999999999, dist_correction_y: 1.3824525,
+ focal_distance: 11.1, focal_slope: 1.3, horiz_offset_correction: -0.025999999, laser_id: 1,
+ min_intensity: 40, rot_correction: -0.04257169063286875, vert_correction: -0.11732028531813898,
+ vert_offset_correction: 0.21504793}
+- {dist_correction: 1.3552602999999999, dist_correction_x: 1.4380073999999998, dist_correction_y: 1.4320663,
+ focal_distance: 24.0, focal_slope: 0.69999999, horiz_offset_correction: 0.025999999,
+ laser_id: 2, min_intensity: 40, rot_correction: 0.0576001797697238, vert_correction: 0.006831742116548479,
+ vert_offset_correction: 0.20608189}
+- {dist_correction: 1.3331795, dist_correction_x: 1.3594026, dist_correction_y: 1.3993605,
+ focal_distance: 23.0, focal_slope: 0.94999999, horiz_offset_correction: -0.025999999,
+ laser_id: 3, min_intensity: 40, rot_correction: 0.09708671122503676, vert_correction: 0.011737269755557637,
+ vert_offset_correction: 0.2057291}
+- {dist_correction: 1.272046, dist_correction_x: 1.3137018, dist_correction_y: 1.2978722,
+ focal_distance: 24.0, focal_slope: 0.69999999, horiz_offset_correction: 0.025999999,
+ laser_id: 4, min_intensity: 40, rot_correction: -0.004134042716809833, vert_correction: -0.11106570246674108,
+ vert_offset_correction: 0.21459229000000002}
+- {dist_correction: 1.1886112, dist_correction_x: 1.2300569000000001, dist_correction_y: 1.2463203,
+ focal_distance: 24.0, focal_slope: 1.2, horiz_offset_correction: -0.025999999, laser_id: 5,
+ min_intensity: 40, rot_correction: 0.03539678170426023, vert_correction: -0.1054088809215172,
+ vert_offset_correction: 0.21418074}
+- {dist_correction: 1.2976839000000002, dist_correction_x: 1.3396898, dist_correction_y: 1.3132230999999999,
+ focal_distance: 24.0, focal_slope: 0.89999998, horiz_offset_correction: 0.025999999,
+ laser_id: 6, min_intensity: 40, rot_correction: -0.01812813105654391, vert_correction: -0.14704592330533348,
+ vert_offset_correction: 0.2172233}
+- {dist_correction: 1.2863681, dist_correction_x: 1.3238104000000002, dist_correction_y: 1.3377951,
+ focal_distance: 14.0, focal_slope: 1.25, horiz_offset_correction: -0.025999999,
+ laser_id: 7, min_intensity: 40, rot_correction: 0.020696316728341994, vert_correction: -0.14023825084996633,
+ vert_offset_correction: 0.21672356}
+- {dist_correction: 1.2849046000000002, dist_correction_x: 1.3267589000000002, dist_correction_y: 1.3180791,
+ focal_distance: 24.0, focal_slope: 0.60000002, horiz_offset_correction: 0.025999999,
+ laser_id: 8, min_intensity: 40, rot_correction: 0.0709183561953673, vert_correction: -0.09954287817478333,
+ vert_offset_correction: 0.21375446}
+- {dist_correction: 1.3211784, dist_correction_x: 1.3745055, dist_correction_y: 1.3908893,
+ focal_distance: 17.5, focal_slope: 1.2, horiz_offset_correction: -0.025999999, laser_id: 9,
+ min_intensity: 40, rot_correction: 0.11014432221066224, vert_correction: -0.09387264202892864,
+ vert_offset_correction: 0.21334291}
+- {dist_correction: 1.2667397, dist_correction_x: 1.3151773, dist_correction_y: 1.3144638000000002,
+ focal_distance: 10.0, focal_slope: 1.8, horiz_offset_correction: 0.025999999, laser_id: 10,
+ min_intensity: 40, rot_correction: 0.05752680089198221, vert_correction: -0.1352242183602887,
+ vert_offset_correction: 0.21635611000000002}
+- {dist_correction: 1.2552061, dist_correction_x: 1.2864645, dist_correction_y: 1.313914,
+ focal_distance: 17.0, focal_slope: 1.4, horiz_offset_correction: -0.025999999, laser_id: 11,
+ min_intensity: 40, rot_correction: 0.09560686749622178, vert_correction: -0.12939936000534133,
+ vert_offset_correction: 0.21592983000000002}
+- {dist_correction: 1.2950737, dist_correction_x: 1.3264038, dist_correction_y: 1.3272704,
+ focal_distance: 24.0, focal_slope: 1.3, horiz_offset_correction: 0.025999999, laser_id: 12,
+ min_intensity: 10, rot_correction: -0.07894119668914298, vert_correction: -0.05117740128364046,
+ vert_offset_correction: 0.21025623}
+- {dist_correction: 1.3314511, dist_correction_x: 1.3439276000000002, dist_correction_y: 1.3750456,
+ focal_distance: 24.0, focal_slope: 1.2, horiz_offset_correction: -0.025999999, laser_id: 13,
+ min_intensity: 25, rot_correction: -0.039590087075821526, vert_correction: -0.04567113183969363,
+ vert_offset_correction: 0.20985937}
+- {dist_correction: 1.2853152, dist_correction_x: 1.3545485, dist_correction_y: 1.32582,
+ focal_distance: 20.0, focal_slope: 1.15, horiz_offset_correction: 0.025999999, laser_id: 14,
+ min_intensity: 40, rot_correction: -0.09264152866247388, vert_correction: -0.08697921631142325,
+ vert_offset_correction: 0.21284317000000003}
+- {dist_correction: 1.1956883999999999, dist_correction_x: 1.2309952, dist_correction_y: 1.2384804,
+ focal_distance: 19.5, focal_slope: 1.15, horiz_offset_correction: -0.025999999,
+ laser_id: 15, min_intensity: 40, rot_correction: -0.053828922936562766, vert_correction: -0.08088988123360417,
+ vert_offset_correction: 0.21240220999999998}
+- {dist_correction: 1.2622006000000001, dist_correction_x: 1.3391359, dist_correction_y: 1.3450137000000002,
+ focal_distance: 24.0, focal_slope: 1.05, horiz_offset_correction: 0.025999999, laser_id: 16,
+ min_intensity: 25, rot_correction: -0.004196640695761861, vert_correction: -0.040366165181013325,
+ vert_offset_correction: 0.20947721000000002}
+- {dist_correction: 1.3882208, dist_correction_x: 1.4129477, dist_correction_y: 1.4390656000000002,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: -0.025999999, laser_id: 17,
+ min_intensity: 20, rot_correction: 0.035191251731545366, vert_correction: -0.03485476621439488,
+ vert_offset_correction: 0.20908035000000003}
+- {dist_correction: 1.270416, dist_correction_x: 1.3805045999999999, dist_correction_y: 1.3587926,
+ focal_distance: 24.0, focal_slope: 0.64999998, horiz_offset_correction: 0.025999999,
+ laser_id: 18, min_intensity: 40, rot_correction: -0.01796702320395082, vert_correction: -0.07621729099615271,
+ vert_offset_correction: 0.21206415}
+- {dist_correction: 1.4391471999999998, dist_correction_x: 1.4701469, dist_correction_y: 1.4810228,
+ focal_distance: 24.0, focal_slope: 1.15, horiz_offset_correction: -0.025999999,
+ laser_id: 19, min_intensity: 10, rot_correction: 0.021402925493316658, vert_correction: -0.07052442491121666,
+ vert_offset_correction: 0.21165258}
+- {dist_correction: 1.3115741, dist_correction_x: 1.4043790000000003, dist_correction_y: 1.3746985,
+ focal_distance: 24.0, focal_slope: 1.1, horiz_offset_correction: 0.025999999, laser_id: 20,
+ min_intensity: 40, rot_correction: 0.07015680097488135, vert_correction: -0.02893277679591552,
+ vert_offset_correction: 0.20865412}
+- {dist_correction: 1.3147861, dist_correction_x: 1.3458926, dist_correction_y: 1.3786374000000001,
+ focal_distance: 22.0, focal_slope: 1.0, horiz_offset_correction: -0.025999999, laser_id: 21,
+ min_intensity: 15, rot_correction: 0.10896112162283324, vert_correction: -0.022600128857734412,
+ vert_offset_correction: 0.20819845}
+- {dist_correction: 1.2870654, dist_correction_x: 1.3318181000000002, dist_correction_y: 1.3219449,
+ focal_distance: 21.0, focal_slope: 0.89999998, horiz_offset_correction: 0.025999999,
+ laser_id: 22, min_intensity: 5, rot_correction: 0.056491201053665105, vert_correction: -0.06441985659968617,
+ vert_offset_correction: 0.21121164}
+- {dist_correction: 1.3116136, dist_correction_x: 1.3367073, dist_correction_y: 1.3722873999999998,
+ focal_distance: 24.0, focal_slope: 0.94999999, horiz_offset_correction: -0.025999999,
+ laser_id: 23, min_intensity: 5, rot_correction: 0.09605195612607761, vert_correction: -0.058717920038627504,
+ vert_offset_correction: 0.21080008}
+- {dist_correction: 1.334183, dist_correction_x: 1.3770262, dist_correction_y: 1.3650365,
+ focal_distance: 15.0, focal_slope: 1.5, horiz_offset_correction: 0.025999999, laser_id: 24,
+ min_intensity: 10, rot_correction: -0.07814212387105615, vert_correction: 0.01868575851656834,
+ vert_offset_correction: 0.20522938000000002}
+- {dist_correction: 1.3277109999999999, dist_correction_x: 1.3308896, dist_correction_y: 1.3380003,
+ focal_distance: 16.0, focal_slope: 1.3, horiz_offset_correction: -0.025999999, laser_id: 25,
+ min_intensity: 20, rot_correction: -0.04068591124530794, vert_correction: 0.02481530248969487,
+ vert_offset_correction: 0.20478842}
+- {dist_correction: 1.3784187, dist_correction_x: 1.4020284, dist_correction_y: 1.4110085,
+ focal_distance: 21.0, focal_slope: 1.15, horiz_offset_correction: 0.025999999, laser_id: 26,
+ min_intensity: 40, rot_correction: -0.09248550146333334, vert_correction: -0.015856927119606682,
+ vert_offset_correction: 0.20771341}
+- {dist_correction: 1.3299843000000002, dist_correction_x: 1.3475424, dist_correction_y: 1.3875761,
+ focal_distance: 24.0, focal_slope: 1.15, horiz_offset_correction: -0.025999999,
+ laser_id: 27, rot_correction: -0.05342781834918644, vert_correction: -0.01033868471699117,
+ vert_offset_correction: 0.20731655000000002}
+- {dist_correction: 1.3601752, dist_correction_x: 1.4000146000000002, dist_correction_y: 1.3781789,
+ focal_distance: 24.0, focal_slope: 0.44999999, horiz_offset_correction: 0.025999999,
+ laser_id: 28, rot_correction: -0.004424292891278668, vert_correction: 0.029513378024883952,
+ vert_offset_correction: 0.20445036000000003}
+- {dist_correction: 1.3607886, dist_correction_x: 1.4001455999999999, dist_correction_y: 1.4214912000000002,
+ focal_distance: 24.0, focal_slope: 0.75, horiz_offset_correction: -0.025999999,
+ laser_id: 29, rot_correction: 0.03487417427567706, vert_correction: 0.03625176439960543,
+ vert_offset_correction: 0.2039653}
+- {dist_correction: 1.3876024000000002, dist_correction_x: 1.4266457, dist_correction_y: 1.3987584000000002,
+ focal_distance: 24.0, focal_slope: 1.25, horiz_offset_correction: 0.025999999, laser_id: 30,
+ rot_correction: -0.018163875399624756, vert_correction: -0.004615383580558845, vert_offset_correction: 0.20690498000000002}
+- {dist_correction: 1.3872712999999999, dist_correction_x: 1.409449, dist_correction_y: 1.4333896,
+ focal_distance: 23.0, focal_slope: 0.94999999, horiz_offset_correction: -0.025999999,
+ laser_id: 31, rot_correction: 0.020882827848197862, vert_correction: 0.001312627241293188,
+ vert_offset_correction: 0.20647875}
+- {dist_correction: 1.3152968000000003, dist_correction_x: 1.3551462, dist_correction_y: 1.3403419,
+ focal_distance: 24.0, focal_slope: 0.40000001, horiz_offset_correction: 0.025999999,
+ laser_id: 32, rot_correction: -0.12998286720751434, vert_correction: -0.3917846862503118,
+ vert_offset_correction: 0.15982219}
+- {dist_correction: 1.1306184000000001, dist_correction_x: 1.1613448, dist_correction_y: 1.1695766,
+ focal_distance: 0.25, focal_slope: 1.0, horiz_offset_correction: -0.025999999, laser_id: 33,
+ rot_correction: -0.06963576259729572, vert_correction: -0.38355018793281753, vert_offset_correction: 0.15922519}
+- {dist_correction: 1.2786647, dist_correction_x: 1.3059875, dist_correction_y: 1.3299147,
+ focal_distance: 24.0, focal_slope: 0.44999999, horiz_offset_correction: 0.025999999,
+ laser_id: 34, rot_correction: 0.08608836360929105, vert_correction: -0.1973354249839361,
+ vert_offset_correction: 0.14657393000000002}
+- {dist_correction: 1.3474704, dist_correction_x: 1.3588457, dist_correction_y: 1.3945218,
+ focal_distance: 11.0, focal_slope: 1.9, horiz_offset_correction: -0.025999999, laser_id: 35,
+ rot_correction: 0.14181459383312406, vert_correction: -0.18432959791721729, vert_offset_correction: 0.14573559}
+- {dist_correction: 1.2310821, dist_correction_x: 1.2938965, dist_correction_y: 1.2814186,
+ focal_distance: 16.0, focal_slope: 0.40000001, horiz_offset_correction: 0.025999999,
+ laser_id: 36, rot_correction: -0.009213370242732586, vert_correction: -0.37561450743655717,
+ vert_offset_correction: 0.1586536}
+- {dist_correction: 1.2136781, dist_correction_x: 1.2622253, dist_correction_y: 1.2666883,
+ focal_distance: 8.0, focal_slope: 0.44999999, horiz_offset_correction: -0.025999999,
+ laser_id: 37, rot_correction: 0.05153091946896116, vert_correction: -0.36709468269294687,
+ vert_offset_correction: 0.1580439}
+- {dist_correction: 1.3207919000000001, dist_correction_x: 1.3694466, dist_correction_y: 1.3758972,
+ focal_distance: 0.25, focal_slope: 0.43000001, horiz_offset_correction: 0.025999999,
+ laser_id: 38, rot_correction: -0.032988304130995134, vert_correction: -0.42738242167398816,
+ vert_offset_correction: 0.16245152000000002}
+- {dist_correction: 1.254662, dist_correction_x: 1.2655572, dist_correction_y: 1.2925728,
+ focal_distance: 0.25, focal_slope: 1.1, horiz_offset_correction: -0.025999999, laser_id: 39,
+ rot_correction: 0.02996149305566275, vert_correction: -0.4197376875640353, vert_offset_correction: 0.16187992}
+- {dist_correction: 1.2326976, dist_correction_x: 1.2977957, dist_correction_y: 1.2959807,
+ focal_distance: 0.25, focal_slope: 0.94999999, horiz_offset_correction: 0.025999999,
+ laser_id: 40, rot_correction: 0.11124875259869024, vert_correction: -0.35546799734786144,
+ vert_offset_correction: 0.15721827}
+- {dist_correction: 1.2586923, dist_correction_x: 1.2898768999999999, dist_correction_y: 1.2877043000000001,
+ focal_distance: 8.0, focal_slope: 1.55, horiz_offset_correction: -0.025999999, laser_id: 41,
+ rot_correction: 0.17148979704092368, vert_correction: -0.34319637793757907, vert_offset_correction: 0.15635452000000002}
+- {dist_correction: 1.2951652999999999, dist_correction_x: 1.3469331, dist_correction_y: 1.3253401,
+ focal_distance: 0.25, focal_slope: 0.94999999, horiz_offset_correction: 0.025999999,
+ laser_id: 42, rot_correction: 0.08973073485850933, vert_correction: -0.4113537192494002,
+ vert_offset_correction: 0.16125753}
+- {dist_correction: 1.2491970000000001, dist_correction_x: 1.2513244000000001, dist_correction_y: 1.2672708000000001,
+ focal_distance: 6.0, focal_slope: 1.45, horiz_offset_correction: -0.025999999, laser_id: 43,
+ rot_correction: 0.15193096025532546, vert_correction: -0.398922524385608, vert_offset_correction: 0.16034298}
+- {dist_correction: 1.3504793000000002, dist_correction_x: 1.3742923, dist_correction_y: 1.3776834,
+ focal_distance: 11.0, focal_slope: 1.9, horiz_offset_correction: 0.025999999, laser_id: 44,
+ rot_correction: -0.12746921783885332, vert_correction: -0.2851614052352569, vert_offset_correction: 0.15236607}
+- {dist_correction: 1.3194353, dist_correction_x: 1.3555048, dist_correction_y: 1.3676692,
+ focal_distance: 5.0, focal_slope: 0.55000001, horiz_offset_correction: -0.025999999,
+ laser_id: 45, rot_correction: -0.0670297922925212, vert_correction: -0.27515581660600885,
+ vert_offset_correction: 0.15169286}
+- {dist_correction: 1.2517572, dist_correction_x: 1.3298462000000002, dist_correction_y: 1.2881517,
+ focal_distance: 9.5, focal_slope: 1.65, horiz_offset_correction: 0.025999999, laser_id: 46,
+ rot_correction: -0.1522074465887801, vert_correction: -0.33538020013520276, vert_offset_correction: 0.15580834}
+- {dist_correction: 1.214207, dist_correction_x: 1.2622674, dist_correction_y: 1.2687372000000001,
+ focal_distance: 0.25, focal_slope: 0.75, horiz_offset_correction: -0.025999999,
+ laser_id: 47, rot_correction: -0.08983663794686182, vert_correction: -0.3282540382526024,
+ vert_offset_correction: 0.15531295}
+- {dist_correction: 1.1414406, dist_correction_x: 1.2080206, dist_correction_y: 1.1919655,
+ focal_distance: 8.5, focal_slope: 1.3, horiz_offset_correction: 0.025999999, laser_id: 48,
+ rot_correction: -0.008088342700603029, vert_correction: -0.26946698572230343, vert_offset_correction: 0.1513118}
+- {dist_correction: 1.1837295, dist_correction_x: 1.2247887, dist_correction_y: 1.2112551,
+ focal_distance: 15.0, focal_slope: 0.69999999, horiz_offset_correction: -0.025999999,
+ laser_id: 49, rot_correction: 0.05046789701743674, vert_correction: -0.2601368046069921,
+ vert_offset_correction: 0.1506894}
+- {dist_correction: 1.2635911, dist_correction_x: 1.3508514, dist_correction_y: 1.3295909000000001,
+ focal_distance: 13.0, focal_slope: 0.55000001, horiz_offset_correction: 0.025999999,
+ laser_id: 50, rot_correction: -0.03103305540321719, vert_correction: -0.32109314431788744,
+ vert_offset_correction: 0.15481757000000002}
+- {dist_correction: 1.0956693, dist_correction_x: 1.1582519, dist_correction_y: 1.1591959,
+ focal_distance: 10.5, focal_slope: 0.85000002, horiz_offset_correction: -0.025999999,
+ laser_id: 51, rot_correction: 0.029237828933237592, vert_correction: -0.3140828722976195,
+ vert_offset_correction: 0.15433489}
+- {dist_correction: 1.2680698, dist_correction_x: 1.3010519, dist_correction_y: 1.3118181999999998,
+ focal_distance: 0.25, focal_slope: 0.69999999, horiz_offset_correction: 0.025999999,
+ laser_id: 52, rot_correction: 0.10784944462775096, vert_correction: -0.2509518697920318,
+ vert_offset_correction: 0.1500797}
+- {dist_correction: 1.3034142, dist_correction_x: 1.3091043, dist_correction_y: 1.3535146,
+ focal_distance: 11.0, focal_slope: 2.0, horiz_offset_correction: -0.025999999, laser_id: 53,
+ rot_correction: 0.16523614619534635, vert_correction: -0.23940972819591302, vert_offset_correction: 0.14931756999999998}
+- {dist_correction: 1.3151974000000002, dist_correction_x: 1.3637082, dist_correction_y: 1.3533908,
+ focal_distance: 0.25, focal_slope: 0.40000001, horiz_offset_correction: 0.025999999,
+ laser_id: 54, rot_correction: 0.0869574695089434, vert_correction: -0.30294892830695713,
+ vert_offset_correction: 0.15357277}
+- {dist_correction: 1.2776234, dist_correction_x: 1.289026, dist_correction_y: 1.3073460000000001,
+ focal_distance: 11.5, focal_slope: 1.85, horiz_offset_correction: -0.025999999,
+ laser_id: 55, rot_correction: 0.1464806513031853, vert_correction: -0.29229936554360075,
+ vert_offset_correction: 0.15284875}
+- {dist_correction: 1.3890512000000002, dist_correction_x: 1.3877768000000001, dist_correction_y: 1.3785843,
+ focal_distance: 0.25, focal_slope: 1.2, horiz_offset_correction: 0.025999999, laser_id: 56,
+ rot_correction: -0.1252743738020201, vert_correction: -0.17582174613227564, vert_offset_correction: 0.1451894}
+- {dist_correction: 1.3896303, dist_correction_x: 1.4135710000000001, dist_correction_y: 1.4434415999999999,
+ focal_distance: 0.25, focal_slope: 1.05, horiz_offset_correction: -0.025999999,
+ laser_id: 57, rot_correction: -0.0668689252953649, vert_correction: -0.16848034151967312,
+ vert_offset_correction: 0.14471942000000002}
+- {dist_correction: 1.4813303, dist_correction_x: 1.5015753, dist_correction_y: 1.5009795,
+ focal_distance: 7.0, focal_slope: 1.65, horiz_offset_correction: 0.025999999, laser_id: 58,
+ rot_correction: -0.14694131176062744, vert_correction: -0.230128800272093, vert_offset_correction: 0.14870787}
+- {dist_correction: 1.3051801, dist_correction_x: 1.3334875, dist_correction_y: 1.356346,
+ focal_distance: 4.0, focal_slope: 0.94999999, horiz_offset_correction: -0.025999999,
+ laser_id: 59, rot_correction: -0.08817857864812571, vert_correction: -0.2219747092732381,
+ vert_offset_correction: 0.14817439000000002}
+- {dist_correction: 1.300378, dist_correction_x: 1.3379957999999998, dist_correction_y: 1.3313292,
+ focal_distance: 0.25, focal_slope: 0.60000002, horiz_offset_correction: 0.025999999,
+ laser_id: 60, rot_correction: -0.0084572566097885, vert_correction: -0.16012465801089584,
+ vert_offset_correction: 0.14418593}
+- {dist_correction: 1.2581644, dist_correction_x: 1.3149522, dist_correction_y: 1.2930194000000002,
+ focal_distance: 0.25, focal_slope: 0.89999998, horiz_offset_correction: -0.025999999,
+ laser_id: 61, rot_correction: 0.048843297425790605, vert_correction: -0.1511470421311337,
+ vert_offset_correction: 0.14361434}
+- {dist_correction: 1.2993362, dist_correction_x: 1.3299077, dist_correction_y: 1.324184,
+ focal_distance: 10.0, focal_slope: 0.80000001, horiz_offset_correction: 0.025999999,
+ laser_id: 62, rot_correction: -0.030143852037228126, vert_correction: -0.21457119711920336,
+ vert_offset_correction: 0.14769171}
+- {dist_correction: 1.3722379, dist_correction_x: 1.3900346, dist_correction_y: 1.4076549,
+ focal_distance: 13.0, focal_slope: 0.40000001, horiz_offset_correction: -0.025999999,
+ laser_id: 63, rot_correction: 0.02800567535054865, vert_correction: -0.20577295745331492,
+ vert_offset_correction: 0.14712011}
+num_lasers: 64
diff --git a/modules/calibration/data/mkz9/velodyne64_novatel_extrinsics_example.yaml b/modules/calibration/data/mkz9/velodyne64_novatel_extrinsics_example.yaml
new file mode 100644
index 00000000000..c9e4862b105
--- /dev/null
+++ b/modules/calibration/data/mkz9/velodyne64_novatel_extrinsics_example.yaml
@@ -0,0 +1,17 @@
+child_frame_id: velodyne64
+transform:
+ rotation:
+ x: 0.0178712428342356
+ y: -0.01105483165178439
+ z: 0.7086047865380262
+ w: 0.7052926101074
+ translation:
+ x: -0.0008540722033043019
+ y: 1.410303305307884
+ z: 1
+header:
+ seq: 0
+ stamp:
+ secs: 1502870042
+ nsecs: 0
+ frame_id: novatel
diff --git a/modules/calibration/lidar_ex_checker/BUILD b/modules/calibration/lidar_ex_checker/BUILD
new file mode 100644
index 00000000000..1fc89fa38e0
--- /dev/null
+++ b/modules/calibration/lidar_ex_checker/BUILD
@@ -0,0 +1,38 @@
+load("//tools:cpplint.bzl", "cpplint")
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "lidar_ex_checker_lib",
+ srcs = ["lidar_ex_checker.cc"],
+ hdrs = ["lidar_ex_checker.h"],
+ copts = [
+ "-Wno-deprecated",
+ ],
+ deps = [
+ "//modules/calibration/lidar_ex_checker/common:lidar_ex_checker_common",
+ "//modules/common:apollo_app",
+ "//modules/common:log",
+ "//modules/common/adapters:adapter_manager",
+ "//modules/localization/proto:gps_proto",
+ "//modules/perception/lib/pcl_util",
+ "@vtk//:vtk",
+ ],
+)
+
+cc_binary(
+ name = "lidar_ex_checker",
+ srcs = ["main.cc"],
+ data = [
+ "//modules/calibration/lidar_ex_checker/conf:lidar_ex_checker_adapter_manager_config",
+ ],
+ linkstatic = 0,
+ deps = [
+ ":lidar_ex_checker_lib",
+ "//external:gflags",
+ "//modules/common:log",
+ "@ros//:ros_common",
+ ],
+)
+
+cpplint()
diff --git a/modules/calibration/lidar_ex_checker/README.md b/modules/calibration/lidar_ex_checker/README.md
new file mode 100644
index 00000000000..1c24dfcbdf4
--- /dev/null
+++ b/modules/calibration/lidar_ex_checker/README.md
@@ -0,0 +1,5 @@
+# calibration visualzer
+This node is used to check lidar-to-gps calibration file. Run command:
+```bash
+$:./lidar_ex_checker --flagfile=/apollo/modules/calibration/lidar_ex_checker/conf/lidar_ex_checker.conf
+```
diff --git a/modules/calibration/lidar_ex_checker/common/BUILD b/modules/calibration/lidar_ex_checker/common/BUILD
new file mode 100644
index 00000000000..c7f2a2ede01
--- /dev/null
+++ b/modules/calibration/lidar_ex_checker/common/BUILD
@@ -0,0 +1,18 @@
+load("//tools:cpplint.bzl", "cpplint")
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "lidar_ex_checker_common",
+ srcs = glob([
+ "*.cc",
+ ]),
+ hdrs = glob([
+ "*.h",
+ ]),
+ deps = [
+ "//modules/common",
+ ],
+)
+
+cpplint()
diff --git a/modules/calibration/lidar_ex_checker/common/lidar_ex_checker_gflags.cc b/modules/calibration/lidar_ex_checker/common/lidar_ex_checker_gflags.cc
new file mode 100644
index 00000000000..ab6f635670f
--- /dev/null
+++ b/modules/calibration/lidar_ex_checker/common/lidar_ex_checker_gflags.cc
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright 2017 The Apollo Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *****************************************************************************/
+
+#include "modules/calibration/lidar_ex_checker/common/lidar_ex_checker_gflags.h"
+
+DEFINE_string(node_name, "lidar_ex_checker",
+ "The lidar extrinsics checker module name in proto");
+
+DEFINE_int32(capture_cloud_count, 3, "the number of cloud count to capture");
+
+DEFINE_double(capture_distance, 15.0, "the distance between two clouds");
+
+DEFINE_string(adapter_config_filename,
+ "/apollo/modules/calibration/lidar_ex_checker/conf/adapter.conf",
+ "The adapter config file");
diff --git a/modules/calibration/lidar_ex_checker/common/lidar_ex_checker_gflags.h b/modules/calibration/lidar_ex_checker/common/lidar_ex_checker_gflags.h
new file mode 100644
index 00000000000..1511e234fde
--- /dev/null
+++ b/modules/calibration/lidar_ex_checker/common/lidar_ex_checker_gflags.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Copyright 2017 The Apollo Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *****************************************************************************/
+
+#ifndef MODULES_CALIBRATION_LIDAR_EX_CHECKER_COMMON_LIDAR_EX_CHECKER_GFLAGS_H_
+#define MODULES_CALIBRATION_LIDAR_EX_CHECKER_COMMON_LIDAR_EX_CHECKER_GFLAGS_H_
+
+#include "gflags/gflags.h"
+
+DECLARE_string(node_name);
+
+// the number of cloud count to capture
+DECLARE_int32(capture_cloud_count);
+// the distance between two clouds
+DECLARE_double(capture_distance);
+
+DECLARE_string(adapter_config_filename);
+
+#endif
+/* MODULES_CALIBRATION_LIDAR_EX_CHECKER_COMMON_LIDAR_EX_CHECKER_GFLAGS_H_ */
diff --git a/modules/calibration/lidar_ex_checker/conf/BUILD b/modules/calibration/lidar_ex_checker/conf/BUILD
new file mode 100644
index 00000000000..56be46ffbc9
--- /dev/null
+++ b/modules/calibration/lidar_ex_checker/conf/BUILD
@@ -0,0 +1,15 @@
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "lidar_ex_checker_adapter_manager_config",
+ srcs = [
+ "adapter.conf",
+ ],
+)
+
+filegroup(
+ name = "lidar_ex_checker_config",
+ srcs = [
+ "lidar_ex_checker.conf",
+ ],
+)
diff --git a/modules/calibration/lidar_ex_checker/conf/adapter.conf b/modules/calibration/lidar_ex_checker/conf/adapter.conf
new file mode 100644
index 00000000000..cde31cc8a00
--- /dev/null
+++ b/modules/calibration/lidar_ex_checker/conf/adapter.conf
@@ -0,0 +1,19 @@
+config {
+ type: POINT_CLOUD
+ mode: RECEIVE_ONLY
+ message_history_limit: 10
+}
+
+config {
+ type: GPS
+ mode: RECEIVE_ONLY
+ message_history_limit: 100
+}
+
+config {
+ type: INS_STAT
+ mode: RECEIVE_ONLY
+ message_history_limit: 1
+}
+
+is_ros: true
diff --git a/modules/calibration/lidar_ex_checker/conf/lidar_ex_checker.conf b/modules/calibration/lidar_ex_checker/conf/lidar_ex_checker.conf
new file mode 100644
index 00000000000..348a0f932e6
--- /dev/null
+++ b/modules/calibration/lidar_ex_checker/conf/lidar_ex_checker.conf
@@ -0,0 +1,15 @@
+####################################################################
+# The pointcloud topic name.
+# type: string
+# default: /sensor/velodyne64/compensator/PointCloud2
+--pointcloud_topic=/apollo/sensor/velodyne64/compensator/PointCloud2
+
+# The gnss topic name.
+# type: string
+# default: /sensor/gnss/odometry
+--gps_topic=/apollo/sensor/gnss/odometry
+
+# Project work root directory.
+# type: string
+# default: ""
+--work_root=modules/calibration
diff --git a/modules/calibration/lidar_ex_checker/lidar_ex_checker.cc b/modules/calibration/lidar_ex_checker/lidar_ex_checker.cc
new file mode 100644
index 00000000000..c3c5073117e
--- /dev/null
+++ b/modules/calibration/lidar_ex_checker/lidar_ex_checker.cc
@@ -0,0 +1,207 @@
+/******************************************************************************
+ * Copyright 2017 The Apollo Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *****************************************************************************/
+
+#include "eigen_conversions/eigen_msg.h"
+#include "pcl/io/pcd_io.h"
+#include "pcl/visualization/cloud_viewer.h"
+#include "pcl_conversions/pcl_conversions.h"
+#include "ros/include/ros/ros.h"
+#include "sensor_msgs/PointCloud2.h"
+#include "tf2_ros/transform_listener.h"
+
+#include "modules/calibration/lidar_ex_checker/common/lidar_ex_checker_gflags.h"
+#include "modules/calibration/lidar_ex_checker/lidar_ex_checker.h"
+#include "modules/common/adapters/adapter_manager.h"
+#include "modules/common/log.h"
+
+namespace apollo {
+namespace calibration {
+
+using apollo::common::adapter::AdapterManager;
+using apollo::common::Status;
+using apollo::common::ErrorCode;
+
+std::string LidarExChecker::Name() const { return "lidar_extrinsics_checker"; }
+
+Status LidarExChecker::Init() {
+ is_first_gps_msg_ = true;
+
+ top_redundant_cloud_count_ = 0;
+ bottom_redundant_cloud_count_ = 0;
+ enough_data_ = false;
+
+ cloud_count_ = FLAGS_capture_cloud_count;
+ capture_distance_ = FLAGS_capture_distance;
+
+ position_type_ = 0;
+
+ AdapterManager::Init(FLAGS_adapter_config_filename);
+
+ CHECK(AdapterManager::GetGps()) << "GPS is not initialized.";
+ CHECK(AdapterManager::GetPointCloud()) << "PointCloud is not initialized.";
+ CHECK(AdapterManager::GetInsStat()) << "InsStat is not initialized.";
+ AdapterManager::AddPointCloudCallback(&LidarExChecker::OnPointCloud, this);
+ AdapterManager::AddGpsCallback(&LidarExChecker::OnGps, this);
+ AdapterManager::AddInsStatCallback(&LidarExChecker::OnInsStat, this);
+
+ return Status::OK();
+}
+
+bool LidarExChecker::GetExtrinsics() {
+ static tf2_ros::Buffer tf2_buffer;
+ static tf2_ros::TransformListener tf2Listener(tf2_buffer);
+
+ std::string err_msg;
+
+ if (!tf2_buffer.canTransform("novatel", "velodyne64", ros::Time(0),
+ ros::Duration(100), &err_msg)) {
+ std::cerr << "Fail to get velodyne64 extrinsics for tf" << std::endl;
+ return false;
+ }
+
+ geometry_msgs::TransformStamped transform_stamped;
+ transform_stamped =
+ tf2_buffer.lookupTransform("novatel", "velodyne64", ros::Time(0));
+ tf::transformMsgToEigen(transform_stamped.transform, extrinsics_);
+
+ return true;
+}
+
+void LidarExChecker::VisualizeClouds() {
+ if (!GetExtrinsics()) {
+ return;
+ }
+
+ boost::shared_ptr pcl_vis;
+ pcl_vis.reset(new pcl::visualization::PCLVisualizer("3D Viewer"));
+ for (uint32_t i = 0; i < clouds_.size(); ++i) {
+ pcl::PointCloud cld = clouds_[i];
+ pcl::PointCloud::Ptr tf_cld_ptr(
+ new pcl::PointCloud);
+ double timestamp = cld.points.back().timestamp;
+ timestamp = round(timestamp * 100) / 100.0;
+ Eigen::Affine3d pose = gps_poses_[timestamp];
+
+ for (uint32_t j = 0; j < cld.points.size(); ++j) {
+ PointXYZIT pt = cld.points[j];
+ Eigen::Vector3d pt_vec(pt.x, pt.y, pt.z);
+ Eigen::Vector3d tf_pt_vec = pose * extrinsics_ * pt_vec;
+
+ pcl::PointXYZ tf_pt;
+ tf_pt.x = tf_pt_vec[0];
+ tf_pt.y = tf_pt_vec[1];
+ tf_pt.z = tf_pt_vec[2];
+ tf_cld_ptr->points.push_back(tf_pt);
+ }
+ uint32_t seed = static_cast(timestamp);
+ int r = rand_r(&seed) % 255;
+ int g = rand_r(&seed) % 255;
+ int b = rand_r(&seed) % 255;
+ pcl::visualization::PointCloudColorHandlerCustom handler(
+ tf_cld_ptr, r, g, b);
+ pcl_vis->addPointCloud(tf_cld_ptr, handler, "clouds" + i);
+ }
+ pcl_vis->spin();
+}
+
+void LidarExChecker::OnPointCloud(const sensor_msgs::PointCloud2& message) {
+ if (top_redundant_cloud_count_ < 50) {
+ top_redundant_cloud_count_++;
+ return;
+ }
+
+ if (enough_data_) {
+ bottom_redundant_cloud_count_++;
+ if (bottom_redundant_cloud_count_ == 50) {
+ VisualizeClouds();
+ }
+ return;
+ }
+
+ if (position_type_ != 56) {
+ return;
+ }
+
+ Eigen::Vector3d position;
+ Eigen::Affine3d pose = gps_poses_.rbegin()->second;
+ position[0] = pose.translation().x();
+ position[1] = pose.translation().y();
+ position[2] = pose.translation().z();
+ if ((position - last_position_).norm() < capture_distance_) {
+ return;
+ }
+
+ pcl::PointCloud cld;
+ pcl::fromROSMsg(message, cld);
+
+ pcl::PointCloud tmp_cld;
+ tmp_cld.header = cld.header;
+ for (uint32_t i = 0; i < cld.points.size(); ++i) {
+ if (pcl_isfinite(cld.points[i].x)) {
+ tmp_cld.push_back(cld.points[i]);
+ }
+ }
+ cld = tmp_cld;
+
+ if (clouds_.size() < cloud_count_) {
+ last_position_ = position;
+ clouds_.push_back(cld);
+ }
+
+ if (clouds_.size() >= cloud_count_) {
+ enough_data_ = true;
+ } else {
+ enough_data_ = false;
+ }
+}
+
+void LidarExChecker::OnGps(const localization::Gps& message) {
+ if (message.has_localization()) {
+ const auto pose_msg = message.localization();
+ Eigen::Quaterniond rotation(
+ pose_msg.orientation().qw(), pose_msg.orientation().qx(),
+ pose_msg.orientation().qy(), pose_msg.orientation().qz());
+ Eigen::Translation3d translation(pose_msg.position().x(),
+ pose_msg.position().y(),
+ pose_msg.position().z());
+ Eigen::Affine3d pose = translation * rotation;
+
+ if (is_first_gps_msg_) {
+ is_first_gps_msg_ = false;
+ last_position_[0] = translation.x();
+ last_position_[1] = translation.y();
+ last_position_[2] = translation.z();
+ offset_ = pose.inverse();
+ }
+ Eigen::Affine3d new_pose = offset_ * pose;
+
+ double timestamp = message.header().timestamp_sec();
+ timestamp = round(timestamp * 100) / 100.0;
+
+ gps_poses_.insert(std::make_pair(timestamp, new_pose));
+ }
+}
+
+void LidarExChecker::OnInsStat(const drivers::gnss::InsStat& message) {
+ position_type_ = message.pos_type();
+}
+
+Status LidarExChecker::Start() { return Status::OK(); }
+
+void LidarExChecker::Stop() {}
+
+} // namespace calibration
+} // namespace apollo
diff --git a/modules/calibration/lidar_ex_checker/lidar_ex_checker.h b/modules/calibration/lidar_ex_checker/lidar_ex_checker.h
new file mode 100644
index 00000000000..acc7dee2477
--- /dev/null
+++ b/modules/calibration/lidar_ex_checker/lidar_ex_checker.h
@@ -0,0 +1,98 @@
+/******************************************************************************
+ * Copyright 2017 The Apollo Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *****************************************************************************/
+
+/**
+ * @file
+ */
+
+#ifndef MODEULES_CALIBRATION_LIDAR_EX_CHECKER_H_
+#define MODEULES_CALIBRATION_LIDAR_EX_CHECKER_H_
+
+#include