Full Code of Hypha-ROS/hypharos_minicar for AI

master fef61e1757d3 cached
55 files
169.5 KB
51.7k tokens
21 symbols
1 requests
Download .txt
Repository: Hypha-ROS/hypharos_minicar
Branch: master
Commit: fef61e1757d3
Files: 55
Total size: 169.5 KB

Directory structure:
gitextract_x9qft2fw/

├── CMakeLists.txt
├── LICENSE
├── document/
│   ├── ipopt_install/
│   │   ├── ipopt_arm_install_tutorial.md
│   │   └── ipopt_x86_install_tutorial.md
│   └── udev/
│       ├── stm32base.rules
│       └── udev_install.sh
├── example/
│   ├── CppAD_Ipopt.cpp
│   └── CppAD_started.cpp
├── include/
│   └── MPC.h
├── launch/
│   ├── Desktop/
│   │   ├── HyphaROS_Desktop_Mapping.launch
│   │   └── HyphaROS_Desktop_Racing.launch
│   ├── HyphaROS_MiniCar_Mapping.launch
│   ├── HyphaROS_MiniCar_Racing.launch
│   ├── Simulation/
│   │   ├── HyphaROS_Simulation_Stage.launch
│   │   ├── maps/
│   │   │   └── maze.yaml
│   │   ├── params/
│   │   │   ├── amcl_params.yaml
│   │   │   ├── carlike/
│   │   │   │   ├── costmap_common_params.yaml
│   │   │   │   ├── global_costmap_params.yaml
│   │   │   │   ├── global_planner.yaml
│   │   │   │   ├── local_costmap_params.yaml
│   │   │   │   └── teb_local_planner_params.yaml
│   │   │   ├── mpc_params.yaml
│   │   │   ├── pure_pursuit_params.yaml
│   │   │   └── rviz_navigation.rviz
│   │   └── stage/
│   │       ├── maze_carlike.world
│   │       └── robots/
│   │           └── carlike_robot.inc
│   ├── includes/
│   │   ├── HyphaROS_MiniCar_Drivers.launch.xml
│   │   ├── amcl.launch.xml
│   │   ├── gmapping.launch.xml
│   │   ├── hector_slam.launch.xml
│   │   ├── karto_slam.launch.xml
│   │   ├── minicar_base.launch.xml
│   │   ├── minicar_tf.launch.xml
│   │   ├── mrpt_icp.launch.xml
│   │   └── ydlidar.launch.xml
│   └── params/
│       ├── costmap_common_params.yaml
│       ├── global_costmap_params.yaml
│       ├── global_planner.yaml
│       ├── local_costmap_params.yaml
│       ├── mpc/
│       │   └── mpc_params.yaml
│       ├── pure_pursuit/
│       │   └── pure_pursuit_params.yaml
│       └── teb/
│           └── teb_local_planner_params.yaml
├── map/
│   ├── map_amcl.pgm
│   ├── map_amcl.yaml
│   ├── map_nav.pgm
│   └── map_nav.yaml
├── package.xml
├── readme.md
├── rviz/
│   ├── hypharos_minicar_mapping.rviz
│   └── hypharos_minicar_racing.rviz
├── script/
│   ├── base_control.py
│   └── teleop_keyboard.py
└── src/
    ├── MPC.cpp
    ├── MPC_Node.cpp
    └── Pure_Pursuit.cpp

================================================
FILE CONTENTS
================================================

================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.5)
project(hypharos_minicar)

## Compile as C++11, supported in ROS Kinetic and newer
add_definitions(-std=c++11 -O3)

# options for build configuration
option(BUILD_EXAMPLE "Whether or not building the CppAD & Ipopt example" OFF) 

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
  costmap_2d
  dynamic_reconfigure
  geometry_msgs
  nav_msgs
  ackermann_msgs
  message_generation
  move_base
  roscpp
  rospy
  std_msgs
  tf
  visualization_msgs
)


catkin_package(
   INCLUDE_DIRS include
#  LIBRARIES hypharos_minicar
#  CATKIN_DEPENDS costmap_2d dynamic_reconfigure geometry_msgs message_generation move_base roscpp rospy std_msgs tf visualization_msgs
#  DEPENDS system_lib
)

###########
## Build ##
###########

## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories( ${catkin_INCLUDE_DIRS} include )
include_directories(/usr/include)
link_directories(/usr/lib)

# MPC_Node
ADD_EXECUTABLE( MPC_Node src/MPC.cpp src/MPC_Node.cpp )
TARGET_LINK_LIBRARIES(MPC_Node ipopt ${catkin_LIBRARIES} )

# Pure Pursuit Node
add_executable(Pure_Pursuit src/Pure_Pursuit.cpp)
target_link_libraries(Pure_Pursuit ${catkin_LIBRARIES})

#############
## Example ##
#############
if(BUILD_EXAMPLE)
    ADD_EXECUTABLE( CppAD_started example/CppAD_started.cpp )
    TARGET_LINK_LIBRARIES(CppAD_started)
    
    ADD_EXECUTABLE( CppAD_Ipopt example/CppAD_Ipopt.cpp )
    TARGET_LINK_LIBRARIES(CppAD_Ipopt ipopt)
endif(BUILD_EXAMPLE)


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [2018] [HyphaROS Workshop]

   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: document/ipopt_install/ipopt_arm_install_tutorial.md
================================================
# How to install Ipopt on arm environment  

## Inatall CPPAD & Fortran   
$ sudo apt-get install cppad gfortran  

## Get ipopt source code   
Download Ipopt-3.12.8.tgz from https://www.coin-or.org/download/source/Ipopt/  
Untar the package and cd into the "Ipopt-3.12.8" folder  

## Step by step   
$ cd CUSTOM_PATH/Ipopt-3.12.8/ThirdParty/Blas  
$ ./get.Blas    
$ cd ../Lapack  
$ ./get.Lapack  
$ cd ../Mumps  
$ ./get.Mumps  
$ cd ../Metis  
$ ./get.Metis  
   
$ cd CUSTOM_PATH/Ipopt-3.12.8  
$ mkdir build  
$ cd build  
$ ../configure --build=arm-linux  
$ make -j4  
$ make install  
    
## Copy install files into specific directory 
$ cd CUSTOM_PATH/Ipopt-3.12.8/build  
$ sudo cp -a include/* /usr/include/.  
$ sudo cp -a lib/* /usr/lib/.  
  
## Trouble Shooting
If something wrong like: "redefinition of ‘bool CppAD::is_pod()"  
Modify the file:  
$ sudo gedit /usr/include/cppad/configure.hpp   
Change line from:  
define CPPAD_SIZE_T_NOT_UNSIGNED_INT 1  
to 
define CPPAD_SIZE_T_NOT_UNSIGNED_INT 0  


================================================
FILE: document/ipopt_install/ipopt_x86_install_tutorial.md
================================================
# How to install Ipopt on x86 environment  

## Inatall CPPAD & Fortran  
$ sudo apt-get install cppad gfortran  
    
## Get ipopt source code    
Download Ipopt-3.12.8.tgz from https://www.coin-or.org/download/source/Ipopt/  
Untar the package and cd into the "Ipopt-3.12.8" folder  
  
## Step by step   
$ cd CUSTOM_PATH/Ipopt-3.12.8/ThirdParty/Blas  
$ ./get.Blas    
$ cd ../Lapack  
$ ./get.Lapack  
$ cd ../Mumps  
$ ./get.Mumps  
$ cd ../Metis  
$ ./get.Metis
$ cd ../ASL
$ ./get.ASL
   
$ cd CUSTOM_PATH/Ipopt-3.12.8  
$ mkdir build  
$ cd build  
$ ../configure  
$ make -j4  
$ make install  
    
## Copy install files into specific directory 
$ cd CUSTOM_PATH/Ipopt-3.12.8/build  
$ sudo cp -a include/* /usr/include/.  
$ sudo cp -a lib/* /usr/lib/.  


================================================
FILE: document/udev/stm32base.rules
================================================
# set the udev rule , make the device_port be fixed by arduino
#
KERNEL=="ttyUSB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="666", SYMLINK+="stm32base"



================================================
FILE: document/udev/udev_install.sh
================================================
#!/bin/bash
echo "=========== HyphaROS ==========="
echo "Automatically install udev rules"

# YDLidar
#echo  'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0666", GROUP:="dialout",  SYMLINK+="ydlidar"' >/etc/udev/rules.d/ydlidar.rules
#echo  'KERNEL=="ttyACM*", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", MODE:="0666", GROUP:="dialout",  SYMLINK+="ydlidar"' >/etc/udev/rules.d/ydlidar-V2.rules
#echo  'KERNEL=="ttyUSB*", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", MODE:="0666", GROUP:="dialout",  SYMLINK+="ydlidar"' >/etc/udev/rules.d/ydlidar-2303.rules

# GY85 IMU
#echo  'KERNEL=="ttyUSB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="666", SYMLINK+="gy85"' >/etc/udev/rules.d/gy85.rules 

# STM32 Base
echo  'KERNEL=="ttyUSB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="666", SYMLINK+="stm32base"' >/etc/udev/rules.d/stm32base.rules 

service udev reload
sleep 2
service udev restart

echo "=========== Finished ==========="

exit



================================================
FILE: example/CppAD_Ipopt.cpp
================================================
// $Id$
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell

CppAD is distributed under multiple licenses. This distribution is under
the terms of the
                    Eclipse Public License Version 1.0.

A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */

/*

$begin ipopt_solve_get_started.cpp$$
$spell
	cppad_nlp
	IpoptDir
	CppAD
$$

$section Nonlinear Programming Using CppAD and Ipopt: Example and Test$$
$mindex ipopt AD$$

$head Purpose$$
This example program demonstrates how to use $cref ipopt_solve$$ to
solve the example problem in the Ipopt documentation; i.e., the problem
$latex \[
\begin{array}{lc}
{\rm minimize \; }      &  x_1 * x_4 * (x_1 + x_2 + x_3) + x_3
\\
{\rm subject \; to \; } &  x_1 * x_2 * x_3 * x_4  \geq 25
\\
                        &  x_1^2 + x_2^2 + x_3^2 + x_4^2 = 40
\\
                        &  1 \leq x_1, x_2, x_3, x_4 \leq 5
\end{array}
\] $$


$head Configuration Requirement$$
This example will be compiled and tested provided that
$cref ipopt_prefix$$ is specified on the $cref cmake$$ command line.

$code
$srcfile%example/ipopt_solve/get_started.cpp%0%// BEGIN C++%// END C++%1%$$
$$

$end
*/
// BEGIN C++

// system include files used for I/O
# include <iostream>
// C style asserts
# include <cassert>
// ipopt solve include file
# include <cppad/ipopt/solve.hpp>

namespace {
	using CppAD::AD;

	class FG_eval {
	public:
		typedef CPPAD_TESTVECTOR( AD<double> ) ADvector;
        // fg: function that evaluates the objective and constraints using the syntax
		void operator()(ADvector& fg, const ADvector& x)
		{	assert( fg.size() == 3 );
			assert( x.size()  == 4 );

			// Fortran style indexing
			AD<double> x1 = x[0];
			AD<double> x2 = x[1];
			AD<double> x3 = x[2];
			AD<double> x4 = x[3];
			// f(x)
			fg[0] = x1 * x4 * (x1 + x2 + x3) + x3;
			// g_1 (x)
			fg[1] = x1 * x2 * x3 * x4;
			// g_2 (x)
			fg[2] = x1 * x1 + x2 * x2 + x3 * x3 + x4 * x4;
			//
			return;
		}
	};
}

bool get_started(void)
{	bool ok = true;
	size_t i;
	typedef CPPAD_TESTVECTOR( double ) Dvector;

	// number of independent variables (domain dimension for f and g)
	size_t nx = 4;
	// number of constraints (range dimension for g)
	size_t ng = 2;
	// initial value of the independent variables
	Dvector xi(nx);
	xi[0] = 1.0;
	xi[1] = 5.0;
	xi[2] = 5.0;
	xi[3] = 1.0;
	// lower and upper limits for x
	Dvector xl(nx), xu(nx);
	for(i = 0; i < nx; i++)
	{	xl[i] = 1.0;
		xu[i] = 5.0;
	}
	// lower and upper limits for g
	Dvector gl(ng), gu(ng);
	gl[0] = 25.0;     gu[0] = 1.0e19;
	gl[1] = 40.0;     gu[1] = 40.0;

	// object that computes objective and constraints
	FG_eval fg_eval;

	// options
	std::string options;
	// turn off any printing
	options += "Integer print_level  0\n";
	options += "String  sb           yes\n";
	// maximum number of iterations
	options += "Integer max_iter     10\n";
	// approximate accuracy in first order necessary conditions;
	// see Mathematical Programming, Volume 106, Number 1,
	// Pages 25-57, Equation (6)
	options += "Numeric tol          1e-6\n";
	// derivative testing
	options += "String  derivative_test            second-order\n";
	// maximum amount of random pertubation; e.g.,
	// when evaluation finite diff
	options += "Numeric point_perturbation_radius  0.\n";

	// place to return solution
	CppAD::ipopt::solve_result<Dvector> solution;

	// solve the problem
	CppAD::ipopt::solve<Dvector, FG_eval>(
		options, xi, xl, xu, gl, gu, fg_eval, solution
	);
	//
	// Check some of the solution values
	//
	ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;
	// exact solution
	double check_x[]  = { 1.000000, 4.743000, 3.82115, 1.379408 }; 
	double check_zl[] = { 1.087871, 0.,       0.,      0.       };
	double check_zu[] = { 0.,       0.,       0.,      0.       };
	double rel_tol    = 1e-6;  // relative tolerance
	double abs_tol    = 1e-6;  // absolute tolerance
	for(i = 0; i < nx; i++)
	{	ok &= CppAD::NearEqual(
			check_x[i],  solution.x[i],   rel_tol, abs_tol
		);
		ok &= CppAD::NearEqual(
			check_zl[i], solution.zl[i], rel_tol, abs_tol
		);
		ok &= CppAD::NearEqual(
			check_zu[i], solution.zu[i], rel_tol, abs_tol
		);
        std::cout << "x[" << i << "] = " << solution.x[i] << std::endl;
	}

	return ok;
}

// main program that runs all the tests
int main(void)
{	
    std::cout << "===== Ipopt with CppAD Testing =====" << std::endl;
    bool result = get_started();
    std::cout << "Final checking: " << result << std::endl;
}
// END C++




================================================
FILE: example/CppAD_started.cpp
================================================
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell

CppAD is distributed under multiple licenses. This distribution is under
the terms of the
                    Eclipse Public License Version 1.0.

A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */

/*
$begin get_started.cpp$$
$spell
	cppad.hpp
	http://www.coin-or.org/CppAD/
	getstarted
	namespace
	iostream
	const
	std
	powx
	Jacobian
	jac
	endl
	da
	cout
$$

$section Getting Started Using CppAD to Compute Derivatives$$
$mindex simple example start$$

$head Purpose$$
Demonstrate the use of CppAD by computing the derivative
of a simple example function.

$head Function$$
The example function $latex f : \B{R} \rightarrow \B{R}$$ is defined by
$latex \[
	f(x) = a_0 + a_1 * x^1 + \cdots + a_{k-1} * x^{k-1}
\] $$
where $icode a$$ is a fixed vector of length $icode k$$.

$head Derivative$$
The derivative of $latex f(x)$$ is given by
$latex \[
	f' (x) = a_1 + 2 * a_2 * x +  \cdots + (k-1) * a_{k-1} * x^{k-2}
\] $$

$head Value$$
For the particular case in this example,
$latex k$$ is equal to 5,
$latex a = (1, 1, 1, 1, 1)$$, and
$latex x = 3$$.
If follows that
$latex \[
	f' ( 3 ) = 1 + 2 * 3 + 3 * 3^2 + 4 * 3^3 = 142
\] $$

$head Poly$$
The routine $code Poly$$ is defined below for this particular application.
A general purpose polynomial evaluation routine is documented and
distributed with CppAD (see $cref Poly$$).

$head Exercises$$
Modify the program below to accomplish the following tasks
using CppAD:
$list number$$
Compute and print the derivative of $latex f(x) = 1 + x + x^2 + x^3 + x^4$$
at the point $latex x = 2$$.
$lnext
Compute and print the derivative of $latex f(x) = 1 + x + x^2 / 2$$
at the point $latex x = .5$$.
$lnext
Compute and print the derivative of $latex f(x) = \exp (x) - 1 - x - x^2 / 2$$
at the point $latex x = .5$$.
$lend


$head Program$$
$srccode%cpp% */
#include <iostream>      // standard input/output
#include <vector>        // standard vector
#include <cppad/cppad.hpp> // the CppAD package http://www.coin-or.org/CppAD/

namespace {
	// define y(x) = Poly(a, x) in the empty namespace
	template <class Type>
	Type Poly(const std::vector<double> &a, const Type &x)
	{	size_t k  = a.size();
		Type y   = 0.;  // initialize summation
		Type x_i = 1.;  // initialize x^i
		size_t i;
		for(i = 0; i < k; i++)
		{	y   += a[i] * x_i;  // y   = y + a_i * x^i
			x_i *= x;           // x_i = x_i * x
		}
		return y;
	}
}
// main program
int main(void)
{	
    std::cout << "===== CppAD Diff Testing =====" << std::endl;    
    using CppAD::AD;           // use AD as abbreviation for CppAD::AD
	using std::vector;         // use vector as abbreviation for std::vector
	size_t i;                  // a temporary index

	// vector of polynomial coefficients
	size_t k = 5;              // number of polynomial coefficients
	vector<double> a(k);       // vector of polynomial coefficients
	for(i = 0; i < k; i++)
		a[i] = 1.;           // value of polynomial coefficients

	// domain space vector
	size_t n = 1;              // number of domain space variables
	vector< AD<double> > X(n); // vector of domain space variables
	X[0] = 3.;                 // value corresponding to operation sequence

	// declare independent variables and start recording operation sequence
	CppAD::Independent(X);

	// range space vector
	size_t m = 1;              // number of ranges space variables
	vector< AD<double> > Y(m); // vector of ranges space variables
	Y[0] = Poly(a, X[0]);      // value during recording of operations

	// store operation sequence in f: X -> Y and stop recording
	CppAD::ADFun<double> f(X, Y);

	// compute derivative using operation sequence stored in f
	vector<double> jac(m * n); // Jacobian of f (m by n matrix)
	vector<double> x(n);       // domain space vector
	x[0] = 3.;                 // argument value for derivative
	jac  = f.Jacobian(x);      // Jacobian for operation sequence

	// print the results
	std::cout << "f'(3) computed by CppAD = " << jac[0] << std::endl;

	// check if the derivative is correct
	int error_code;
	if( jac[0] == 142. )
		error_code = 0;      // return code for correct case
	else  error_code = 1;      // return code for incorrect case

	return error_code;
}
/* %$$
$head Output$$
Executing the program above will generate the following output:
$codep
	f'(3) computed by CppAD = 142
$$

$head Running$$
To build and run this program see $cref cmake_check$$.

$end
*/


================================================
FILE: include/MPC.h
================================================
/*
# Copyright 2018 HyphaROS Workshop.
# Developer: HaoChih, LIN (hypha.ros@gmail.com)
#
# 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 MPC_H
#define MPC_H

#include <vector>
#include <map>
#include <Eigen/Core>

using namespace std;

class MPC
{
    public:
        MPC();
    
        // Solve the model given an initial state and polynomial coefficients.
        // Return the first actuatotions.
        vector<double> Solve(Eigen::VectorXd state, Eigen::VectorXd coeffs);
        vector<double> mpc_x;
        vector<double> mpc_y;

        void LoadParams(const std::map<string, double> &params);
    
    private:
        // Parameters for mpc solver
        double _max_steering, _max_throttle, _bound_value;
        int _mpc_steps, _x_start, _y_start, _psi_start, _v_start, _cte_start, _epsi_start, _delta_start, _a_start;
        std::map<string, double> _params;
        
};

#endif /* MPC_H */


================================================
FILE: launch/Desktop/HyphaROS_Desktop_Mapping.launch
================================================
<?xml version="1.0"?>

<launch>
    <!-- Launch arguments -->
    <arg name="use_rviz"  default="true" />
    <arg name="use_key"   default="true"/>

    <!-- Keyboard control -->
    <node pkg="hypharos_minicar" type="teleop_keyboard.py" name="teleop_keyboard" output="screen" if="$(arg use_key)"/>

    <!-- Visualization -->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find hypharos_minicar)/rviz/hypharos_minicar_mapping.rviz" if="$(arg use_rviz)" />
</launch>


================================================
FILE: launch/Desktop/HyphaROS_Desktop_Racing.launch
================================================
<?xml version="1.0"?>

<launch>
    <!-- Launch arguments -->
    <arg name="use_rviz"  default="true" />
    <arg name="use_key"   default="true"/>

    <!-- Keyboard control -->
    <node pkg="hypharos_minicar" type="teleop_keyboard.py" name="teleop_keyboard" output="screen" if="$(arg use_key)">
        <param name="safety_mode" value="True"/>
    </node>

    <!-- Visualization -->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find hypharos_minicar)/rviz/hypharos_minicar_racing.rviz" if="$(arg use_rviz)" />
</launch>


================================================
FILE: launch/HyphaROS_MiniCar_Mapping.launch
================================================
<?xml version="1.0"?>

<launch>
    <!-- launch file arguments -->
    <arg name="slam_type"   default="gmapping" doc="opt: gmapping, karto_slam, mrpt_icp, hector_slam"/> 
    <arg name="debug_mode"  default="false" doc="show debug info (bool)"/> 
    <arg name="pwm_radian"  default="450" doc="non scaled factor pwm/radian (steering)"/>
    <arg name="neutral_pt"  default="-5.0"   doc="steering neutral point (degree)"/>
    <arg name="use_imu"     default="false" doc="use imu for ekf (bool)"/> 
    <arg name="time_out"    default="1.0"   doc="communication time out, unit: sec"/> 
    <arg name="output"      default="log"   doc="log or screen"/> 
    <!-- arg name="output"           default="screen" /--> 

    <!-- Boot up all components -->
    <include file="$(find hypharos_minicar)/launch/includes/HyphaROS_MiniCar_Drivers.launch.xml">
        <arg name="debug_mode" value="$(arg debug_mode)" />
        <arg name="pwm_radian" value="$(arg pwm_radian)"/>
        <arg name="neutral_pt" value="$(arg neutral_pt)"/>
        <arg name="use_imu"    value="$(arg use_imu)" />
        <arg name="time_out"   value="$(arg time_out)" />
    </include>

    <!-- gmapping -->
    <include file="$(find hypharos_minicar)/launch/includes/gmapping.launch.xml" if="$(eval slam_type == 'gmapping')">
        <arg name="output" value="$(arg output)" />
    </include>

    <!-- karto slam -->
    <include file="$(find hypharos_minicar)/launch/includes/karto_slam.launch.xml" if="$(eval slam_type == 'karto_slam')">
        <arg name="output" value="$(arg output)" />
    </include>

    <!-- mrpt icp -->
    <include file="$(find hypharos_minicar)/launch/includes/mrpt_icp.launch.xml" if="$(eval slam_type == 'mrpt_icp')">
        <arg name="output" value="$(arg output)" />
    </include>

    <!-- hector slam -->
    <include file="$(find hypharos_minicar)/launch/includes/hector_slam.launch.xml" if="$(eval slam_type == 'hector_slam')">
        <arg name="output" value="$(arg output)" />
    </include>

</launch>


================================================
FILE: launch/HyphaROS_MiniCar_Racing.launch
================================================
<?xml version="1.0"?>

<launch>
    <!-- ********************** -->
    <!-- Launch file parameters -->
    <!-- ********************** -->
    <!-- general -->
    <arg name="debug_mode"  default="false" doc="show debug info (bool)"/> 
    <arg name="pwm_radian"  default="450" doc="non scaled factor pwm/radian (steering)"/>
    <arg name="neutral_pt"  default="-5.0"   doc="steering neutral point (degree)"/>
    <arg name="use_imu"     default="false" doc="use imu for ekf (bool)"/> 
    <arg name="time_out"    default="1.0"   doc="communication time out, unit: sec"/> 
    <arg name="output"      default="log"   doc="log or screen"/> 
    <!-- for amcl -->    
    <arg name="init_x" default="0.0" />
    <arg name="init_y" default="0.0" />
    <arg name="init_a" default="0.0" />
    <!-- for controller -->
    <arg name="controller"  default="pure_pursuit" doc="opt: mpc, pure_pursuit"/> 


    <!-- ********************** -->
    <!-- Boot up all components -->
    <!-- ********************** -->
    <include file="$(find hypharos_minicar)/launch/includes/HyphaROS_MiniCar_Drivers.launch.xml">
        <arg name="debug_mode" value="$(arg debug_mode)" />
        <arg name="pwm_radian" value="$(arg pwm_radian)"/>
        <arg name="neutral_pt" value="$(arg neutral_pt)"/>
        <arg name="use_imu"    value="$(arg use_imu)" />
        <arg name="time_out"   value="$(arg time_out)" />
    </include>


    <!-- ************ -->
    <!-- Localization -->
    <!-- ************ -->
    <!-- Map server (for amcl) -->
    <node name="map_server" pkg="map_server" type="map_server" args="$(find hypharos_minicar)/map/map_amcl.yaml">
        <remap from="map" to="map_amcl"/>
    </node>
    <!-- Map server (for nav)-->
    <node name="map_server_nav" pkg="map_server" type="map_server" args="$(find hypharos_minicar)/map/map_nav.yaml"/>

    <!-- amcl -->
    <include file="$(find hypharos_minicar)/launch/includes/amcl.launch.xml">
        <arg name="init_x" value="$(arg init_x)"/>
        <arg name="init_y" value="$(arg init_y)"/>
        <arg name="init_a" value="$(arg init_a)"/>
    </include>


    <!-- ********************** -->
    <!-- Navigation (move_base) -->
    <!-- ********************** -->
    <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
        <rosparam file="$(find hypharos_minicar)/launch/params/costmap_common_params.yaml" command="load" ns="global_costmap" />
        <rosparam file="$(find hypharos_minicar)/launch/params/costmap_common_params.yaml" command="load" ns="local_costmap" />
        <rosparam file="$(find hypharos_minicar)/launch/params/local_costmap_params.yaml" command="load" />
        <rosparam file="$(find hypharos_minicar)/launch/params/global_costmap_params.yaml" command="load" />        
        <!-- Global Planner -->
        <param name="base_global_planner" value="global_planner/GlobalPlanner" />
        <param name="planner_frequency" value="0.0" />
        <param name="planner_patience" value="5.0" />
        <rosparam file="$(find hypharos_minicar)/launch/params/global_planner.yaml" command="load" />
        <!-- Local Planner -->
        <param name="base_local_planner" value="base_local_planner/TrajectoryPlannerROS" />
        <!-- Our carlike robot is not able to rotate in place -->
        <param name="clearing_rotation_allowed" value="false" /> 
        <!-- external controller -->
        <remap from="/cmd_vel" to="/fake_cmd" />
    </node>
    
    <!--  ****** MPC Node ******  -->
    <node name="MPC_Node" pkg="hypharos_minicar" type="MPC_Node" output="screen" if="$(eval controller == 'mpc')" >
        <rosparam file="$(find hypharos_minicar)/launch/params/mpc/mpc_params.yaml" command="load" />
    </node>

    <!--  ****** Pure Pursuit ******  -->
    <node name="Pure_Pursuit" pkg="hypharos_minicar" type="Pure_Pursuit" output="screen" if="$(eval controller == 'pure_pursuit')" >
        <rosparam file="$(find hypharos_minicar)/launch/params/pure_pursuit/pure_pursuit_params.yaml" command="load" />
        <remap from="/pure_pursuit/odom" to="/odom" />
        <remap from="/pure_pursuit/global_planner" to="/move_base/GlobalPlanner/plan" />
        <remap from="/pure_pursuit/goal" to="/move_base_simple/goal" />
        <remap from="/pure_pursuit/ackermann_cmd" to="/ackermann_cmd" />
    </node>

</launch>


================================================
FILE: launch/Simulation/HyphaROS_Simulation_Stage.launch
================================================
<launch>

    <!--  ************** Global Parameters ***************  -->
    <param name="/use_sim_time" value="true"/>
    <arg name="controller"  default="mpc" doc="opt: dwa, mpc, pure_pursuit"/> 

    <!--  ************** Stage Simulator ***************  -->
    <node pkg="stage_ros" type="stageros" name="stageros" args="$(find hypharos_minicar)/launch/Simulation/stage/maze_carlike.world">
        <remap from="base_scan" to="scan"/>
    </node>

    <!--  ************** Map Server **************  -->
    <node name="map_server" pkg="map_server" type="map_server" args="$(find hypharos_minicar)/launch/Simulation/maps/maze.yaml" output="screen">
        <param name="frame_id" value="/map"/>
    </node>

    <!--  ************** Localization **************  -->
    <node pkg="amcl" type="amcl" name="amcl" output="screen">
        <rosparam file="$(find hypharos_minicar)/launch/Simulation/params/amcl_params.yaml" command="load" />
        <param name="initial_pose_x"            value="1"/>
        <param name="initial_pose_y"            value="1"/>
        <param name="initial_pose_a"            value="0"/>
    </node>

    <!--  ************** Navigation ***************  -->
    <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
        <rosparam file="$(find hypharos_minicar)/launch/Simulation/params/carlike/costmap_common_params.yaml" command="load" ns="global_costmap" />
        <rosparam file="$(find hypharos_minicar)/launch/Simulation/params/carlike/costmap_common_params.yaml" command="load" ns="local_costmap" />
        <rosparam file="$(find hypharos_minicar)/launch/Simulation/params/carlike/local_costmap_params.yaml" command="load" />
        <rosparam file="$(find hypharos_minicar)/launch/Simulation/params/carlike/global_costmap_params.yaml" command="load" />        
        <!-- Global Planner -->
        <param name="base_global_planner" value="global_planner/GlobalPlanner" />
        <param name="planner_frequency" value="0.0" />
        <param name="planner_frequency" value="0.0" if="$(eval controller == 'pure_pursuit')"/>
        <param name="planner_patience" value="5.0" />
        <rosparam file="$(find hypharos_minicar)/launch/Simulation/params/carlike/global_planner.yaml" command="load" />
        <!-- Local Planner -->
        <param name="base_local_planner" value="base_local_planner/TrajectoryPlannerROS" />
        <!-- Our carlike robot is not able to rotate in place -->
        <param name="clearing_rotation_allowed" value="false" /> 
        <!-- external controller -->
        <remap from="/cmd_vel" to="/fake_cmd" unless="$(eval controller == 'dwa')"/>
    </node>
    
    <!--  ************** MPC Node **************  -->
    <node name="MPC_Node" pkg="hypharos_minicar" type="MPC_Node" output="screen" if="$(eval controller == 'mpc')" >
        <rosparam file="$(find hypharos_minicar)/launch/Simulation/params/mpc_params.yaml" command="load" />
    </node>

    <!--  ************** Pure Pursuit **************  -->
    <node name="Pure_Pursuit" pkg="hypharos_minicar" type="Pure_Pursuit" output="screen" if="$(eval controller == 'pure_pursuit')" >
        <rosparam file="$(find hypharos_minicar)/launch/Simulation/params/pure_pursuit_params.yaml" command="load" />
        <remap from="/pure_pursuit/odom" to="/odom" />
        <remap from="/pure_pursuit/global_planner" to="/move_base/GlobalPlanner/plan" />
        <remap from="/pure_pursuit/goal" to="/move_base_simple/goal" />
        <remap from="/pure_pursuit/cmd_vel" to="/cmd_vel" />
    </node>

    <!--  ************** Visualisation **************  -->
    <node name="rviz" pkg="rviz" type="rviz" args="-d $(find hypharos_minicar)/launch/Simulation/params/rviz_navigation.rviz"/>

</launch>


================================================
FILE: launch/Simulation/maps/maze.yaml
================================================
image: maze.png
resolution: 0.05
origin: [0.0, 0.0, 0.0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196


================================================
FILE: launch/Simulation/params/amcl_params.yaml
================================================
use_map_topic: true

odom_frame_id: "odom"
base_frame_id: "base_footprint"
global_frame_id: "/map"

## Publish scans from best pose at a max of 10 Hz
odom_model_type: "diff"
odom_alpha5: 0.1
gui_publish_rate: 10.0
laser_max_beams: 60
laser_max_range: 12.0
min_particles: 500
max_particles: 2000
kld_err: 0.05
kld_z: 0.99
odom_alpha1: 0.2
odom_alpha2: 0.2
## translation std dev, m 
odom_alpha3: 0.2
odom_alpha4: 0.2
laser_z_hit: 0.5
aser_z_short: 0.05
laser_z_max: 0.05
laser_z_rand: 0.5
laser_sigma_hit: 0.2
laser_lambda_short: 0.1
laser_model_type: "likelihood_field" # "likelihood_field" or "beam"
laser_likelihood_max_dist: 2.0
update_min_d: 0.25
update_min_a: 0.2

resample_interval: 1

## Increase tolerance because the computer can get quite busy 
transform_tolerance: 1.0
recovery_alpha_slow: 0.001
recovery_alpha_fast: 0.1


================================================
FILE: launch/Simulation/params/carlike/costmap_common_params.yaml
================================================

#---standard pioneer footprint---
#---(in meters)---
#footprint: [ [0.254, -0.0508], [0.1778, -0.0508], [0.1778, -0.1778], [-0.1905, -0.1778], [-0.254, 0], [-0.1905, 0.1778], [0.1778, 0.1778], [0.1778, 0.0508], [0.254, 0.0508] ]
#footprint: [ [-0.1,-0.125], [0.5,-0.125], [0.5,0.125], [-0.1,0.125] ]
footprint: [ [-0.6,-0.125], [0.0,-0.125], [0.0,0.125], [-0.6,0.125] ]

transform_tolerance: 0.2
map_type: costmap

obstacle_layer:
 enabled: true
 obstacle_range: 3.0
 raytrace_range: 3.5
 inflation_radius: 0.2
 track_unknown_space: false
 combination_method: 1

 observation_sources: laser_scan_sensor
 laser_scan_sensor: {data_type: LaserScan, topic: scan, marking: true, clearing: true}


inflation_layer:
  enabled:              true
  cost_scaling_factor:  10.0  # exponential rate at which the obstacle cost drops off (default: 10)
  inflation_radius:     0.5  # max. distance from an obstacle at which costs are incurred for planning paths.

static_layer:
  enabled:              true
  map_topic:            "/map"


================================================
FILE: launch/Simulation/params/carlike/global_costmap_params.yaml
================================================
global_costmap:
    global_frame: /map
    robot_base_frame: base_link
    update_frequency: 1.0
    publish_frequency: 0.5
    static_map: true

    transform_tolerance: 0.5
    plugins:
    - {name: static_layer,            type: "costmap_2d::StaticLayer"}
    - {name: obstacle_layer,          type: "costmap_2d::VoxelLayer"}
    - {name: inflation_layer,         type: "costmap_2d::InflationLayer"}


    inflation_layer:
        inflation_radius: 2.5
        cost_scaling_factor: 2.0



================================================
FILE: launch/Simulation/params/carlike/global_planner.yaml
================================================
GlobalPlanner:
    use_dijkstra: true
    use_grid_path: false


================================================
FILE: launch/Simulation/params/carlike/local_costmap_params.yaml
================================================
local_costmap:
  global_frame: /map
  robot_base_frame: base_link
  update_frequency: 10.0
  publish_frequency: 10.0
  static_map: false
  rolling_window: true
  width: 5.5
  height: 5.5
  resolution: 0.2
  transform_tolerance: 0.5
  
  plugins:
   - {name: static_layer,        type: "costmap_2d::StaticLayer"}
   - {name: obstacle_layer,      type: "costmap_2d::ObstacleLayer"}


================================================
FILE: launch/Simulation/params/carlike/teb_local_planner_params.yaml
================================================
TebLocalPlannerROS:

 odom_topic: odom
    
 # Trajectory
  
 teb_autosize: True
 dt_ref: 0.3
 dt_hysteresis: 0.1
 global_plan_overwrite_orientation: True
 allow_init_with_backwards_motion: True
 max_global_plan_lookahead_dist: 3.0
 feasibility_check_no_poses: 2
    
 # Robot
         
 max_vel_x: 0.4
 max_vel_x_backwards: 0.2
 max_vel_y: 0.0
 max_vel_theta: 0.3 # the angular velocity is also bounded by min_turning_radius in case of a carlike robot (r = v / omega)
 acc_lim_x: 0.5
 acc_lim_theta: 0.5

 # ********************** Carlike robot parameters ********************
 min_turning_radius: 0.5        # Min turning radius of the carlike robot (compute value using a model or adjust with rqt_reconfigure manually)
 wheelbase: 0.4                 # Wheelbase of our robot
 cmd_angle_instead_rotvel: True # stage simulator takes the angle instead of the rotvel as input (twist message)
 # ********************************************************************

 footprint_model: # types: "point", "circular", "two_circles", "line", "polygon"
   type: "line"
   radius: 0.2 # for type "circular"
   line_start: [0.0, 0.0] # for type "line"
   line_end: [0.4, 0.0] # for type "line"
   front_offset: 0.2 # for type "two_circles"
   front_radius: 0.2 # for type "two_circles"
   rear_offset: 0.2 # for type "two_circles"
   rear_radius: 0.2 # for type "two_circles"
   vertices: [ [0.25, -0.05], [0.18, -0.05], [0.18, -0.18], [-0.19, -0.18], [-0.25, 0], [-0.19, 0.18], [0.18, 0.18], [0.18, 0.05], [0.25, 0.05] ] # for type "polygon"

 # GoalTolerance
    
 xy_goal_tolerance: 0.2
 yaw_goal_tolerance: 0.1
 free_goal_vel: False
    
 # Obstacles
    
 min_obstacle_dist: 0.27 # This value must also include our robot's expansion, since footprint_model is set to "line".
 include_costmap_obstacles: True
 costmap_obstacles_behind_robot_dist: 1.0
 obstacle_poses_affected: 30
 costmap_converter_plugin: ""
 costmap_converter_spin_thread: True
 costmap_converter_rate: 5

 # Optimization
    
 no_inner_iterations: 5
 no_outer_iterations: 4
 optimization_activate: True
 optimization_verbose: False
 penalty_epsilon: 0.1
 weight_max_vel_x: 2
 weight_max_vel_theta: 1
 weight_acc_lim_x: 1
 weight_acc_lim_theta: 1
 weight_kinematics_nh: 1000
 weight_kinematics_forward_drive: 1
 weight_kinematics_turning_radius: 1
 weight_optimaltime: 1
 weight_obstacle: 50
 weight_dynamic_obstacle: 10 # not in use yet

 # Homotopy Class Planner

 enable_homotopy_class_planning: True
 enable_multithreading: True
 simple_exploration: False
 max_number_classes: 4
 selection_cost_hysteresis: 1.0
 selection_obst_cost_scale: 1.0
 selection_alternative_time_cost: False
 roadmap_graph_no_samples: 15
 roadmap_graph_area_width: 5
 h_signature_prescaler: 0.5
 h_signature_threshold: 0.1
 obstacle_keypoint_offset: 0.1
 obstacle_heading_threshold: 0.45
 visualize_hc_graph: False


================================================
FILE: launch/Simulation/params/mpc_params.yaml
================================================
# Parameters for control loop
pub_twist_cmd: true
debug_info: false
delay_mode: true
max_speed: 2.0 # unit: m/s 
waypoints_dist: -1.0 # unit: m, set < 0 means computed by node
path_length: 8.0 # unit: m
goal_radius: 0.5 # unit: m
controller_freq: 10
vehicle_Lf: 0.25 # distance between the front of the vehicle and its center of gravity

# Parameter for MPC solver
mpc_steps: 20.0
mpc_ref_cte: 0.0
mpc_ref_epsi: 0.0
mpc_ref_vel: 1.5
mpc_w_cte: 100.0
mpc_w_epsi: 100.0
mpc_w_vel: 100.0
mpc_w_delta: 100.0
mpc_w_accel: 50.0
mpc_w_delta_d: 0.0
mpc_w_accel_d: 0.0
mpc_max_steering: 0.523 # Maximal steering radian (~30 deg)
mpc_max_throttle: 1.0 # Maximal throttle accel
mpc_bound_value: 1.0e3 # Bound value for other variables



================================================
FILE: launch/Simulation/params/pure_pursuit_params.yaml
================================================
# Parameters for pure pursuit controller
L: 0.5    # Length of car (m)
lfw: 0.25 # distance between the front of the vehicle and its center of gravity
Vcmd: 2.0 # reference speed (m/s)
Lfw: 1.0 # forward look ahead distance (m)
goal_radius: 1.0 # unit: m
controller_freq: 20 # unit: Hz
steering_gain: 1.0
base_angle: 0.0 # neutral point of servo (rad) 
cmd_vel_mode: true # whether or not publishing cmd_vel
smooth_accel: true # whether or not smoothing the acceleration of car
speed_incremental: 0.05 # speed incremental value (discrete acceleraton), unit: m/s
debug_mode: true


================================================
FILE: launch/Simulation/params/rviz_navigation.rviz
================================================
Panels:
  - Class: rviz/Displays
    Help Height: 81
    Name: Displays
    Property Tree Widget:
      Expanded:
        - /Global Planner1/Potential map1
        - /Local Planner1/Local costmap1
      Splitter Ratio: 0.605095983
    Tree Height: 562
  - Class: rviz/Selection
    Name: Selection
  - Class: rviz/Tool Properties
    Expanded:
      - /2D Pose Estimate1
      - /2D Nav Goal1
      - /Publish Point1
    Name: Tool Properties
    Splitter Ratio: 0.588679016
  - Class: rviz/Views
    Expanded:
      - /Current View1
    Name: Views
    Splitter Ratio: 0.5
  - Class: rviz/Time
    Experimental: false
    Name: Time
    SyncMode: 0
    SyncSource: ""
Visualization Manager:
  Class: ""
  Displays:
    - Class: rviz/TF
      Enabled: true
      Frame Timeout: 15
      Frames:
        All Enabled: true
        base_footprint:
          Value: true
        base_laser_link:
          Value: true
        base_link:
          Value: true
        map:
          Value: true
        odom:
          Value: true
      Marker Scale: 1
      Name: TF
      Show Arrows: true
      Show Axes: true
      Show Names: true
      Tree:
        map:
          odom:
            base_footprint:
              base_link:
                base_laser_link:
                  {}
      Update Interval: 0
      Value: true
    - Alpha: 0.5
      Cell Size: 1
      Class: rviz/Grid
      Color: 249; 249; 255
      Enabled: true
      Line Style:
        Line Width: 0.0299999993
        Value: Lines
      Name: Grid
      Normal Cell Count: 0
      Offset:
        X: 0
        Y: 0
        Z: 0
      Plane: XY
      Plane Cell Count: 50
      Reference Frame: <Fixed Frame>
      Value: true
    - Alpha: 1
      Axes Length: 1
      Axes Radius: 0.100000001
      Class: rviz/Pose
      Color: 255; 25; 0
      Enabled: true
      Head Length: 0.300000012
      Head Radius: 0.100000001
      Name: Pose
      Shaft Length: 1
      Shaft Radius: 0.0500000007
      Shape: Arrow
      Topic: /move_base/current_goal
      Unreliable: false
      Value: true
    - Alpha: 0.400000006
      Class: rviz/Map
      Color Scheme: map
      Draw Behind: false
      Enabled: true
      Name: Map
      Topic: /map
      Unreliable: false
      Use Timestamp: false
      Value: true
    - Class: rviz/Group
      Displays:
        - Alpha: 1
          Class: rviz/Polygon
          Color: 85; 0; 255
          Enabled: true
          Name: Robot Footprint
          Topic: /move_base/local_costmap/footprint
          Unreliable: false
          Value: true
        - Alpha: 1
          Autocompute Intensity Bounds: true
          Autocompute Value Bounds:
            Max Value: 10
            Min Value: -10
            Value: true
          Axis: Z
          Channel Name: intensity
          Class: rviz/LaserScan
          Color: 255; 255; 255
          Color Transformer: Intensity
          Decay Time: 0
          Enabled: false
          Invert Rainbow: false
          Max Color: 255; 255; 255
          Max Intensity: 1
          Min Color: 0; 0; 0
          Min Intensity: 1
          Name: LaserScan
          Position Transformer: XYZ
          Queue Size: 10
          Selectable: true
          Size (Pixels): 3
          Size (m): 0.00999999978
          Style: Flat Squares
          Topic: /scan
          Unreliable: false
          Use Fixed Frame: true
          Use rainbow: true
          Value: false
        - Alpha: 1
          Arrow Length: 0.100000001
          Axes Length: 0.300000012
          Axes Radius: 0.00999999978
          Class: rviz/PoseArray
          Color: 255; 25; 0
          Enabled: false
          Head Length: 0.0700000003
          Head Radius: 0.0299999993
          Name: AMCL Particles
          Shaft Length: 0.230000004
          Shaft Radius: 0.00999999978
          Shape: Arrow (Flat)
          Topic: /particlecloud
          Unreliable: false
          Value: false
        - Class: rviz/TF
          Enabled: false
          Frame Timeout: 15
          Frames:
            All Enabled: true
          Marker Scale: 1
          Name: TF
          Show Arrows: true
          Show Axes: true
          Show Names: true
          Tree:
            {}
          Update Interval: 0
          Value: false
        - Angle Tolerance: 0.100000001
          Class: rviz/Odometry
          Covariance:
            Orientation:
              Alpha: 0.5
              Color: 255; 255; 127
              Color Style: Unique
              Frame: Local
              Offset: 1
              Scale: 1
              Value: true
            Position:
              Alpha: 0.300000012
              Color: 204; 51; 204
              Scale: 1
              Value: true
            Value: true
          Enabled: false
          Keep: 100
          Name: Odometry
          Position Tolerance: 0.100000001
          Shape:
            Alpha: 1
            Axes Length: 1
            Axes Radius: 0.100000001
            Color: 255; 25; 0
            Head Length: 0.300000012
            Head Radius: 0.100000001
            Shaft Length: 1
            Shaft Radius: 0.0500000007
            Value: Arrow
          Topic: /odom
          Unreliable: false
          Value: false
      Enabled: true
      Name: Robot
    - Class: rviz/Group
      Displays:
        - Alpha: 1
          Buffer Length: 1
          Class: rviz/Path
          Color: 25; 255; 0
          Enabled: true
          Head Diameter: 0.300000012
          Head Length: 0.200000003
          Length: 0.300000012
          Line Style: Lines
          Line Width: 0.0299999993
          Name: GlobalPath
          Offset:
            X: 0
            Y: 0
            Z: 0
          Pose Color: 255; 85; 255
          Pose Style: None
          Radius: 0.0299999993
          Shaft Diameter: 0.100000001
          Shaft Length: 0.100000001
          Topic: /move_base/GlobalPlanner/plan
          Unreliable: false
          Value: true
        - Alpha: 0.400000006
          Class: rviz/Map
          Color Scheme: costmap
          Draw Behind: false
          Enabled: true
          Name: Potential map
          Topic: /move_base/GlobalPlanner/potential
          Unreliable: false
          Use Timestamp: false
          Value: true
      Enabled: true
      Name: Global Planner
    - Class: rviz/Group
      Displays:
        - Alpha: 1
          Arrow Length: 0.300000012
          Axes Length: 0.300000012
          Axes Radius: 0.00999999978
          Class: rviz/PoseArray
          Color: 255; 25; 0
          Enabled: false
          Head Length: 0.0700000003
          Head Radius: 0.0299999993
          Name: TebPoses
          Shaft Length: 0.230000004
          Shaft Radius: 0.00999999978
          Shape: Arrow (Flat)
          Topic: /move_base/TebLocalPlannerROS/teb_poses
          Unreliable: false
          Value: false
        - Class: rviz/Marker
          Enabled: false
          Marker Topic: /move_base/TebLocalPlannerROS/teb_markers
          Name: TebMarker
          Namespaces:
            {}
          Queue Size: 100
          Value: false
        - Alpha: 1
          Buffer Length: 1
          Class: rviz/Path
          Color: 255; 0; 0
          Enabled: false
          Head Diameter: 0.300000012
          Head Length: 0.200000003
          Length: 0.300000012
          Line Style: Lines
          Line Width: 0.0299999993
          Name: LocalPath
          Offset:
            X: 0
            Y: 0
            Z: 0
          Pose Color: 255; 85; 255
          Pose Style: None
          Radius: 0.0299999993
          Shaft Diameter: 0.100000001
          Shaft Length: 0.100000001
          Topic: /move_base/TrajectoryPlannerROS/global_plan
          Unreliable: false
          Value: false
        - Alpha: 0.800000012
          Class: rviz/Map
          Color Scheme: map
          Draw Behind: false
          Enabled: true
          Name: Local costmap
          Topic: /move_base/local_costmap/costmap
          Unreliable: false
          Use Timestamp: false
          Value: true
      Enabled: true
      Name: Local Planner
    - Alpha: 1
      Buffer Length: 1
      Class: rviz/Path
      Color: 85; 85; 255
      Enabled: true
      Head Diameter: 0.300000012
      Head Length: 0.200000003
      Length: 0.300000012
      Line Style: Lines
      Line Width: 0.0299999993
      Name: MPC_Reference
      Offset:
        X: 0
        Y: 0
        Z: 0
      Pose Color: 255; 85; 255
      Pose Style: None
      Radius: 0.0299999993
      Shaft Diameter: 0.100000001
      Shaft Length: 0.100000001
      Topic: /mpc_reference
      Unreliable: false
      Value: true
    - Alpha: 1
      Buffer Length: 1
      Class: rviz/Path
      Color: 255; 0; 0
      Enabled: true
      Head Diameter: 0.300000012
      Head Length: 0.00999999978
      Length: 0.200000003
      Line Style: Lines
      Line Width: 0.0299999993
      Name: MPC_Trajectory
      Offset:
        X: 0
        Y: 0
        Z: 0
      Pose Color: 255; 85; 255
      Pose Style: Axes
      Radius: 0.00999999978
      Shaft Diameter: 0.100000001
      Shaft Length: 0.00999999978
      Topic: /mpc_trajectory
      Unreliable: false
      Value: true
    - Class: rviz/Marker
      Enabled: true
      Marker Topic: /pure_pursuit/path_marker
      Name: Pure_Pursuit
      Namespaces:
        Markers: true
      Queue Size: 100
      Value: true
  Enabled: true
  Global Options:
    Background Color: 0; 0; 0
    Default Light: true
    Fixed Frame: map
    Frame Rate: 30
  Name: root
  Tools:
    - Class: rviz/Interact
      Hide Inactive Objects: true
    - Class: rviz/MoveCamera
    - Class: rviz/Select
    - Class: rviz/FocusCamera
    - Class: rviz/Measure
    - Class: rviz/SetInitialPose
      Topic: /initialpose
    - Class: rviz/SetGoal
      Topic: /move_base_simple/goal
    - Class: rviz/PublishPoint
      Single click: true
      Topic: /clicked_point
  Value: true
  Views:
    Current:
      Class: rviz/Orbit
      Distance: 13.6532335
      Enable Stereo Rendering:
        Stereo Eye Separation: 0.0599999987
        Stereo Focal Distance: 1
        Swap Stereo Eyes: false
        Value: false
      Focal Point:
        X: 4.77877808
        Y: 4.80319309
        Z: -1.40279174
      Focal Shape Fixed Size: true
      Focal Shape Size: 0.0500000007
      Invert Z Axis: false
      Name: Current View
      Near Clip Distance: 0.00999999978
      Pitch: 1.56480002
      Target Frame: <Fixed Frame>
      Value: Orbit (rviz)
      Yaw: 4.71043015
    Saved: ~
Window Geometry:
  Displays:
    collapsed: false
  Height: 846
  Hide Left Dock: false
  Hide Right Dock: true
  QMainWindow State: 000000ff00000000fd00000004000000000000016a000002c4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000028000002c4000000d700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002c4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730000000028000002c4000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004bf0000003efc0100000002fb0000000800540069006d00650100000000000004bf0000030000fffffffb0000000800540069006d006501000000000000045000000000000000000000034f000002c400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
  Selection:
    collapsed: false
  Time:
    collapsed: false
  Tool Properties:
    collapsed: false
  Views:
    collapsed: true
  Width: 1215
  X: 65
  Y: 25


================================================
FILE: launch/Simulation/stage/maze_carlike.world
================================================
include "robots/carlike_robot.inc"


define floorplan model
(
  # sombre, sensible, artistic
  color "gray30"

  # most maps will need a bounding box
  boundary 1

  gui_nose 0
  gui_grid 0
  gui_outline 0
  gripper_return 0
  fiducial_return 0
  laser_return 1
)

resolution 0.02
interval_sim 100  # simulation timestep in milliseconds

window
(
  size [ 600.0 700.0 ]
  center [ 0.0 0.0 ]
  rotate [ 0.0 0.0 ]
  scale 60
)

floorplan
(
  name "maze"
  bitmap "../maps/maze.png"
  size [ 10.0 10.0 2.0 ]
  pose [  5.0  5.0 0.0 0.0 ]
)

# throw in a robot
carlike_robot
(
  pose [ 1.0 1.0 0.0 0.0 ]
  name "robot"
)


================================================
FILE: launch/Simulation/stage/robots/carlike_robot.inc
================================================
define laser ranger
(
  sensor
  (
    range_max 6.5
    fov 180.0
    samples 640
  )
  # generic model properties
  color "black"
  size [ 0.06 0.15 0.03 ]
)

#
# Robot model:
# footprint (counter-clockwise): [-0.1,-0.125], [0.5,-0.125], [0.5,0.125], [-0.1,0.125]
# center of rotation: [0,0]
# wheelbase: 0.4

define carlike_robot position
(
  pose [ 0.0 0.0 0.0 0.0 ]

  odom_error [0.03 0.03 999999 999999 999999 0.02]

  size [ 0.6 0.25 0.40 ] # this models the footprint (rectangular), but shifted such that the bottom-left corner is in [0,0]. The center of rotation now here at [0.3, 0.125, 0.2]
  # correct center of rotation:
  origin [ 0.3 0.0 0.0 0.0]
  gui_nose 1
  color "red"

  # kinematics
  drive "car"
  wheelbase 0.4 # distance between both axles
  
  # spawn sensors
  laser(pose [ -0.1 0.0 -0.11 0.0 ])
)


================================================
FILE: launch/includes/HyphaROS_MiniCar_Drivers.launch.xml
================================================
<launch>
    <!-- launch file arguments -->
    <arg name="debug_mode"  default="false" doc="show debug info (bool)"/> 
    <arg name="pwm_radian"  default="450.0" doc="non scaled factor pwm/radian (steering)"/> 
    <arg name="neutral_pt"  default="0.0"   doc="steering neutral point (degree)"/>
    <arg name="odom_topic"  default="/odom" doc="odom topic name"/>
    <arg name="time_out"    default="0.5"   doc="communication time out, unit: sec"/> 
    <arg name="use_imu"     default="false" doc="use imu for ekf (bool)"/> 

    <!-- TF setting -->
    <include file="$(find hypharos_minicar)/launch/includes/minicar_tf.launch.xml" />

    <!-- YDLidar -->
    <include file="$(find hypharos_minicar)/launch/includes/ydlidar.launch.xml" />

    <!-- ODOMETRY -->
    <group if="$(arg use_imu)">
        <!-- base control -->
        <include file="$(find hypharos_minicar)/launch/includes/minicar_base.launch.xml">
            <arg name="debug_mode" value="$(arg debug_mode)"/>
            <arg name="odom_topic" value="$(arg odom_topic)"/>
            <arg name="pwm_radian" value="$(arg pwm_radian)"/>
            <arg name="neutral_pt" value="$(arg neutral_pt)"/>
            <arg name="time_out"   value="$(arg time_out)"/>
            <arg name="pub_tf"     value="false"/>
        </include>
        <!-- IMU -->
        <include file="$(find hypharos_minicar)/launch/includes/minicar_imu.launch.xml" />
        <!-- Robot_Localization -->
        <node pkg="robot_localization" type="ekf_localization_node" name="ekf_se" clear_params="true">
            <rosparam command="load" file="$(find hypharos_minicar)/launch/params/minicar_imu_ekf_params.yaml" />
            <remap from="/odometry/filtered" to="/odom" />
        </node>
    </group>

    <group unless="$(arg use_imu)">
        <!-- base control -->
        <include file="$(find hypharos_minicar)/launch/includes/minicar_base.launch.xml">
            <arg name="debug_mode" value="$(arg debug_mode)"/>
            <arg name="odom_topic" value="$(arg odom_topic)"/>
            <arg name="pwm_radian" value="$(arg pwm_radian)"/>
            <arg name="neutral_pt" value="$(arg neutral_pt)"/>
            <arg name="time_out"   value="$(arg time_out)"/>
            <arg name="pub_tf"     value="true"/>
        </include>
    </group>
</launch>


================================================
FILE: launch/includes/amcl.launch.xml
================================================
<launch>
    <arg name="init_x" default="0" />
    <arg name="init_y" default="0" />
    <arg name="init_a" default="0" />
    <remap from="map" to="map_amcl"/>

    <node pkg="amcl" type="amcl" name="amcl" output="screen">
        <!-- Publish scans from best pose at a max of 10 Hz -->
        <param name="transform_tolerance" value="0.5" />
        <param name="gui_publish_rate" value="5.0"/>
        <param name="min_particles" value="800"/>
        <param name="max_particles" value="1500"/>
        <param name="kld_err" value="0.05"/>
        <param name="kld_z" value="0.95"/>
        <!-- translation std dev, m -->
        <param name="odom_alpha1" value="2.0"/>
        <param name="odom_alpha2" value="2.0"/>
        <param name="odom_alpha3" value="2.0"/>
        <param name="odom_alpha4" value="2.0"/>
        <param name="laser_z_hit" value="0.7"/>
        <param name="laser_z_short" value="0.05"/>
        <param name="laser_z_max" value="0.2"/>
        <param name="laser_z_rand" value="0.05"/>
        <param name="laser_sigma_hit" value="0.1"/>
        <param name="laser_lambda_short" value="0.1"/>
        <param name="laser_min_range" value="0.2"/>
        <param name="laser_max_range" value="2.8"/>

        <param name="laser_model_type" value="likelihood_field"/>
        <param name="laser_likelihood_max_dist" value="2.0"/>
        <param name="laser_max_beams"  value="100"/>
        <param name="update_min_d" value="0.01"/>
        <param name="update_min_a" value="0.01"/>
        <param name="resample_interval" value="1"/>
        <param name="recovery_alpha_slow" value="0.001"/>
        <param name="recovery_alpha_fast" value="0.1"/>

        <param name="use_map_topic" value="true"/>
        <param name="first_map_only" value="true"/>
        <param name="tf_broadcast" value="true"/>

        <param name="odom_frame_id" value="/odom"/>
        <param name="global_frame_id" value="/map"/>
        <param name="base_frame_id" value="/base_footprint"/>
        <param name="odom_model_type" value="diff-corrected"/>

        <param name="initial_pose_x" value="$(arg init_x)"/>
        <param name="initial_pose_y" value="$(arg init_y)"/>
        <param name="initial_pose_a" value="$(arg init_a)"/>
        <param name="initial_cov_xx" value="0.05" />
        <param name="initial_cov_yy" value="0.05" />
        <param name="initial_cov_aa" value="0.02" />
    </node>
</launch>


================================================
FILE: launch/includes/gmapping.launch.xml
================================================
<?xml version="1.0"?>

<launch>
    <!-- Launch file parameters -->
    <arg name="output"  default="log" />  <!-- option: "screen" or "log" --> 

    <!-- gmapping -->
    <node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="$(arg output)">
        <param name="map_update_interval" value="1.0"/>
        <param name="maxUrange" value="16.0"/>
        <param name="sigma" value="0.05"/>
        <param name="kernelSize" value="1"/>
        <param name="lstep" value="0.05"/>
        <param name="astep" value="0.05"/>
        <param name="iterations" value="5"/>
        <param name="lsigma" value="0.075"/>
        <param name="ogain" value="3.0"/>
        <param name="lskip" value="0"/>
        <param name="srr" value="0.1"/>
        <param name="srt" value="0.2"/>
        <param name="str" value="0.1"/>
        <param name="stt" value="0.2"/>
        <param name="linearUpdate" value="0.10"/>
        <param name="angularUpdate" value="0.2"/>
        <param name="temporalUpdate" value="1.0"/>
        <param name="resampleThreshold" value="0.25"/>
        <param name="particles" value="30"/>
        <param name="xmin" value="-50.0"/>
        <param name="ymin" value="-50.0"/>
        <param name="xmax" value="50.0"/>
        <param name="ymax" value="50.0"/>
        <param name="delta" value="0.05"/>
        <param name="llsamplerange" value="0.01"/>
        <param name="llsamplestep" value="0.01"/>
        <param name="lasamplerange" value="0.005"/>
        <param name="lasamplestep" value="0.005"/>
        <param name="odom_frame" value="odom"/>
        <param name="base_frame" value="base_footprint"/>
    </node>

</launch>


================================================
FILE: launch/includes/hector_slam.launch.xml
================================================
<?xml version="1.0"?>

<launch>
    <!-- Launch file parameters -->
    <arg name="output"  default="log" />  <!-- option: "screen" or "log" --> 
    <arg name="tf_map_scanmatch_transform_frame_name" default="scanmatcher_frame"/>
    <arg name="base_frame" default="base_footprint"/>
    <arg name="odom_frame" default="odom"/>
    <arg name="pub_map_odom_transform" default="true"/>
    <arg name="scan_subscriber_queue_size" default="5"/>
    <arg name="scan_topic" default="scan"/>
    <arg name="map_size" default="2048"/>

    <!-- hector mapping -->
    <node pkg="hector_mapping" type="hector_mapping" name="hector_mapping" output="$(arg output)">
        <!-- Frame names -->
        <param name="map_frame" value="map" />
        <param name="base_frame" value="$(arg base_frame)" />
        <param name="odom_frame" value="$(arg odom_frame)" />

        <!-- Tf use -->
        <param name="use_tf_scan_transformation" value="true"/>
        <param name="use_tf_pose_start_estimate" value="false"/>
        <param name="pub_map_odom_transform" value="$(arg pub_map_odom_transform)"/>

        <!-- Map size / start point -->
        <param name="map_resolution" value="0.050"/>
        <param name="map_size" value="$(arg map_size)"/>
        <param name="map_start_x" value="0.5"/>
        <param name="map_start_y" value="0.5" />
        <param name="map_multi_res_levels" value="2" />

        <!-- Map update parameters -->
        <param name="update_factor_free" value="0.4"/>
        <param name="update_factor_occupied" value="0.9" />    
        <param name="map_update_distance_thresh" value="0.4"/>
        <param name="map_update_angle_thresh" value="0.06" />
        <param name="laser_z_min_value" value = "-1.0" />
        <param name="laser_z_max_value" value = "1.0" />

        <!-- Advertising config --> 
        <param name="advertise_map_service" value="true"/>

        <param name="scan_subscriber_queue_size" value="$(arg scan_subscriber_queue_size)"/>
        <param name="scan_topic" value="$(arg scan_topic)"/>

        <!-- Debug parameters -->
        <!--
          <param name="output_timing" value="false"/>
          <param name="pub_drawings" value="true"/>
          <param name="pub_debug_output" value="true"/>
        -->
        <param name="tf_map_scanmatch_transform_frame_name" value="$(arg tf_map_scanmatch_transform_frame_name)" />
    </node>

    <!-- TF -->
    <node pkg="tf" type="static_transform_publisher" name="map_nav_broadcaster" args="0 0 0 0 0 0 map nav 100"/>

    <!-- geotiff_mapper -->
    <include file="$(find hector_geotiff)/launch/geotiff_mapper.launch">
        <arg name="trajectory_source_frame_name" value="$(arg base_frame)"/>
    </include>

</launch>


================================================
FILE: launch/includes/karto_slam.launch.xml
================================================
<?xml version="1.0"?>

<launch>
    <!-- Launch file parameters -->
    <arg name="output"  default="log" />  <!-- option: "screen" or "log" --> 

    <!-- Karto SLAM -->
    <node pkg="slam_karto" type="slam_karto" name="slam_karto" output="$(arg output)">
        <param name="odom_frame" value="odom"/>
        <param name="map_update_interval" value="10"/>
        <param name="resolution" value="0.025"/>
    </node>

</launch>


================================================
FILE: launch/includes/minicar_base.launch.xml
================================================
<launch>
    <!-- launch file arguments -->
    <arg name="debug_mode"  default="false" doc="show debug info (bool)"/> 
    <arg name="pwm_radian"  default="450.0" doc="non scaled factor pwm/radian (steering)"/> 
    <arg name="neutral_pt"  default="0.0"   doc="steering neutral point (degree)"/>
    <arg name="odom_topic"  default="/odom" doc="odom topic name"/>
    <arg name="odom_freq"   default="50"    doc="freq of odom topic, unit: Hz"/>
    <arg name="time_out"    default="0.5"   doc="communication time out, unit: sec"/> 
    <arg name="pub_tf"      default="true"  doc="broadcast odom TF (bool)"/> 

    <node name="base_control"   pkg="hypharos_minicar"  type="base_control.py" output="screen">
        <param name="port"       value="/dev/stm32base"/>
        <param name="baudrate"   value="115200"/>   
        <param name="base_id"    value="base_footprint"/> 
        <param name="odom_id"    value="odom"/>      
        <param name="odom_freq"  value="$(arg odom_freq)"/>
        <param name="odom_topic" value="$(arg odom_topic)"/> 
        <param name="pwm_radian" value="$(arg pwm_radian)"/>
        <param name="neutral_pt" value="$(arg neutral_pt)"/>
        <param name="pub_tf"     value="$(arg pub_tf)"/>   
        <param name="debug_mode" value="$(arg debug_mode)"/> 
        <param name="time_out"   value="$(arg time_out)"/> 
    </node>
</launch>


================================================
FILE: launch/includes/minicar_tf.launch.xml
================================================
<launch>
    <node pkg="tf" type="static_transform_publisher" name="base_footprint2base_link" args=" 0 0 0 0 0 0 /base_footprint /base_link 10"/>
    <node pkg="tf" type="static_transform_publisher" name="base_link2laser_link"     args=" 0 0 0.15 0 0 0 /base_link /laser_link 10"/>
    <node pkg="tf" type="static_transform_publisher" name="base_link2imu"            args=" 0 0 0 0 0 3.1415926 /base_link /imu_link 10"/>
</launch>


================================================
FILE: launch/includes/mrpt_icp.launch.xml
================================================
<?xml version="1.0"?>

<launch>
    <!-- Launch file parameters -->
    <arg name="output"  default="log" />  <!-- option: "screen" or "log" --> 

    <!-- MRPT ICP -->
    <param name="ini_filename" value="$(find mrpt_icp_slam_2d)/tutorial/icp_slam_demo.ini"/>
    <param name="odom_frame_id" value="/odom"/>
    <param name="global_frame_id" value="/map"/>
    <param name="base_frame_id" value="/laser_link"/>
    <param name="sensor_source" value="/scan"/>
    <env name="ROSCONSOLE_CONFIG_FILE" value="$(find mrpt_icp_slam_2d)/config/rosconsole.config"/>
    <!--SLAM RUN-->
    <node pkg="mrpt_icp_slam_2d" type="mrpt_icp_slam_2d" name="mrpt_icp_slam_2d" output="$(arg output)"/>

</launch>


================================================
FILE: launch/includes/ydlidar.launch.xml
================================================
<launch>
  <node name="ydlidar_node"  pkg="ydlidar"  type="ydlidar_node" output="screen">
    <param name="port"         type="string" value="/dev/ydlidar"/>  
    <param name="baudrate"     type="int"    value="128000"/>
    <param name="frame_id"     type="string" value="laser_link"/>
    <param name="angle_fixed"  type="bool"   value="true"/>
    <param name="intensities"  type="bool"   value="false"/>
    <param name="angle_min"    type="double" value="-180" />
    <param name="angle_max"    type="double" value="180" />
    <param name="range_min"    type="double" value="0.08" />
    <param name="range_max"    type="double" value="10.0" />
    <param name="ignore_array" type="string" value="" />
  </node>
</launch>


================================================
FILE: launch/params/costmap_common_params.yaml
================================================

#---standard pioneer footprint---
#---(in meters)---
#footprint: [ [0.254, -0.0508], [0.1778, -0.0508], [0.1778, -0.1778], [-0.1905, -0.1778], [-0.254, 0], [-0.1905, 0.1778], [0.1778, 0.1778], [0.1778, 0.0508], [0.254, 0.0508] ]
#footprint: [ [-0.1,-0.125], [0.5,-0.125], [0.5,0.125], [-0.1,0.125] ]
footprint: [ [-0.145,-0.08], [0.0,-0.08], [0.0,0.08], [-0.145,0.08] ]

transform_tolerance: 0.2
map_type: costmap

obstacle_layer:
  enabled: true
  obstacle_range: 3.0
  raytrace_range: 3.5
  inflation_radius: 0.2
  track_unknown_space: false
  combination_method: 1

  observation_sources: base_scan
  base_scan: {sensor_frame: laser_link, data_type: LaserScan, topic: scan, marking: true, clearing: true}


inflation_layer:
  enabled:              true
  cost_scaling_factor:  10.0  # exponential rate at which the obstacle cost drops off (default: 10)
  inflation_radius:     0.5  # max. distance from an obstacle at which costs are incurred for planning paths.

static_layer:
  enabled:              true
  map_topic:            "/map"


================================================
FILE: launch/params/global_costmap_params.yaml
================================================
global_costmap:
    global_frame: /map
    robot_base_frame: base_link
    update_frequency: 1.0
    publish_frequency: 0.5
    static_map: true

    transform_tolerance: 0.5
    plugins:
    - {name: static_layer,            type: "costmap_2d::StaticLayer"}
    - {name: obstacle_layer,          type: "costmap_2d::VoxelLayer"}
    - {name: inflation_layer,         type: "costmap_2d::InflationLayer"}


    inflation_layer:
        inflation_radius: 1.0
        cost_scaling_factor: 6.0



================================================
FILE: launch/params/global_planner.yaml
================================================
GlobalPlanner:
    use_dijkstra: true
    use_grid_path: false


================================================
FILE: launch/params/local_costmap_params.yaml
================================================
local_costmap:
  global_frame: /map
  robot_base_frame: base_link
  update_frequency: 10.0
  publish_frequency: 10.0
  static_map: false
  rolling_window: true
  width: 1.5
  height: 1.5
  resolution: 0.2
  transform_tolerance: 0.5
  
  plugins:
   - {name: static_layer,        type: "costmap_2d::StaticLayer"}
   - {name: obstacle_layer,      type: "costmap_2d::ObstacleLayer"}


================================================
FILE: launch/params/mpc/mpc_params.yaml
================================================
# Parameters for control loop
pub_twist_cmd: true
debug_info: false
delay_mode: true
max_speed: 1.5 # unit: m/s 
waypoints_dist: -1.0 # unit: m, set < 0 means computed by node
path_length: 3.0 # unit: m
goal_radius: 0.2 # unit: m
controller_freq: 10
vehicle_Lf: 0.0723 # distance between the front of the vehicle and its center of gravity

# Parameter for MPC solver
mpc_steps: 20.0
mpc_ref_cte: 0.0
mpc_ref_epsi: 0.0
mpc_ref_vel: 1.0
mpc_w_cte: 100.0
mpc_w_epsi: 100.0
mpc_w_vel: 100.0
mpc_w_delta: 100.0
mpc_w_accel: 50.0
mpc_w_delta_d: 0.0
mpc_w_accel_d: 0.0
mpc_max_steering: 0.436 # Maximal steering radian (~25 deg)
mpc_max_throttle: 0.8 # Maximal throttle accel
mpc_bound_value: 1.0e3 # Bound value for other variables



================================================
FILE: launch/params/pure_pursuit/pure_pursuit_params.yaml
================================================
# Parameters for pure pursuit controller
L: 0.1446    # Length of car (m)
lfw: 0.0723 # distance between the front of the vehicle and its center of gravity
Vcmd: 1.5 # reference speed (m/s)
Lfw: 1.0 # forward look ahead distance (m)
goal_radius: 1.0 # unit: m
controller_freq: 20 # unit: Hz
steering_gain: 1.2
base_angle: 0.0 # neutral point of servo (rad) 
cmd_vel_mode: false # whether or not publishing cmd_vel
smooth_accel: true # whether or not smoothing the acceleration of car
speed_incremental: 0.05 # speed incremental value (discrete acceleraton), unit: m/s
debug_mode: false


================================================
FILE: launch/params/teb/teb_local_planner_params.yaml
================================================
TebLocalPlannerROS:

 odom_topic: odom
    
 # Trajectory
  
 teb_autosize: True
 dt_ref: 0.3
 dt_hysteresis: 0.1
 global_plan_overwrite_orientation: True
 allow_init_with_backwards_motion: True
 max_global_plan_lookahead_dist: 3.0
 feasibility_check_no_poses: 2
    
 # Robot
         
 max_vel_x: 0.4
 max_vel_x_backwards: 0.2
 max_vel_y: 0.0
 max_vel_theta: 0.3 # the angular velocity is also bounded by min_turning_radius in case of a carlike robot (r = v / omega)
 acc_lim_x: 0.5
 acc_lim_theta: 0.5

 # ********************** Carlike robot parameters ********************
 min_turning_radius: 0.5        # Min turning radius of the carlike robot (compute value using a model or adjust with rqt_reconfigure manually)
 wheelbase: 0.4                 # Wheelbase of our robot
 cmd_angle_instead_rotvel: True # stage simulator takes the angle instead of the rotvel as input (twist message)
 # ********************************************************************

 footprint_model: # types: "point", "circular", "two_circles", "line", "polygon"
   type: "line"
   radius: 0.2 # for type "circular"
   line_start: [0.0, 0.0] # for type "line"
   line_end: [0.4, 0.0] # for type "line"
   front_offset: 0.2 # for type "two_circles"
   front_radius: 0.2 # for type "two_circles"
   rear_offset: 0.2 # for type "two_circles"
   rear_radius: 0.2 # for type "two_circles"
   vertices: [ [0.25, -0.05], [0.18, -0.05], [0.18, -0.18], [-0.19, -0.18], [-0.25, 0], [-0.19, 0.18], [0.18, 0.18], [0.18, 0.05], [0.25, 0.05] ] # for type "polygon"

 # GoalTolerance
    
 xy_goal_tolerance: 0.2
 yaw_goal_tolerance: 0.1
 free_goal_vel: False
    
 # Obstacles
    
 min_obstacle_dist: 0.27 # This value must also include our robot's expansion, since footprint_model is set to "line".
 include_costmap_obstacles: True
 costmap_obstacles_behind_robot_dist: 1.0
 obstacle_poses_affected: 30
 costmap_converter_plugin: ""
 costmap_converter_spin_thread: True
 costmap_converter_rate: 5

 # Optimization
    
 no_inner_iterations: 5
 no_outer_iterations: 4
 optimization_activate: True
 optimization_verbose: False
 penalty_epsilon: 0.1
 weight_max_vel_x: 2
 weight_max_vel_theta: 1
 weight_acc_lim_x: 1
 weight_acc_lim_theta: 1
 weight_kinematics_nh: 1000
 weight_kinematics_forward_drive: 1
 weight_kinematics_turning_radius: 1
 weight_optimaltime: 1
 weight_obstacle: 50
 weight_dynamic_obstacle: 10 # not in use yet

 # Homotopy Class Planner

 enable_homotopy_class_planning: True
 enable_multithreading: True
 simple_exploration: False
 max_number_classes: 4
 selection_cost_hysteresis: 1.0
 selection_obst_cost_scale: 1.0
 selection_alternative_time_cost: False
 roadmap_graph_no_samples: 15
 roadmap_graph_area_width: 5
 h_signature_prescaler: 0.5
 h_signature_threshold: 0.1
 obstacle_keypoint_offset: 0.1
 obstacle_heading_threshold: 0.45
 visualize_hc_graph: False


================================================
FILE: map/map_amcl.pgm
================================================
P5
# CREATOR: Map_generator.cpp 0.050 m/pix
1984 1984
255


================================================
FILE: map/map_amcl.yaml
================================================
image: map_amcl.pgm
resolution: 0.050000
origin: [-50.000000, -50.000000, 0.000000]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196



================================================
FILE: map/map_nav.pgm
================================================
P5
# CREATOR: GIMP PNM Filter Version 1.1
1984 1984
255


================================================
FILE: map/map_nav.yaml
================================================
image: map_nav.pgm
resolution: 0.050000
origin: [-50.000000, -50.000000, 0.000000]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196



================================================
FILE: package.xml
================================================
<?xml version="1.0"?>
<package format="2">
  <name>hypharos_minicar</name>
  <version>0.0.0</version>
  <description>The hypharos_minicar package</description>

  <maintainer email="hypharos@gmail.com">HaoChih, Lin</maintainer>
  <license>Apache 2.0</license>
  <url type="website">https://hypharosworkshop.wordpress.com/</url>


  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>costmap_2d</build_depend>
  <build_depend>dynamic_reconfigure</build_depend>
  <build_depend>geometry_msgs</build_depend>
  <build_depend>message_generation</build_depend>
  <build_depend>move_base</build_depend>
  <build_depend>nav_msgs</build_depend>
  <build_depend>ackermann_msgs</build_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_depend>tf</build_depend>
  <build_depend>visualization_msgs</build_depend>
  <build_export_depend>costmap_2d</build_export_depend>
  <build_export_depend>dynamic_reconfigure</build_export_depend>
  <build_export_depend>geometry_msgs</build_export_depend>
  <build_export_depend>move_base</build_export_depend>
  <build_export_depend>nav_msgs</build_export_depend>
  <build_export_depend>ackermann_msgs</build_export_depend>
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>rospy</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>
  <build_export_depend>tf</build_export_depend>
  <build_export_depend>visualization_msgs</build_export_depend>
  <exec_depend>costmap_2d</exec_depend>
  <exec_depend>dynamic_reconfigure</exec_depend>
  <exec_depend>geometry_msgs</exec_depend>
  <exec_depend>move_base</exec_depend>
  <exec_depend>nav_msgs</exec_depend>
  <exec_depend>ackermann_msgs</exec_depend>
  <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  <exec_depend>tf</exec_depend>
  <exec_depend>visualization_msgs</exec_depend>


  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->

  </export>
</package>


================================================
FILE: readme.md
================================================
# HyphaROS MiniCar (1/20 Scale MPC Racing Car)
![alt text](https://github.com/Hypha-ROS/hypharos_minicar/blob/master/document/photo/HyphaROS_logo.png)  

## Abstract
Low cost, High speed 1/20 Racing Car for control laws evaluation !   
Fully open-sourced (hardware & software), total cost <300USD.  
Currently supports: Pure-Pursuit, Model-Predictive-Control (Nonlinear)  

![alt text](https://github.com/Hypha-ROS/hypharos_minicar/blob/master/document/photo/HyphaROS_MiniCar_photo.jpg)  

## About us
FB Page: https://www.facebook.com/HyphaROS/  
Website: https://hypharosworkshop.wordpress.com/  
Contact: hypha.ros@gmail.com  
Developer:   
* HaoChih, LIN  

Date: 2018/08/16  
License: Apache 2.0  

## Features
* Nonlinear Bicycle Model Based MPC (through ipopt solver)  
* Pure-Pursuit Controller  
* Onboard mapping (Gmapping, Hector-SLAM, Karto-SLAM, MRPT-ICP)  
* STM32 for motor speed closed-loop control  
* AMCL localization (encoder-odometry based)  
* Dynamic obstacle avoidance  
* Stage Simulation (supports: MPC & Pure-Pursuit)  

## Roadmap
* Add EKF supports (odometry with mpu6050)  
* MPC for obstacle avoidance  
* Implement MPC on different solvers (ACADO, OSQP, etc)  
* Multi-cars racing through ROS 2.0 layer  
* High Speed Drifting  

## Hardware 
* Odroid XU4  
(Ref: https://www.hardkernel.com/main/products/prdt_info.php)   
* YDLidar X4  
(Ref: http://www.ydlidar.com/product/X4)  
* STM32(F103) MCU (with OLED display)  
* Diff Motor with A/B encoder(res: 340)  
* Ackermann Based 1/20 car chassis  
(Ref: https://item.taobao.com/item.htm?spm=a312a.7700824.w4004-15726392027.68.79503c88Rqwzb9&id=554619475840)   
Total Cost: < 300 USD  

## Document  
HyphaROS MPC MiniCar 1-Day Workshop:  
https://drive.google.com/open?id=1yX0aeA4spf_szpxXFpIlH0EQKIgiwJx7  
ROS Summer School in China 2018 Slides:  
https://goo.gl/RpVBDH  

## Software
### VirtualBox Image ###  
OVA image file (Kinetic, password: hypharos, 20180816)  
Link: https://drive.google.com/open?id=1uRvXGakvQrbynmPHX_KIFJxPm8o6MWPb  

### Odroid Image
Image file for Odroid XU4.(with SD card >=16G, password: hypharos)  
Link: https://goo.gl/87vrNk   
(if your SD card is around 13GB, it's OK to force Win32DiskImager to write the file!)   
The default ethernet IP address is 10.0.0.1  

### STM32 (MCU)
Source codes: https://drive.google.com/open?id=19rjjpJmz85lTSxCyu-9CtvZhUW37c2LS         
[WARNING!]  
Since the original STM32 codes came from third-paries,   
currently, the quality of codes are not guaranteed by us.  
For MCUISP Driver: http://www.mcuisp.com/English%20mcuisp%20web/ruanjianxiazai-english.htm  

### Install from source (16.04) 
1. Install ROS Kinetic (Desktop-Full) (http://wiki.ros.org/kinetic/Installation/Ubuntu)  
2. Install dependencies:  
$ sudo apt-get install remmina synaptic gimp git ros-kinetic-navigation* ros-kinetic-gmapping ros-kinetic-hector-slam ros-kinetic-mrpt-icp-slam-2d ros-kinetic-slam-karto ros-kinetic-ackermann-msgs -y  
3. Install Ipopt: Please refer the tutorial in "document/ipopt_install".  
4. create your own catkin_ws   
(http://wiki.ros.org/ROS/Tutorials/InstallingandConfiguringROSEnvironment#Create_a_ROS_Workspace)  
$ cd catkin_ws/src  
$ git clone https://github.com/EAIBOT/ydlidar  
$ git clone https://github.com/Hypha-ROS/hypharos_minicar   
$ cd ..  
$ catkin_make  

## Operation
### Simulation
$ roslaunch hypharos_minicar HyphaROS_Simulation_Stage.launch  
The default controller is mpc, you can switch to pure-pursuit or DWA through param: "controller"    
![alt text](https://github.com/Hypha-ROS/hypharos_minicar/blob/master/document/photo/HyphaROS_MPC_MiniCar_Simulation.jpg)    
  
### Ethernet Connection
The default static eth IP on Odroid image is 10.0.0.1, hence, to connect to your Odroid through cable, please set your host IP as 10.0.0.X  
Notice: for the first bootup, you have to update Odroid MAC address through HDMI Dispaly!  

### Wifi Connection
Use ethernet or display connection to make Odroid connect to your local Wifi AP. Remember to set ROS_MASTER_URI and ROS_IP in ".bashrc" file on both Odroid & host machine.    

### Mapping
* MiniCar (Odroid) side:  
$ roslaunch hypharos_minicar HyphaROS_MiniCar_Mapping.launch  
The default mapping algorithm is gmapping, you can swith to other slam method through param: "slam_type"  
(crrently supports: gmapping, karto_slam, mrpt_icp and hector_slam)  
  
* Host (Desktop) side:  
$ roslaunch hypharos_minicar HyphaROS_Desktop_Mapping.launch  
Use keyboard to control the minicar.  
  
After mapping, remember to save two maps, one for amcl and the other for move_base!  

### Racing
* MiniCar (Odroid) side:  
$ roslaunch hypharos_minicar HyphaROS_MiniCar_Racing.launch  
The default controller is mpc, you can swith to other slam method through param: "controller"  
(crrently supports: mpc and pure_pursuit)  
  
* Host (Desktop) side:  
$ roslaunch hypharos_minicar HyphaROS_Desktop_Racing.launch  
Use keyboard to interrupt controller's behavior.  



================================================
FILE: rviz/hypharos_minicar_mapping.rviz
================================================
Panels:
  - Class: rviz/Displays
    Help Height: 78
    Name: Displays
    Property Tree Widget:
      Expanded: ~
      Splitter Ratio: 0.5
    Tree Height: 775
  - Class: rviz/Selection
    Name: Selection
  - Class: rviz/Tool Properties
    Expanded:
      - /2D Pose Estimate1
      - /2D Nav Goal1
      - /Publish Point1
    Name: Tool Properties
    Splitter Ratio: 0.588679016
  - Class: rviz/Views
    Expanded:
      - /Current View1
    Name: Views
    Splitter Ratio: 0.5
  - Class: rviz/Time
    Experimental: false
    Name: Time
    SyncMode: 0
    SyncSource: LaserScan
Visualization Manager:
  Class: ""
  Displays:
    - Alpha: 0.5
      Cell Size: 1
      Class: rviz/Grid
      Color: 160; 160; 164
      Enabled: true
      Line Style:
        Line Width: 0.0299999993
        Value: Lines
      Name: Grid
      Normal Cell Count: 0
      Offset:
        X: 0
        Y: 0
        Z: 0
      Plane: XY
      Plane Cell Count: 10
      Reference Frame: <Fixed Frame>
      Value: true
    - Alpha: 0.699999988
      Class: rviz/Map
      Color Scheme: map
      Draw Behind: false
      Enabled: true
      Name: Map
      Topic: /map
      Unreliable: false
      Use Timestamp: false
      Value: true
    - Class: rviz/TF
      Enabled: true
      Frame Timeout: 15
      Frames:
        All Enabled: true
        base_footprint:
          Value: true
        base_link:
          Value: true
        imu_link:
          Value: true
        laser_link:
          Value: true
        map:
          Value: true
        odom:
          Value: true
      Marker Scale: 1
      Name: TF
      Show Arrows: true
      Show Axes: true
      Show Names: true
      Tree:
        map:
          odom:
            base_footprint:
              base_link:
                imu_link:
                  {}
                laser_link:
                  {}
      Update Interval: 0
      Value: true
    - Alpha: 1
      Autocompute Intensity Bounds: true
      Autocompute Value Bounds:
        Max Value: 10
        Min Value: -10
        Value: true
      Axis: Z
      Channel Name: intensity
      Class: rviz/LaserScan
      Color: 255; 255; 255
      Color Transformer: Intensity
      Decay Time: 0
      Enabled: true
      Invert Rainbow: false
      Max Color: 255; 255; 255
      Max Intensity: 10
      Min Color: 0; 0; 0
      Min Intensity: 10
      Name: LaserScan
      Position Transformer: XYZ
      Queue Size: 10
      Selectable: true
      Size (Pixels): 3
      Size (m): 0.00999999978
      Style: Flat Squares
      Topic: /scan
      Unreliable: false
      Use Fixed Frame: true
      Use rainbow: true
      Value: true
    - Angle Tolerance: 0.100000001
      Class: rviz/Odometry
      Covariance:
        Orientation:
          Alpha: 0.5
          Color: 255; 255; 127
          Color Style: Unique
          Frame: Local
          Offset: 1
          Scale: 1
          Value: true
        Position:
          Alpha: 0.300000012
          Color: 204; 51; 204
          Scale: 1
          Value: true
        Value: false
      Enabled: true
      Keep: 100
      Name: Odometry
      Position Tolerance: 0.100000001
      Shape:
        Alpha: 1
        Axes Length: 1
        Axes Radius: 0.100000001
        Color: 255; 25; 0
        Head Length: 0.100000001
        Head Radius: 0.0500000007
        Shaft Length: 0.100000001
        Shaft Radius: 0.0199999996
        Value: Arrow
      Topic: /odom
      Unreliable: false
      Value: true
  Enabled: true
  Global Options:
    Background Color: 48; 48; 48
    Default Light: true
    Fixed Frame: map
    Frame Rate: 30
  Name: root
  Tools:
    - Class: rviz/Interact
      Hide Inactive Objects: true
    - Class: rviz/MoveCamera
    - Class: rviz/Select
    - Class: rviz/FocusCamera
    - Class: rviz/Measure
    - Class: rviz/SetInitialPose
      Topic: /initialpose
    - Class: rviz/SetGoal
      Topic: /move_base_simple/goal
    - Class: rviz/PublishPoint
      Single click: true
      Topic: /clicked_point
  Value: true
  Views:
    Current:
      Class: rviz/Orbit
      Distance: 5.40849447
      Enable Stereo Rendering:
        Stereo Eye Separation: 0.0599999987
        Stereo Focal Distance: 1
        Swap Stereo Eyes: false
        Value: false
      Focal Point:
        X: 0.00899724383
        Y: -0.074087061
        Z: 0.856899977
      Focal Shape Fixed Size: true
      Focal Shape Size: 0.0500000007
      Invert Z Axis: false
      Name: Current View
      Near Clip Distance: 0.00999999978
      Pitch: 1.56979632
      Target Frame: <Fixed Frame>
      Value: Orbit (rviz)
      Yaw: 3.09352851
    Saved: ~
Window Geometry:
  Displays:
    collapsed: false
  Height: 1056
  Hide Left Dock: false
  Hide Right Dock: true
  QMainWindow State: 000000ff00000000fd00000004000000000000016a00000396fc0200000009fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000002800000396000000d700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d00610067006501000002c7000000f70000000000000000000000010000010f000002c4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730000000028000002c4000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073f0000003efc0100000002fb0000000800540069006d006501000000000000073f0000030000fffffffb0000000800540069006d00650100000000000004500000000000000000000005cf0000039600000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
  Selection:
    collapsed: false
  Time:
    collapsed: false
  Tool Properties:
    collapsed: false
  Views:
    collapsed: true
  Width: 1855
  X: 65
  Y: 24


================================================
FILE: rviz/hypharos_minicar_racing.rviz
================================================
Panels:
  - Class: rviz/Displays
    Help Height: 81
    Name: Displays
    Property Tree Widget:
      Expanded:
        - /Global Planner1/Potential map1
        - /Local Planner1/Local costmap1
      Splitter Ratio: 0.605095983
    Tree Height: 562
  - Class: rviz/Selection
    Name: Selection
  - Class: rviz/Tool Properties
    Expanded:
      - /2D Pose Estimate1
      - /2D Nav Goal1
      - /Publish Point1
    Name: Tool Properties
    Splitter Ratio: 0.588679016
  - Class: rviz/Views
    Expanded:
      - /Current View1
    Name: Views
    Splitter Ratio: 0.5
  - Class: rviz/Time
    Experimental: false
    Name: Time
    SyncMode: 0
    SyncSource: LaserScan
Visualization Manager:
  Class: ""
  Displays:
    - Class: rviz/TF
      Enabled: true
      Frame Timeout: 15
      Frames:
        All Enabled: true
        base_footprint:
          Value: true
        base_link:
          Value: true
        imu_link:
          Value: true
        laser_link:
          Value: true
        map:
          Value: true
        odom:
          Value: true
      Marker Scale: 1
      Name: TF
      Show Arrows: true
      Show Axes: true
      Show Names: true
      Tree:
        map:
          odom:
            base_footprint:
              base_link:
                imu_link:
                  {}
                laser_link:
                  {}
      Update Interval: 0
      Value: true
    - Alpha: 0.5
      Cell Size: 1
      Class: rviz/Grid
      Color: 249; 249; 255
      Enabled: true
      Line Style:
        Line Width: 0.0299999993
        Value: Lines
      Name: Grid
      Normal Cell Count: 0
      Offset:
        X: 0
        Y: 0
        Z: 0
      Plane: XY
      Plane Cell Count: 50
      Reference Frame: <Fixed Frame>
      Value: true
    - Alpha: 1
      Axes Length: 1
      Axes Radius: 0.100000001
      Class: rviz/Pose
      Color: 255; 25; 0
      Enabled: true
      Head Length: 0.300000012
      Head Radius: 0.100000001
      Name: Pose
      Shaft Length: 1
      Shaft Radius: 0.0500000007
      Shape: Arrow
      Topic: /move_base/current_goal
      Unreliable: false
      Value: true
    - Alpha: 0.400000006
      Class: rviz/Map
      Color Scheme: map
      Draw Behind: false
      Enabled: true
      Name: Map
      Topic: /map
      Unreliable: false
      Use Timestamp: false
      Value: true
    - Class: rviz/Group
      Displays:
        - Alpha: 1
          Class: rviz/Polygon
          Color: 85; 0; 255
          Enabled: true
          Name: Robot Footprint
          Topic: /move_base/local_costmap/footprint
          Unreliable: false
          Value: true
        - Alpha: 1
          Autocompute Intensity Bounds: true
          Autocompute Value Bounds:
            Max Value: 10
            Min Value: -10
            Value: true
          Axis: Z
          Channel Name: intensity
          Class: rviz/LaserScan
          Color: 255; 255; 255
          Color Transformer: Intensity
          Decay Time: 0
          Enabled: false
          Invert Rainbow: false
          Max Color: 255; 255; 255
          Max Intensity: 1
          Min Color: 0; 0; 0
          Min Intensity: 1
          Name: LaserScan
          Position Transformer: XYZ
          Queue Size: 10
          Selectable: true
          Size (Pixels): 3
          Size (m): 0.00999999978
          Style: Flat Squares
          Topic: /scan
          Unreliable: false
          Use Fixed Frame: true
          Use rainbow: true
          Value: false
        - Alpha: 1
          Arrow Length: 0.100000001
          Axes Length: 0.300000012
          Axes Radius: 0.00999999978
          Class: rviz/PoseArray
          Color: 255; 25; 0
          Enabled: false
          Head Length: 0.0700000003
          Head Radius: 0.0299999993
          Name: AMCL Particles
          Shaft Length: 0.230000004
          Shaft Radius: 0.00999999978
          Shape: Arrow (Flat)
          Topic: /particlecloud
          Unreliable: false
          Value: false
        - Class: rviz/TF
          Enabled: false
          Frame Timeout: 15
          Frames:
            All Enabled: true
          Marker Scale: 1
          Name: TF
          Show Arrows: true
          Show Axes: true
          Show Names: true
          Tree:
            {}
          Update Interval: 0
          Value: false
        - Angle Tolerance: 0.100000001
          Class: rviz/Odometry
          Covariance:
            Orientation:
              Alpha: 0.5
              Color: 255; 255; 127
              Color Style: Unique
              Frame: Local
              Offset: 1
              Scale: 1
              Value: true
            Position:
              Alpha: 0.300000012
              Color: 204; 51; 204
              Scale: 1
              Value: true
            Value: true
          Enabled: false
          Keep: 100
          Name: Odometry
          Position Tolerance: 0.100000001
          Shape:
            Alpha: 1
            Axes Length: 1
            Axes Radius: 0.100000001
            Color: 255; 25; 0
            Head Length: 0.300000012
            Head Radius: 0.100000001
            Shaft Length: 1
            Shaft Radius: 0.0500000007
            Value: Arrow
          Topic: /odom
          Unreliable: false
          Value: false
      Enabled: true
      Name: Robot
    - Class: rviz/Group
      Displays:
        - Alpha: 1
          Buffer Length: 1
          Class: rviz/Path
          Color: 25; 255; 0
          Enabled: true
          Head Diameter: 0.300000012
          Head Length: 0.200000003
          Length: 0.300000012
          Line Style: Lines
          Line Width: 0.0299999993
          Name: GlobalPath
          Offset:
            X: 0
            Y: 0
            Z: 0
          Pose Color: 255; 85; 255
          Pose Style: None
          Radius: 0.0299999993
          Shaft Diameter: 0.100000001
          Shaft Length: 0.100000001
          Topic: /move_base/GlobalPlanner/plan
          Unreliable: false
          Value: true
        - Alpha: 0.400000006
          Class: rviz/Map
          Color Scheme: costmap
          Draw Behind: false
          Enabled: true
          Name: Potential map
          Topic: /move_base/GlobalPlanner/potential
          Unreliable: false
          Use Timestamp: false
          Value: true
      Enabled: true
      Name: Global Planner
    - Class: rviz/Group
      Displays:
        - Alpha: 1
          Arrow Length: 0.300000012
          Axes Length: 0.300000012
          Axes Radius: 0.00999999978
          Class: rviz/PoseArray
          Color: 255; 25; 0
          Enabled: false
          Head Length: 0.0700000003
          Head Radius: 0.0299999993
          Name: TebPoses
          Shaft Length: 0.230000004
          Shaft Radius: 0.00999999978
          Shape: Arrow (Flat)
          Topic: /move_base/TebLocalPlannerROS/teb_poses
          Unreliable: false
          Value: false
        - Class: rviz/Marker
          Enabled: false
          Marker Topic: /move_base/TebLocalPlannerROS/teb_markers
          Name: TebMarker
          Namespaces:
            {}
          Queue Size: 100
          Value: false
        - Alpha: 1
          Buffer Length: 1
          Class: rviz/Path
          Color: 255; 0; 0
          Enabled: false
          Head Diameter: 0.300000012
          Head Length: 0.200000003
          Length: 0.300000012
          Line Style: Lines
          Line Width: 0.0299999993
          Name: LocalPath
          Offset:
            X: 0
            Y: 0
            Z: 0
          Pose Color: 255; 85; 255
          Pose Style: None
          Radius: 0.0299999993
          Shaft Diameter: 0.100000001
          Shaft Length: 0.100000001
          Topic: /move_base/TrajectoryPlannerROS/global_plan
          Unreliable: false
          Value: false
        - Alpha: 0.200000003
          Class: rviz/Map
          Color Scheme: map
          Draw Behind: false
          Enabled: true
          Name: Local costmap
          Topic: /move_base/local_costmap/costmap
          Unreliable: false
          Use Timestamp: false
          Value: true
      Enabled: true
      Name: Local Planner
    - Alpha: 1
      Buffer Length: 1
      Class: rviz/Path
      Color: 85; 85; 255
      Enabled: true
      Head Diameter: 0.300000012
      Head Length: 0.200000003
      Length: 0.300000012
      Line Style: Lines
      Line Width: 0.0299999993
      Name: MPC_Reference
      Offset:
        X: 0
        Y: 0
        Z: 0
      Pose Color: 255; 85; 255
      Pose Style: None
      Radius: 0.0299999993
      Shaft Diameter: 0.100000001
      Shaft Length: 0.100000001
      Topic: /mpc_reference
      Unreliable: false
      Value: true
    - Alpha: 1
      Buffer Length: 1
      Class: rviz/Path
      Color: 255; 0; 0
      Enabled: true
      Head Diameter: 0.300000012
      Head Length: 0.00999999978
      Length: 0.200000003
      Line Style: Lines
      Line Width: 0.0299999993
      Name: MPC_Trajectory
      Offset:
        X: 0
        Y: 0
        Z: 0
      Pose Color: 255; 85; 255
      Pose Style: Axes
      Radius: 0.00999999978
      Shaft Diameter: 0.100000001
      Shaft Length: 0.00999999978
      Topic: /mpc_trajectory
      Unreliable: false
      Value: true
    - Alpha: 1
      Autocompute Intensity Bounds: true
      Autocompute Value Bounds:
        Max Value: 10
        Min Value: -10
        Value: true
      Axis: Z
      Channel Name: intensity
      Class: rviz/LaserScan
      Color: 255; 255; 255
      Color Transformer: Intensity
      Decay Time: 0
      Enabled: true
      Invert Rainbow: false
      Max Color: 255; 255; 255
      Max Intensity: 10
      Min Color: 0; 0; 0
      Min Intensity: 10
      Name: LaserScan
      Position Transformer: XYZ
      Queue Size: 10
      Selectable: true
      Size (Pixels): 3
      Size (m): 0.00999999978
      Style: Flat Squares
      Topic: /scan
      Unreliable: false
      Use Fixed Frame: true
      Use rainbow: true
      Value: true
    - Alpha: 0.5
      Arrow Length: 0.0500000007
      Axes Length: 0.300000012
      Axes Radius: 0.00999999978
      Class: rviz/PoseArray
      Color: 255; 25; 0
      Enabled: true
      Head Length: 0.0700000003
      Head Radius: 0.0299999993
      Name: PoseArray
      Shaft Length: 0.230000004
      Shaft Radius: 0.00999999978
      Shape: Arrow (Flat)
      Topic: /particlecloud
      Unreliable: false
      Value: true
    - Class: rviz/Marker
      Enabled: true
      Marker Topic: /pure_pursuit/path_marker
      Name: Pure_Pursuit_Marker
      Namespaces:
        {}
      Queue Size: 100
      Value: true
  Enabled: true
  Global Options:
    Background Color: 0; 0; 0
    Default Light: true
    Fixed Frame: map
    Frame Rate: 30
  Name: root
  Tools:
    - Class: rviz/Interact
      Hide Inactive Objects: true
    - Class: rviz/MoveCamera
    - Class: rviz/Select
    - Class: rviz/FocusCamera
    - Class: rviz/Measure
    - Class: rviz/SetInitialPose
      Topic: /initialpose
    - Class: rviz/SetGoal
      Topic: /move_base_simple/goal
    - Class: rviz/PublishPoint
      Single click: true
      Topic: /clicked_point
  Value: true
  Views:
    Current:
      Class: rviz/Orbit
      Distance: 10.2806225
      Enable Stereo Rendering:
        Stereo Eye Separation: 0.0599999987
        Stereo Focal Distance: 1
        Swap Stereo Eyes: false
        Value: false
      Focal Point:
        X: 1.29834783
        Y: 1.0163064
        Z: -1.42960763
      Focal Shape Fixed Size: true
      Focal Shape Size: 0.0500000007
      Invert Z Axis: false
      Name: Current View
      Near Clip Distance: 0.00999999978
      Pitch: 1.56979632
      Target Frame: <Fixed Frame>
      Value: Orbit (rviz)
      Yaw: 3.14542842
    Saved: ~
Window Geometry:
  Displays:
    collapsed: false
  Height: 846
  Hide Left Dock: false
  Hide Right Dock: true
  QMainWindow State: 000000ff00000000fd00000004000000000000016a000002c4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000028000002c4000000d700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002c4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730000000028000002c4000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004bf0000003efc0100000002fb0000000800540069006d00650100000000000004bf0000030000fffffffb0000000800540069006d006501000000000000045000000000000000000000034f000002c400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
  Selection:
    collapsed: false
  Time:
    collapsed: false
  Tool Properties:
    collapsed: false
  Views:
    collapsed: true
  Width: 1215
  X: 65
  Y: 25


================================================
FILE: script/base_control.py
================================================
#!/usr/bin/python
# Copyright 2018 HyphaROS Workshop.
# Developer: HaoChih, LIN (hypha.ros@gmail.com)
#
# 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.

import rospy
import tf
import time
import sys
import math
import serial
import string
from geometry_msgs.msg import Twist
from ackermann_msgs.msg import AckermannDriveStamped
from nav_msgs.msg import Odometry

class BaseControl:
    def __init__(self):
        # Get params
        self.baseId = rospy.get_param('~base_id', 'base_footprint') # base link
        self.odomId = rospy.get_param('~odom_id', 'odom') # odom link
        self.devicePort = rospy.get_param('~port', '/dev/stm32base') # device port
        self.baudrate = float( rospy.get_param('~baudrate', '115200') ) # baudrate
        self.odom_freq = float( rospy.get_param('~odom_freq', '50') ) # hz of odom pub
        self.pwmRadian = float( rospy.get_param('~pwm_radian', '450') ) # non scaled factor pwm/radian
        self.neutralPt = float( rospy.get_param('~neutral_pt', '0') ) # steering neutral point (degree)
        self.carLength = float( rospy.get_param('~car_length', '0.1445') ) # unit: meter 
        self.wheelSep  = float( rospy.get_param('~wheel_separation', '0.156') ) # unit: meter 
        self.wheelRad  = float( rospy.get_param('~wheel_radius', '0.032') ) # unit: meter
        self.timeOut   = float( rospy.get_param('~time_out', '0.5') ) # unit: sec        
        self.VxCov = float( rospy.get_param('~vx_cov', '1.0') ) # covariance for Vx measurement
        self.VyawCov = float( rospy.get_param('~vyaw_cov', '1.0') ) # covariance for Vyaw measurement
        self.odom_topic = rospy.get_param('~odom_topic', '/odom') # topic name
        self.pub_tf = bool(rospy.get_param('~pub_tf', True)) # whether publishes TF or not
        self.debug_mode = bool(rospy.get_param('~debug_mode', False)) # true for detail info     
        self.steering_pwm_bound = float(rospy.get_param('~steering_pwm_bound', '240.0')) # unit: pwm
        self.throttle_pwm_bound = float(rospy.get_param('~throttle_pwm_bound', '128.0')) # unit: pwm, 93: 7.4v(~1.0 m/s), 131: 11.1v(~1.6 m/s)

        # Serial Communication
        try:
            self.serial = serial.Serial(self.devicePort, self.baudrate, timeout=10)
            rospy.loginfo("Flusing first 50 data readings ...")
            for x in range(0, 50):
                data = self.serial.read()
                time.sleep(0.01)

        except serial.serialutil.SerialException:
            rospy.logerr("Can not receive data from the port: "+ self.devicePort + 
            ". Did you specify the correct port ?")
            self.serial.close
            sys.exit(0) 
        rospy.loginfo("Communication success !")

        # ROS handler        
        self.sub_cmd  = rospy.Subscriber('ackermann_cmd', AckermannDriveStamped, self.ackermannCmdCB, queue_size=10)
        self.sub_safe = rospy.Subscriber('ackermann_safe', AckermannDriveStamped, self.ackermannSafeCB, queue_size=10)
        self.pub = rospy.Publisher(self.odom_topic, Odometry, queue_size=10)   
        self.timer_odom = rospy.Timer(rospy.Duration(1.0/self.odom_freq), self.timerOdomCB) 
        self.timer_cmd = rospy.Timer(rospy.Duration(0.05), self.timerCmdCB) # 10Hz
        self.tf_broadcaster = tf.TransformBroadcaster() # TF

        # variable 
        self.neutralPt_radian = self.neutralPt*math.pi/180.0
        #self.steering_pwm_bound = 240.0 # unit: pwm
        #self.throttle_pwm_bound = 93.0
        self.cmd_steering_bound = self.steering_pwm_bound/self.pwmRadian # (pwm limit)/pwmRadian, unit: radian              
        self.cmd_steering = 0.0 # radian
        self.cmd_speed_bound = 2*math.pi*self.wheelRad*100.0/1560.0*self.throttle_pwm_bound # pwm to m/s formula (hardware spec), unit: m/s
        self.max_speed_compensate = self.cmd_speed_bound*self.wheelSep*math.tan(self.cmd_steering_bound - abs(self.neutralPt_radian))/(2.0*self.carLength) # find max rear wheel difference (m/s)
        self.compensate_factor = 0.75; # since the real compensation can only be found by iteration, we use a factor to approximate 
        self.cmd_speed = 0.0 # m/s
        self.cmd_time = rospy.Time.now()
        self.safe_steering = 0.0
        self.safe_speed = 0.0
        self.safe_time = rospy.Time.now()
        self.current_time = rospy.Time.now()
        self.previous_time = rospy.Time.now()
        self.timeOut_flag = 0
        self.pose_x = 0.0 # SI
        self.pose_y = 0.0
        self.pose_yaw = 0.0

        # reading loop 
        while True:         
            reading = self.serial.read(6)
            if int(reading[0].encode('hex'),16) == 255 and int(reading[1].encode('hex'),16) == 254:
                self.data = reading
            else:
                self.serial.read(1)

    def ackermannCmdCB(self, data):
        self.cmd_steering = data.drive.steering_angle # radian
        if self.cmd_steering > (self.cmd_steering_bound - abs(self.neutralPt_radian)): # shrink the bound range by subtracting the neutral point
            self.cmd_steering = self.cmd_steering_bound - abs(self.neutralPt_radian)
        if self.cmd_steering < -(self.cmd_steering_bound - abs(self.neutralPt_radian)):
            self.cmd_steering = -(self.cmd_steering_bound - abs(self.neutralPt_radian))
        self.cmd_speed    = data.drive.speed
        if self.cmd_speed > (self.cmd_speed_bound - self.compensate_factor*self.max_speed_compensate): # decrease speed if compensation added value is higher than the bound 
            self.cmd_speed = self.cmd_speed_bound - self.compensate_factor*self.max_speed_compensate
        if self.cmd_speed < -(self.cmd_speed_bound- self.compensate_factor*self.max_speed_compensate):
            self.cmd_speed = -(self.cmd_speed_bound - self.compensate_factor*self.max_speed_compensate)
        self.cmd_time     = rospy.Time.now()
        self.timeOut_flag = 0 # reset

    # Relay: Safety commands
    def ackermannSafeCB(self, data):
        self.safe_steering = data.drive.steering_angle # radian
        if self.safe_steering > (self.cmd_steering_bound - abs(self.neutralPt_radian)): # shrink the bound range by subtracting the neutral point
            self.safe_steering = self.cmd_steering_bound - abs(self.neutralPt_radian)
        if self.safe_steering < -(self.cmd_steering_bound - abs(self.neutralPt_radian)):
            self.safe_steering = -(self.cmd_steering_bound - abs(self.neutralPt_radian))
        self.safe_speed    = data.drive.speed
        if self.safe_speed > (self.cmd_speed_bound - self.compensate_factor*self.max_speed_compensate): # decrease speed if compensation added value is higher than the bound 
            self.safe_speed = self.cmd_speed_bound - self.compensate_factor*self.max_speed_compensate
        if self.safe_speed < -(self.cmd_speed_bound- self.compensate_factor*self.max_speed_compensate):
            self.safe_speed = -(self.cmd_speed_bound - self.compensate_factor*self.max_speed_compensate)
        self.safe_time     = rospy.Time.now()
        self.timeOut_flag = 0 # reset
    
    def timerOdomCB(self, event):
        # Serial read & publish 
        try:           
            data = self.data            
            # Normal mode            
            if len(data) == 6:
                WL = -float( (int(data[2].encode('hex'),16)*256 + int(data[3].encode('hex'),16) -500)*100.0/1560.0*2*math.pi ) # unit: rad/sec
                WR = -float( (int(data[4].encode('hex'),16)*256 + int(data[5].encode('hex'),16) -500)*100.0/1560.0*2*math.pi )
            else:
                print 'Error Value! header1: ' + str(int(data[0].encode('hex'),16)) + ', header2: ' + str(int(data[1].encode('hex'),16))          

            # Twist
            VL = WL * self.wheelRad # V = omega * radius, unit: m/s
            VR = WR * self.wheelRad
            Vx = (VR+VL)/2.0
            Vyaw = Vx * math.tan(self.cmd_steering) / self.wheelSep;

            # Pose
            self.current_time = rospy.Time.now()
            dt = (self.current_time - self.previous_time).to_sec()
            self.previous_time = self.current_time
            self.pose_x   = self.pose_x   + Vx * math.cos(self.pose_yaw) * dt
            self.pose_y   = self.pose_y   + Vx * math.sin(self.pose_yaw) * dt
            self.pose_yaw = self.pose_yaw + Vyaw * dt
            pose_quat = tf.transformations.quaternion_from_euler(0,0,self.pose_yaw)
            
            # Publish Odometry
            msg = Odometry()
            msg.header.stamp = self.current_time
            msg.header.frame_id = self.odomId
            msg.child_frame_id  = self.baseId
            msg.pose.pose.position.x = self.pose_x
            msg.pose.pose.position.y = self.pose_y
            msg.pose.pose.position.z = 0.0
            msg.pose.pose.orientation.x =  pose_quat[0]
            msg.pose.pose.orientation.y =  pose_quat[1]
            msg.pose.pose.orientation.z =  pose_quat[2]
            msg.pose.pose.orientation.w =  pose_quat[3]
            msg.twist.twist.linear.x = Vx
            msg.twist.twist.angular.z = Vyaw
            for i in range(36):
                msg.twist.covariance[i] = 0
            msg.twist.covariance[0] = self.VxCov
            msg.twist.covariance[35] = self.VyawCov
            msg.pose.covariance = msg.twist.covariance
            self.pub.publish(msg)

            # TF Broadcaster
            if self.pub_tf:
                self.tf_broadcaster.sendTransform( (self.pose_x, self.pose_y, 0.0), pose_quat, self.current_time, self.baseId, self.odomId)          

            # Debug mode                      
            if self.debug_mode: 
                if len(data) == 6:
                    header_1 = int(data[0].encode('hex'),16)
                    header_2 = int(data[1].encode('hex'),16)
                    tx_1 = int(data[2].encode('hex'),16)
                    tx_2 = int(data[3].encode('hex'),16)
                    tx_3 = int(data[4].encode('hex'),16)
                    tx_4 = int(data[5].encode('hex'),16) 
                    rospy.loginfo("[Debug] header_1:%4d, header_2:%4d, tx_1:%4d, tx_2:%4d, tx_3:%4d, tx_4:%4d", header_1, header_2, tx_1, tx_2, tx_3, tx_4 )
            
        except: 
            #rospy.loginfo("Error in sensor value !") 
            pass            

    def timerCmdCB(self, event):
        # time out thresholding        
        if (rospy.Time.now() - self.cmd_time).to_sec() > self.timeOut and (rospy.Time.now() - self.safe_time).to_sec() > self.timeOut and self.timeOut_flag == 0:
            rospy.loginfo("Commands time out!")
            output = chr(255) + chr(254) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) #Vel_L, Vel_R, forward, steering, leftside 
            self.serial.write(output)
            self.timeOut_flag = 1
            return
        
        if self.timeOut_flag == 0:
            # check safety cmds
            cmd_steering = self.cmd_steering # local copy
            cmd_speed = self.cmd_speed
            if (rospy.Time.now() - self.safe_time).to_sec() <= self.timeOut:
                cmd_steering = self.safe_steering
                cmd_speed = self.safe_speed

            # compute steering cmd
            cmd_steering_adjust = cmd_steering + self.neutralPt_radian # add neutral point compensation (rad)
            steering_send = int(cmd_steering_adjust*self.pwmRadian) # convert pwm from radian
            leftside = 0 # 0: turn left, 1: turn right       
            if steering_send < 0:
                leftside = 1
                steering_send = -steering_send
            # steering limit
            if steering_send > int(self.steering_pwm_bound):
                steering_send = int(self.steering_pwm_bound)

            # compute speed cmd
            omega = cmd_speed/self.wheelRad # w = V/r*i (i is gear ratio), unit: rad/sec
            # calculate rear-wheel differential speed (ackermann effect)
            omega_left  = omega*(1 + self.wheelSep*math.tan(cmd_steering)/(2.0*self.carLength)) # w_L = omega(1+d/(2R)) R = L/tan(theta), unit: rad/s
            omega_right = omega*(1 - self.wheelSep*math.tan(cmd_steering)/(2.0*self.carLength)) # w_R = omega(1+d/(2R)) R = L/tan(theta), unit: rad/s  
            pwm_left  = abs(int(omega_left/100.0*1560.0/2.0/math.pi)) # rad/s to pwm formula (hardware spec)
            pwm_right = abs(int(omega_right/100.0*1560.0/2.0/math.pi))
            if pwm_left > int(self.throttle_pwm_bound): # [final check: shouldn't be called if everything is ok] if achieve max pwm, decrease both speed
                pwm_right = pwm_right - (pwm_left - int(self.throttle_pwm_bound))
                pwm_left = int(self.throttle_pwm_bound)
            if pwm_right > int(self.throttle_pwm_bound): # [final check: shouldn't be called if everything is ok] if achieve max pwm, decrease both speed
                pwm_left  = pwm_left - (pwm_right - int(self.throttle_pwm_bound))
                pwm_right = int(self.throttle_pwm_bound)

            forward = 0 # 0: forward, 1: reverse        
            if cmd_speed < 0.0:
                forward = 1

            #Protocal: Vel_L, Vel_R, forward, steering, leftside 
            output = chr(255) + chr(254) + chr(pwm_left) + chr(pwm_right) + chr(forward) + chr(steering_send) + chr(leftside)  
            #print 'left: ' + str(pwm_left) + ', right: ' + str(pwm_right)       
            self.serial.write(output)
        
if __name__ == "__main__":
    try:    
        # ROS Init    
        rospy.init_node('base_control', anonymous=True)

        # Constract BaseControl Obj
        rospy.loginfo("HyphaROS MiniCar Base Control ...")
        bc = BaseControl()
        rospy.spin()
    except KeyboardInterrupt:    
        bc.serial.close        
        print("Shutting down")


================================================
FILE: script/teleop_keyboard.py
================================================
#!/usr/bin/python

# This is a modified verison of turtlebot_teleop.py
# to fullfill the needs of HyphaROS MiniCar use case
# Copyright (c) 2018, HyphaROS Workshop
# 
# The original license info are as below:
# Copyright (c) 2011, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in the
#      documentation and/or other materials provided with the distribution.
#    * Neither the name of the Willow Garage, Inc. nor the names of its
#      contributors may be used to endorse or promote products derived from
#       this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.


import sys, select, termios, tty, math
import rospy
from ackermann_msgs.msg import AckermannDriveStamped

header_msg = """
Control HyphaROS Minicar!
-------------------------
Moving around:
        i     
   j    k    l
        ,     

w/x : increase/decrease throttle bounds by 10%
e/c : increase/decrease steering bounds by 10%
s   : safety mode
space key, k : force stop
anything else : keep previous commands

CTRL-C to quit
"""

# Func for getting keyboard value
def getKey(safety_mode):
    if safety_mode: # wait unit keyboard interrupt
        tty.setraw(sys.stdin.fileno())
        select.select([sys.stdin], [], [], 0)
        key = sys.stdin.read(1)
        termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
        return key
    else: # pass if not detected
        tty.setraw(sys.stdin.fileno())
        rlist, _, _ = select.select([sys.stdin], [], [], 0.1)
        if rlist:
            key = sys.stdin.read(1)
        else:
            key = ''
        termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
        return key

# Func for showing current bounds 
def showInfo(speed_bound, angle_bound):
    return "current bounds:\tspeed %s\tangle %s " % (speed_bound, angle_bound)

# Main Func
if __name__=="__main__":
    settings = termios.tcgetattr(sys.stdin)
    
    rospy.init_node('minicar_teleop')
    pub_cmd = rospy.Publisher('/ackermann_cmd', AckermannDriveStamped, queue_size=5)
    pub_safe = rospy.Publisher('/ackermann_safe', AckermannDriveStamped, queue_size=5)
    safe_mode = bool(rospy.get_param('~safety_mode', False)) # true for safety cmds 
    speed_i = float(rospy.get_param('~speed_incremental', 0.1)) # m/s
    angle_i = float(rospy.get_param('~angle_incremental', 5.0*math.pi/180.0)) # rad (=5 degree)
    speed_bound = float(rospy.get_param('~speed_bound', 2.0))
    angle_bound = float(rospy.get_param('~angle_bound', 30.0*math.pi/180.0))
    
    if safe_mode:
        print "Switched to Safety Mode !"

    moveBindings = {
            'i':(speed_i,0.0),
            'j':(0.0,angle_i),
            'l':(0.0,-angle_i),
            ',':(-speed_i,0.0),
               }

    boundBindings={
            'w':(1.1,1),
            'x':(.9,1),
            'e':(1,1.1),
            'c':(1,.9),
              }

    status = 0
    acc = 0.1
    target_speed = 0.0 # m/s
    target_angle = 0.0 # rad
    # Create AckermannDriveStamped msg object
    ackermann_msg = AckermannDriveStamped()
    #ackermann_msg.header.frame_id = 'car_id' # for future multi-cars applicaton 

    try:
        print(header_msg)
        print(showInfo(speed_bound, angle_bound))
        while(1):
            key = getKey(safe_mode)
            if key in moveBindings.keys():
                target_speed = target_speed + moveBindings[key][0]
                target_angle = target_angle + moveBindings[key][1]
            elif key in boundBindings.keys():
                speed_bound = speed_bound * boundBindings[key][0]
                angle_bound = angle_bound * boundBindings[key][1]
                print(showInfo(speed_bound, angle_bound))
                if (status == 14):
                    print(header_msg)
                status = (status + 1) % 15
            elif key == ' ' or key == 'k' :
                target_speed = 0.0
                target_angle = 0.0
            elif key == 's' : # switch safety mode
                safe_mode = not safe_mode
                if safe_mode:
                    print "Switched to Safety Mode !"
                else:
                    print "Back to Standard Mode !"
            elif key == '\x03': # cltr + C
                break

            # Command constraints
            if target_speed > speed_bound:
                target_speed = speed_bound
            if target_speed < -speed_bound:
                target_speed = -speed_bound
            if target_angle > angle_bound:
                target_angle = angle_bound
            if target_angle < -angle_bound:
                target_angle = -angle_bound

            # Publishing command
            #ackermann_msg.header.stamp = rospy.Time.now() # for future multi-cars applicaton 
            ackermann_msg.drive.speed = target_speed
            ackermann_msg.drive.steering_angle = target_angle
            if safe_mode:
                pub_safe.publish(ackermann_msg)
            else:
                pub_cmd.publish(ackermann_msg)

    except Exception as e:
        print(e)

    finally:
        ackermann_msg.drive.speed = 0
        ackermann_msg.drive.steering_angle = 0
        pub_cmd.publish(ackermann_msg)
        pub_safe.publish(ackermann_msg)

    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)




================================================
FILE: src/MPC.cpp
================================================
/*
# Copyright 2018 HyphaROS Workshop.
# Developer: HaoChih, LIN (hypha.ros@gmail.com)
#
# 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 "MPC.h"
#include <cppad/cppad.hpp>
#include <cppad/ipopt/solve.hpp>
#include <Eigen/Core>

// The program use fragments of code from
// https://github.com/udacity/CarND-MPC-Quizzes

using CppAD::AD;

// =========================================
// FG_eval class definition implementation.
// =========================================
class FG_eval 
{
    public:
        // Fitted polynomial coefficients
        Eigen::VectorXd coeffs;

        double _Lf, _dt, _ref_cte, _ref_epsi, _ref_vel; 
        double  _w_cte, _w_epsi, _w_vel, _w_delta, _w_accel, _w_delta_d, _w_accel_d;
        int _mpc_steps, _x_start, _y_start, _psi_start, _v_start, _cte_start, _epsi_start, _delta_start, _a_start;

        // Constructor
        FG_eval(Eigen::VectorXd coeffs) 
        { 
            this->coeffs = coeffs; 

            // Set default value    
            _Lf = 0.25; // distance between the front of the vehicle and its center of gravity
            _dt = 0.1;  // in sec
            _ref_cte   = 0;
            _ref_epsi  = 0;
            _ref_vel   = 1.0; // m/s
            _w_cte     = 100;
            _w_epsi    = 100;
            _w_vel     = 100;
            _w_delta   = 100;
            _w_accel   = 50;
            _w_delta_d = 0;
            _w_accel_d = 0;

            _mpc_steps   = 40;
            _x_start     = 0;
            _y_start     = _x_start + _mpc_steps;
            _psi_start   = _y_start + _mpc_steps;
            _v_start     = _psi_start + _mpc_steps;
            _cte_start   = _v_start + _mpc_steps;
            _epsi_start  = _cte_start + _mpc_steps;
            _delta_start = _epsi_start + _mpc_steps;
            _a_start     = _delta_start + _mpc_steps - 1;
        }

        // Load parameters for constraints
        void LoadParams(const std::map<string, double> &params)
        {
            _dt = params.find("DT") != params.end() ? params.at("DT") : _dt;
            _Lf = params.find("LF") != params.end() ? params.at("LF") : _Lf;
            _mpc_steps = params.find("STEPS") != params.end()    ? params.at("STEPS") : _mpc_steps;
            _ref_cte   = params.find("REF_CTE") != params.end()  ? params.at("REF_CTE") : _ref_cte;
            _ref_epsi  = params.find("REF_EPSI") != params.end() ? params.at("REF_EPSI") : _ref_epsi;
            _ref_vel   = params.find("REF_V") != params.end()    ? params.at("REF_V") : _ref_vel;
            
            _w_cte   = params.find("W_CTE") != params.end()   ? params.at("W_CTE") : _w_cte;
            _w_epsi  = params.find("W_EPSI") != params.end()  ? params.at("W_EPSI") : _w_epsi;
            _w_vel   = params.find("W_V") != params.end()     ? params.at("W_V") : _w_vel;
            _w_delta = params.find("W_DELTA") != params.end() ? params.at("W_DELTA") : _w_delta;
            _w_accel = params.find("W_A") != params.end()     ? params.at("W_A") : _w_accel;
            _w_delta_d = params.find("W_DDELTA") != params.end() ? params.at("W_DDELTA") : _w_delta_d;
            _w_accel_d = params.find("W_DA") != params.end()     ? params.at("W_DA") : _w_accel_d;

            _x_start     = 0;
            _y_start     = _x_start + _mpc_steps;
            _psi_start   = _y_start + _mpc_steps;
            _v_start     = _psi_start + _mpc_steps;
            _cte_start   = _v_start + _mpc_steps;
            _epsi_start  = _cte_start + _mpc_steps;
            _delta_start = _epsi_start + _mpc_steps;
            _a_start     = _delta_start + _mpc_steps - 1;
            
            //cout << "\n!! FG_eval Obj parameters updated !! " << _mpc_steps << endl; 
        }

        // MPC implementation (cost func & constraints)
        typedef CPPAD_TESTVECTOR(AD<double>) ADvector; 
        // fg: function that evaluates the objective and constraints using the syntax       
        void operator()(ADvector& fg, const ADvector& vars) 
        {
            
            // fg[0] for cost function
            fg[0] = 0;
            for (int i = 0; i < _mpc_steps; i++) {
              fg[0] += _w_cte * CppAD::pow(vars[_cte_start + i] - _ref_cte, 2); // cross deviation error
              fg[0] += _w_epsi * CppAD::pow(vars[_epsi_start + i] - _ref_epsi, 2); // heading error
              fg[0] += _w_vel * CppAD::pow(vars[_v_start + i] - _ref_vel, 2); // speed error
            }

            // Minimize the use of actuators.
            for (int i = 0; i < _mpc_steps - 1; i++) {
              fg[0] += _w_delta * CppAD::pow(vars[_delta_start + i], 2);
              fg[0] += _w_accel * CppAD::pow(vars[_a_start + i], 2);
            }

            // Minimize the value gap between sequential actuations.
            for (int i = 0; i < _mpc_steps - 2; i++) {
              fg[0] += _w_delta_d * CppAD::pow(vars[_delta_start + i + 1] - vars[_delta_start + i], 2);
              fg[0] += _w_accel_d * CppAD::pow(vars[_a_start + i + 1] - vars[_a_start + i], 2);
            }
            
            // fg[x] for constraints
            // Initial constraints
            fg[1 + _x_start] = vars[_x_start];
            fg[1 + _y_start] = vars[_y_start];
            fg[1 + _psi_start] = vars[_psi_start];
            fg[1 + _v_start] = vars[_v_start];
            fg[1 + _cte_start] = vars[_cte_start];
            fg[1 + _epsi_start] = vars[_epsi_start];

            // Add system dynamic model constraint
            for (int i = 0; i < _mpc_steps - 1; i++)
            {
                // The state at time t+1 .
                AD<double> x1 = vars[_x_start + i + 1];
                AD<double> y1 = vars[_y_start + i + 1];
                AD<double> psi1 = vars[_psi_start + i + 1];
                AD<double> v1 = vars[_v_start + i + 1];
                AD<double> cte1 = vars[_cte_start + i + 1];
                AD<double> epsi1 = vars[_epsi_start + i + 1];

                // The state at time t.
                AD<double> x0 = vars[_x_start + i];
                AD<double> y0 = vars[_y_start + i];
                AD<double> psi0 = vars[_psi_start + i];
                AD<double> v0 = vars[_v_start + i];
                AD<double> cte0 = vars[_cte_start + i];
                AD<double> epsi0 = vars[_epsi_start + i];

                // Only consider the actuation at time t.
                AD<double> delta0 = vars[_delta_start + i];
                AD<double> a0 = vars[_a_start + i];

                AD<double> f0 = 0.0;
                for (int i = 0; i < coeffs.size(); i++) 
                {
                    f0 += coeffs[i] * CppAD::pow(x0, i);
                }
                AD<double> psides0 = 0.0;
                for (int i = 1; i < coeffs.size(); i++) 
                {
                    psides0 += i*coeffs[i] * CppAD::pow(x0, i-1); // f'(x0)
                }
                psides0 = CppAD::atan(psides0);

                fg[2 + _x_start + i] = x1 - (x0 + v0 * CppAD::cos(psi0) * _dt);
                fg[2 + _y_start + i] = y1 - (y0 + v0 * CppAD::sin(psi0) * _dt);
                fg[2 + _psi_start + i] = psi1 - (psi0 + v0 * delta0 / _Lf * _dt);
                fg[2 + _v_start + i] = v1 - (v0 + a0 * _dt);
                fg[2 + _cte_start + i] = cte1 - ((f0 - y0) + (v0 * CppAD::sin(epsi0) * _dt));
                fg[2 + _epsi_start + i] = epsi1 - ((psi0 - psides0) + v0 * delta0 / _Lf * _dt);
            }
        }
};

// ====================================
// MPC class definition implementation.
// ====================================
MPC::MPC() 
{
    // Set default value    
    _mpc_steps = 40;
    _max_steering = 0.523; // Maximal steering radian (~30 deg)
    _max_throttle = 1.0; // Maximal throttle accel
    _bound_value  = 1.0e3; // Bound value for other variables

    _x_start     = 0;
    _y_start     = _x_start + _mpc_steps;
    _psi_start   = _y_start + _mpc_steps;
    _v_start     = _psi_start + _mpc_steps;
    _cte_start   = _v_start + _mpc_steps;
    _epsi_start  = _cte_start + _mpc_steps;
    _delta_start = _epsi_start + _mpc_steps;
    _a_start     = _delta_start + _mpc_steps - 1;

}

void MPC::LoadParams(const std::map<string, double> &params)
{
    _params = params;
    //Init parameters for MPC object
    _mpc_steps = _params.find("STEPS") != _params.end() ? _params.at("STEPS") : _mpc_steps;
    _max_steering = _params.find("MAXSTR") != _params.end() ? _params.at("MAXSTR") : _max_steering;
    _max_throttle = _params.find("MAXTHR") != _params.end() ? _params.at("MAXTHR") : _max_throttle;
    _bound_value  = _params.find("BOUND") != _params.end()  ? _params.at("BOUND") : _bound_value;
    
    _x_start     = 0;
    _y_start     = _x_start + _mpc_steps;
    _psi_start   = _y_start + _mpc_steps;
    _v_start     = _psi_start + _mpc_steps;
    _cte_start   = _v_start + _mpc_steps;
    _epsi_start  = _cte_start + _mpc_steps;
    _delta_start = _epsi_start + _mpc_steps;
    _a_start     = _delta_start + _mpc_steps - 1;

    cout << "\n!! MPC Obj parameters updated !! " << endl; 
}


vector<double> MPC::Solve(Eigen::VectorXd state, Eigen::VectorXd coeffs) 
{
    bool ok = true;
    size_t i;
    typedef CPPAD_TESTVECTOR(double) Dvector;
    const double x = state[0];
    const double y = state[1];
    const double psi = state[2];
    const double v = state[3];
    const double cte = state[4];
    const double epsi = state[5];
    // Set the number of model variables (includes both states and inputs).
    // For example: If the state is a 4 element vector, the actuators is a 2
    // element vector and there are 10 timesteps. The number of variables is:
    size_t n_vars = _mpc_steps * 6 + (_mpc_steps - 1) * 2;
    // Set the number of constraints
    size_t n_constraints = _mpc_steps * 6;

    // Initial value of the independent variables.
    // SHOULD BE 0 besides initial state.
    Dvector vars(n_vars);
    for (int i = 0; i < n_vars; i++) 
    {
        vars[i] = 0;
    }

    Dvector vars_lowerbound(n_vars);
    Dvector vars_upperbound(n_vars);
    // Set lower and upper limits for variables.
    for (int i = 0; i < _delta_start; i++) 
    {
        vars_lowerbound[i] = -_bound_value;
        vars_upperbound[i] = _bound_value;
    }
    // The upper and lower limits of delta are set to -25 and 25
    // degrees (values in radians).
    for (int i = _delta_start; i < _a_start; i++) 
    {
        vars_lowerbound[i] = -_max_steering;
        vars_upperbound[i] = _max_steering;
    }
    // Acceleration/decceleration upper and lower limits
    for (int i = _a_start; i < n_vars; i++)  
    {
        vars_lowerbound[i] = -_max_throttle;
        vars_upperbound[i] = _max_throttle;
    }


    // Lower and upper limits for the constraints
    // Should be 0 besides initial state.
    Dvector constraints_lowerbound(n_constraints);
    Dvector constraints_upperbound(n_constraints);
    for (int i = 0; i < n_constraints; i++)
    {
        constraints_lowerbound[i] = 0;
        constraints_upperbound[i] = 0;
    }
    constraints_lowerbound[_x_start] = x;
    constraints_lowerbound[_y_start] = y;
    constraints_lowerbound[_psi_start] = psi;
    constraints_lowerbound[_v_start] = v;
    constraints_lowerbound[_cte_start] = cte;
    constraints_lowerbound[_epsi_start] = epsi;
    constraints_upperbound[_x_start] = x;
    constraints_upperbound[_y_start] = y;
    constraints_upperbound[_psi_start] = psi;
    constraints_upperbound[_v_start] = v;
    constraints_upperbound[_cte_start] = cte;
    constraints_upperbound[_epsi_start] = epsi;

    // object that computes objective and constraints
    FG_eval fg_eval(coeffs);
    fg_eval.LoadParams(_params);
    // options for IPOPT solver
    std::string options;
    // Uncomment this if you'd like more print information
    options += "Integer print_level  0\n";
    // NOTE: Setting sparse to true allows the solver to take advantage
    // of sparse routines, this makes the computation MUCH FASTER. If you
    // can uncomment 1 of these and see if it makes a difference or not but
    // if you uncomment both the computation time should go up in orders of
    // magnitude.
    options += "Sparse  true        forward\n";
    options += "Sparse  true        reverse\n";
    // NOTE: Currently the solver has a maximum time limit of 0.5 seconds.
    // Change this as you see fit.
    options += "Numeric max_cpu_time          0.5\n";

    // place to return solution
    CppAD::ipopt::solve_result<Dvector> solution;

    // solve the problem
    CppAD::ipopt::solve<Dvector, FG_eval>(
      options, vars, vars_lowerbound, vars_upperbound, constraints_lowerbound,
      constraints_upperbound, fg_eval, solution);

    // Check some of the solution values
    ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;

    // Cost
    auto cost = solution.obj_value;
    //std::cout << "Cost " << cost << std::endl;
    this->mpc_x = {};
    this->mpc_y = {};
    for (int i = 0; i < _mpc_steps; i++) 
    {
        this->mpc_x.push_back(solution.x[_x_start + i]);
        this->mpc_y.push_back(solution.x[_y_start + i]);
    }
    vector<double> result;
    result.push_back(solution.x[_delta_start]);
    result.push_back(solution.x[_a_start]);
    return result;
}


================================================
FILE: src/MPC_Node.cpp
================================================
/*
# Copyright 2018 HyphaROS Workshop.
# Developer: HaoChih, LIN (hypha.ros@gmail.com)
#
# 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 <iostream>
#include <map>
#include <math.h>

#include "ros/ros.h"
#include <geometry_msgs/PoseWithCovarianceStamped.h>
#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/Twist.h>
#include <tf/transform_listener.h>
#include <tf/transform_datatypes.h>
#include <nav_msgs/Path.h>
#include <nav_msgs/Odometry.h>
#include <ackermann_msgs/AckermannDriveStamped.h>
#include <visualization_msgs/Marker.h>

#include "MPC.h"
#include <Eigen/Core>
#include <Eigen/QR>

using namespace std;
using namespace Eigen;

/********************/
/* CLASS DEFINITION */
/********************/
class MPCNode
{
    public:
        MPCNode();
        int get_thread_numbers();
        
    private:
        ros::NodeHandle _nh;
        ros::Subscriber _sub_odom, _sub_path, _sub_goal, _sub_amcl;
        ros::Publisher _pub_odompath, _pub_twist, _pub_ackermann, _pub_mpctraj;
        ros::Timer _timer1;
        tf::TransformListener _tf_listener;

        geometry_msgs::Point _goal_pos;
        nav_msgs::Odometry _odom;
        nav_msgs::Path _odom_path, _mpc_traj; 
        ackermann_msgs::AckermannDriveStamped _ackermann_msg;
        geometry_msgs::Twist _twist_msg;

        string _globalPath_topic, _goal_topic;
        string _map_frame, _odom_frame, _car_frame;

        MPC _mpc;
        map<string, double> _mpc_params;
        double _mpc_steps, _ref_cte, _ref_epsi, _ref_vel, _w_cte, _w_epsi, _w_vel, 
               _w_delta, _w_accel, _w_delta_d, _w_accel_d, _max_steering, _max_throttle, _bound_value;

        double _Lf, _dt, _steering, _throttle, _speed, _max_speed;
        double _pathLength, _goalRadius, _waypointsDist;
        int _controller_freq, _downSampling, _thread_numbers;
        bool _goal_received, _goal_reached, _path_computed, _pub_twist_flag, _debug_info, _delay_mode;

        double polyeval(Eigen::VectorXd coeffs, double x);
        Eigen::VectorXd polyfit(Eigen::VectorXd xvals, Eigen::VectorXd yvals, int order);

        void odomCB(const nav_msgs::Odometry::ConstPtr& odomMsg);
        void pathCB(const nav_msgs::Path::ConstPtr& pathMsg);
        void goalCB(const geometry_msgs::PoseStamped::ConstPtr& goalMsg);
        void amclCB(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& amclMsg);
        void controlLoopCB(const ros::TimerEvent&);

}; // end of class


MPCNode::MPCNode()
{
    //Private parameters handler
    ros::NodeHandle pn("~");

    //Parameters for control loop
    pn.param("thread_numbers", _thread_numbers, 2); // number of threads for this ROS node
    pn.param("pub_twist_cmd", _pub_twist_flag, true);
    pn.param("debug_info", _debug_info, false);
    pn.param("delay_mode", _delay_mode, true);
    pn.param("max_speed", _max_speed, 2.0); // unit: m/s
    pn.param("waypoints_dist", _waypointsDist, -1.0); // unit: m
    pn.param("path_length", _pathLength, 8.0); // unit: m
    pn.param("goal_radius", _goalRadius, 0.5); // unit: m
    pn.param("controller_freq", _controller_freq, 10);
    pn.param("vehicle_Lf", _Lf, 0.25); // distance between the front of the vehicle and its center of gravity
    _dt = double(1.0/_controller_freq); // time step duration dt in s 

    //Parameter for MPC solver
    pn.param("mpc_steps", _mpc_steps, 20.0);
    pn.param("mpc_ref_cte", _ref_cte, 0.0);
    pn.param("mpc_ref_epsi", _ref_epsi, 0.0);
    pn.param("mpc_ref_vel", _ref_vel, 1.5);
    pn.param("mpc_w_cte", _w_cte, 100.0);
    pn.param("mpc_w_epsi", _w_epsi, 100.0);
    pn.param("mpc_w_vel", _w_vel, 100.0);
    pn.param("mpc_w_delta", _w_delta, 100.0);
    pn.param("mpc_w_accel", _w_accel, 50.0);
    pn.param("mpc_w_delta_d", _w_delta_d, 0.0);
    pn.param("mpc_w_accel_d", _w_accel_d, 0.0);
    pn.param("mpc_max_steering", _max_steering, 0.523); // Maximal steering radian (~30 deg)
    pn.param("mpc_max_throttle", _max_throttle, 1.0); // Maximal throttle accel
    pn.param("mpc_bound_value", _bound_value, 1.0e3); // Bound value for other variables

    //Parameter for topics & Frame name
    pn.param<std::string>("global_path_topic", _globalPath_topic, "/move_base/TrajectoryPlannerROS/global_plan" );
    pn.param<std::string>("goal_topic", _goal_topic, "/move_base_simple/goal" );
    pn.param<std::string>("map_frame", _map_frame, "map" );
    pn.param<std::string>("odom_frame", _odom_frame, "odom");
    pn.param<std::string>("car_frame", _car_frame, "base_link" );

    //Display the parameters
    cout << "\n===== Parameters =====" << endl;
    cout << "pub_twist_cmd: "  << _pub_twist_flag << endl;
    cout << "debug_info: "  << _debug_info << endl;
    cout << "delay_mode: "  << _delay_mode << endl;
    cout << "vehicle_Lf: "  << _Lf << endl;
    cout << "frequency: "   << _dt << endl;
    cout << "mpc_steps: "   << _mpc_steps << endl;
    cout << "mpc_ref_vel: " << _ref_vel << endl;
    cout << "mpc_w_cte: "   << _w_cte << endl;
    cout << "mpc_w_epsi: "  << _w_epsi << endl;
    cout << "mpc_max_steering: "  << _max_steering << endl;

    //Publishers and Subscribers
    _sub_odom   = _nh.subscribe("/odom", 1, &MPCNode::odomCB, this);
    _sub_path   = _nh.subscribe( _globalPath_topic, 1, &MPCNode::pathCB, this);
    _sub_goal   = _nh.subscribe( _goal_topic, 1, &MPCNode::goalCB, this);
    _sub_amcl   = _nh.subscribe("/amcl_pose", 5, &MPCNode::amclCB, this);
    _pub_odompath  = _nh.advertise<nav_msgs::Path>("/mpc_reference", 1); // reference path for MPC 
    _pub_mpctraj   = _nh.advertise<nav_msgs::Path>("/mpc_trajectory", 1);// MPC trajectory output
    _pub_ackermann = _nh.advertise<ackermann_msgs::AckermannDriveStamped>("/ackermann_cmd", 1);
    if(_pub_twist_flag)
        _pub_twist = _nh.advertise<geometry_msgs::Twist>("/cmd_vel", 1); //for stage (Ackermann msg non-supported)
    
    //Timer
    _timer1 = _nh.createTimer(ros::Duration((1.0)/_controller_freq), &MPCNode::controlLoopCB, this); // 10Hz

    //Init variables
    _goal_received = false;
    _goal_reached  = false;
    _path_computed = false;
    _throttle = 0.0; 
    _steering = 0.0;
    _speed = 0.0;

    _ackermann_msg = ackermann_msgs::AckermannDriveStamped();
    _twist_msg = geometry_msgs::Twist();
    _mpc_traj = nav_msgs::Path();

    //Init parameters for MPC object
    _mpc_params["DT"] = _dt;
    _mpc_params["LF"] = _Lf;
    _mpc_params["STEPS"]    = _mpc_steps;
    _mpc_params["REF_CTE"]  = _ref_cte;
    _mpc_params["REF_EPSI"] = _ref_epsi;
    _mpc_params["REF_V"]    = _ref_vel;
    _mpc_params["W_CTE"]    = _w_cte;
    _mpc_params["W_EPSI"]   = _w_epsi;
    _mpc_params["W_V"]      = _w_vel;
    _mpc_params["W_DELTA"]  = _w_delta;
    _mpc_params["W_A"]      = _w_accel;
    _mpc_params["W_DDELTA"] = _w_delta_d;
    _mpc_params["W_DA"]     = _w_accel_d;
    _mpc_params["MAXSTR"]   = _max_steering;
    _mpc_params["MAXTHR"]   = _max_throttle;
    _mpc_params["BOUND"]    = _bound_value;
    _mpc.LoadParams(_mpc_params);

}


// Public: return _thread_numbers
int MPCNode::get_thread_numbers()
{
    return _thread_numbers;
}


// Evaluate a polynomial.
double MPCNode::polyeval(Eigen::VectorXd coeffs, double x) 
{
    double result = 0.0;
    for (int i = 0; i < coeffs.size(); i++) 
    {
        result += coeffs[i] * pow(x, i);
    }
    return result;
}


// Fit a polynomial.
// Adapted from
// https://github.com/JuliaMath/Polynomials.jl/blob/master/src/Polynomials.jl#L676-L716
Eigen::VectorXd MPCNode::polyfit(Eigen::VectorXd xvals, Eigen::VectorXd yvals, int order) 
{
    assert(xvals.size() == yvals.size());
    assert(order >= 1 && order <= xvals.size() - 1);
    Eigen::MatrixXd A(xvals.size(), order + 1);

    for (int i = 0; i < xvals.size(); i++)
        A(i, 0) = 1.0;

    for (int j = 0; j < xvals.size(); j++) 
    {
        for (int i = 0; i < order; i++) 
            A(j, i + 1) = A(j, i) * xvals(j);
    }

    auto Q = A.householderQr();
    auto result = Q.solve(yvals);
    return result;
}

// CallBack: Update odometry
void MPCNode::odomCB(const nav_msgs::Odometry::ConstPtr& odomMsg)
{
    _odom = *odomMsg;
}

// CallBack: Update path waypoints (conversion to odom frame)
void MPCNode::pathCB(const nav_msgs::Path::ConstPtr& pathMsg)
{
    if(_goal_received && !_goal_reached)
    {    
        nav_msgs::Path odom_path = nav_msgs::Path();
        try
        {
            //find waypoints distance
            if(_waypointsDist <=0.0)
            {        
                double dx = pathMsg->poses[1].pose.position.x - pathMsg->poses[0].pose.position.x;
                double dy = pathMsg->poses[1].pose.position.y - pathMsg->poses[0].pose.position.y;
                _waypointsDist = sqrt(dx*dx + dy*dy);
                _downSampling = int(_pathLength/10.0/_waypointsDist);
            }
            
            double total_length = 0.0;
            int sampling = _downSampling;
            // Cut and downsampling the path
            for(int i =0; i< pathMsg->poses.size(); i++)
            {
                if(total_length > _pathLength)
                    break;

                if(sampling == _downSampling)
                {   
                    geometry_msgs::PoseStamped tempPose;
                    _tf_listener.transformPose(_odom_frame, ros::Time(0) , pathMsg->poses[i], _map_frame, tempPose);                     
                    odom_path.poses.push_back(tempPose);  
                    sampling = 0;
                }
                total_length = total_length + _waypointsDist; 
                sampling = sampling + 1;  
            }
           
            if(odom_path.poses.size() >= 6 )
            {
                _odom_path = odom_path; // Path waypoints in odom frame
                _path_computed = true;
                // publish odom path
                odom_path.header.frame_id = _odom_frame;
                odom_path.header.stamp = ros::Time::now();
                _pub_odompath.publish(odom_path);
            }
            //DEBUG            
            //cout << endl << "N: " << odom_path.poses.size() << endl <<  "Car path[0]: " << odom_path.poses[0] << ", path[N]: " << _odom_path.poses[_odom_path.poses.size()-1] << endl;


        }
        catch(tf::TransformException &ex)
        {
            ROS_ERROR("%s",ex.what());
            ros::Duration(1.0).sleep();
        }
    }
}

// CallBack: Update goal status
void MPCNode::goalCB(const geometry_msgs::PoseStamped::ConstPtr& goalMsg)
{
    _goal_pos = goalMsg->pose.position;
    _goal_received = true;
    _goal_reached = false;
    ROS_INFO("Goal Received !");
}


// Callback: Check if the car is inside the goal area or not 
void MPCNode::amclCB(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& amclMsg)
{

    if(_goal_received)
    {
        double car2goal_x = _goal_pos.x - amclMsg->pose.pose.position.x;
        double car2goal_y = _goal_pos.y - amclMsg->pose.pose.position.y;
        double dist2goal = sqrt(car2goal_x*car2goal_x + car2goal_y*car2goal_y);
        if(dist2goal < _goalRadius)
        {
            _goal_reached = true;
            _goal_received = false;
            _path_computed = false;
            ROS_INFO("Goal Reached !");
        }
    }
}


// Timer: Control Loop (closed loop nonlinear MPC)
void MPCNode::controlLoopCB(const ros::TimerEvent&)
{      
    if(_goal_received && !_goal_reached && _path_computed ) //received goal & goal not reached    
    {    
        nav_msgs::Odometry odom = _odom; 
        nav_msgs::Path odom_path = _odom_path;   

        // Update system states: X=[x, y, psi, v]
        const double px = odom.pose.pose.position.x; //pose: odom frame
        const double py = odom.pose.pose.position.y;
        tf::Pose pose;
        tf::poseMsgToTF(odom.pose.pose, pose);
        const double psi = tf::getYaw(pose.getRotation());
        const double v = odom.twist.twist.linear.x; //twist: body fixed frame
        // Update system inputs: U=[steering, throttle]
        const double steering = _steering;  // radian
        const double throttle = _throttle; // accel: >0; brake: <0
        const double dt = _dt;
        const double Lf = _Lf;

        // Waypoints related parameters
        const int N = odom_path.poses.size(); // Number of waypoints
        const double cospsi = cos(psi);
        const double sinpsi = sin(psi);

        // Convert to the vehicle coordinate system
        VectorXd x_veh(N);
        VectorXd y_veh(N);
        for(int i = 0; i < N; i++) 
        {
            const double dx = odom_path.poses[i].pose.position.x - px;
            const double dy = odom_path.poses[i].pose.position.y - py;
            x_veh[i] = dx * cospsi + dy * sinpsi;
            y_veh[i] = dy * cospsi - dx * sinpsi;
        }
        
        // Fit waypoints
        auto coeffs = polyfit(x_veh, y_veh, 3); 

        const double cte  = polyeval(coeffs, 0.0);
        const double epsi = atan(coeffs[1]);
        VectorXd state(6);
        if(_delay_mode)
        {
            // Kinematic model is used to predict vehicle state at the actual
            // moment of control (current time + delay dt)
            const double px_act = v * dt;
            const double py_act = 0;
            const double psi_act = v * steering * dt / Lf;
            const double v_act = v + throttle * dt;
            const double cte_act = cte + v * sin(epsi) * dt;
            const double epsi_act = -epsi + psi_act;             
            state << px_act, py_act, psi_act, v_act, cte_act, epsi_act;
        }
        else
        {
            state << 0, 0, 0, v, cte, epsi;
        }
        
        // Solve MPC Problem
        vector<double> mpc_results = _mpc.Solve(state, coeffs);
              
        // MPC result (all described in car frame)        
        _steering = mpc_results[0]; // radian
        _throttle = mpc_results[1]; // acceleration
        _speed = v + _throttle*dt;  // speed
        if (_speed >= _max_speed)
            _speed = _max_speed;
        if(_speed <= 0.0)
            _speed = 0.0;

        if(_debug_info)
        {
            cout << "\n\nDEBUG" << endl;
            cout << "psi: " << psi << endl;
            cout << "V: " << v << endl;
            //cout << "odom_path: \n" << odom_path << endl;
            //cout << "x_points: \n" << x_veh << endl;
            //cout << "y_points: \n" << y_veh << endl;
            cout << "coeffs: \n" << coeffs << endl;
            cout << "_steering: \n" << _steering << endl;
            cout << "_throttle: \n" << _throttle << endl;
            cout << "_speed: \n" << _speed << endl;
        }

        // Display the MPC predicted trajectory
        _mpc_traj = nav_msgs::Path();
        _mpc_traj.header.frame_id = _car_frame; // points in car coordinate        
        _mpc_traj.header.stamp = ros::Time::now();
        for(int i=0; i<_mpc.mpc_x.size(); i++)
        {
            geometry_msgs::PoseStamped tempPose;
            tempPose.header = _mpc_traj.header;
            tempPose.pose.position.x = _mpc.mpc_x[i];
            tempPose.pose.position.y = _mpc.mpc_y[i];
            tempPose.pose.orientation.w = 1.0;
            _mpc_traj.poses.push_back(tempPose); 
        }     
        // publish the mpc trajectory
        _pub_mpctraj.publish(_mpc_traj);

    }
    else
    {
        _steering = 0.0;
        _throttle = 0.0;
        _speed = 0.0;
        if(_goal_reached && _goal_received)
            cout << "Goal Reached !" << endl;
    }

    // publish cmd 
    _ackermann_msg.header.frame_id = _car_frame;
    _ackermann_msg.header.stamp = ros::Time::now();
    _ackermann_msg.drive.steering_angle = _steering;
    _ackermann_msg.drive.speed = _speed;
    _ackermann_msg.drive.acceleration = _throttle;
    _pub_ackermann.publish(_ackermann_msg);        

    if(_pub_twist_flag)
    {
        _twist_msg.linear.x  = _speed; 
        _twist_msg.angular.z = _steering;
        _pub_twist.publish(_twist_msg);
    }
    
}


/*****************/
/* MAIN FUNCTION */
/*****************/
int main(int argc, char **argv)
{
    //Initiate ROS
    ros::init(argc, argv, "MPC_Node");
    MPCNode mpc_node;

    ROS_INFO("Waiting for global path msgs ~");
    ros::AsyncSpinner spinner(mpc_node.get_thread_numbers()); // Use multi threads
    spinner.start();
    ros::waitForShutdown();
    return 0;
}



================================================
FILE: src/Pure_Pursuit.cpp
================================================
/*
# Copyright 2018 HyphaROS Workshop.
# Latest Modifier: HaoChih, LIN (hypha.ros@gmail.com)
# Original Author: ChanYuan KUO & YoRu LU
#
# 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 <iostream>
#include "ros/ros.h"
#include <geometry_msgs/PoseWithCovarianceStamped.h>
#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/Twist.h>
#include <tf/transform_listener.h>
#include <tf/transform_datatypes.h>
#include <nav_msgs/Path.h>
#include <nav_msgs/Odometry.h>
#include <ackermann_msgs/AckermannDriveStamped.h>
#include <visualization_msgs/Marker.h>

/********************/
/* CLASS DEFINITION */
/********************/
class PurePursuit
{
    public:
        PurePursuit();
        void initMarker();
        bool isForwardWayPt(const geometry_msgs::Point& wayPt, const geometry_msgs::Pose& carPose);
        bool isWayPtAwayFromLfwDist(const geometry_msgs::Point& wayPt, const geometry_msgs::Point& car_pos);
        double getYawFromPose(const geometry_msgs::Pose& carPose);        
        double getEta(const geometry_msgs::Pose& carPose);
        double getCar2GoalDist();
        double getSteering(double eta);
        geometry_msgs::Point get_odom_car2WayPtVec(const geometry_msgs::Pose& carPose);

    private:
        ros::NodeHandle n_;
        ros::Subscriber odom_sub, path_sub, goal_sub, amcl_sub;
        ros::Publisher ackermann_pub, cmdvel_pub, marker_pub;
        ros::Timer timer1, timer2;
        tf::TransformListener tf_listener;

        visualization_msgs::Marker points, line_strip, goal_circle;
        geometry_msgs::Point odom_goal_pos, goal_pos;
        geometry_msgs::Twist cmd_vel;
        ackermann_msgs::AckermannDriveStamped ackermann_cmd;
        nav_msgs::Odometry odom;
        nav_msgs::Path map_path, odom_path;

        double L, Lfw, Vcmd, lfw, steering, velocity;
        double steering_gain, base_angle, goal_radius, speed_incremental;
        int controller_freq;
        bool foundForwardPt, goal_received, goal_reached, cmd_vel_mode, debug_mode, smooth_accel;

        void odomCB(const nav_msgs::Odometry::ConstPtr& odomMsg);
        void pathCB(const nav_msgs::Path::ConstPtr& pathMsg);
        void goalCB(const geometry_msgs::PoseStamped::ConstPtr& goalMsg);
        void amclCB(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& amclMsg);
        void controlLoopCB(const ros::TimerEvent&);

}; // end of class


PurePursuit::PurePursuit()
{
    //Private parameters handler
    ros::NodeHandle pn("~");

    //Car parameter
    pn.param("L", L, 0.26); // length of car
    pn.param("Vcmd", Vcmd, 1.0);// reference speed (m/s)
    pn.param("Lfw", Lfw, 3.0); // forward look ahead distance (m)
    pn.param("lfw", lfw, 0.13); // distance between front the center of car

    //Controller parameter
    pn.param("controller_freq", controller_freq, 20);
    pn.param("steering_gain", steering_gain, 1.0);
    pn.param("goal_radius", goal_radius, 0.5); // goal radius (m)
    pn.param("base_angle", base_angle, 0.0); // neutral point of servo (rad) 
    pn.param("cmd_vel_mode", cmd_vel_mode, false); // whether or not publishing cmd_vel
    pn.param("debug_mode", debug_mode, false); // debug mode
    pn.param("smooth_accel", smooth_accel, true); // smooth the acceleration of car
    pn.param("speed_incremental", speed_incremental, 0.5); // speed incremental value (discrete acceleraton), unit: m/s

    //Publishers and Subscribers
    odom_sub = n_.subscribe("/pure_pursuit/odom", 1, &PurePursuit::odomCB, this);
    path_sub = n_.subscribe("/pure_pursuit/global_planner", 1, &PurePursuit::pathCB, this);
    goal_sub = n_.subscribe("/pure_pursuit/goal", 1, &PurePursuit::goalCB, this);
    amcl_sub = n_.subscribe("/amcl_pose", 5, &PurePursuit::amclCB, this);
    marker_pub = n_.advertise<visualization_msgs::Marker>("/pure_pursuit/path_marker", 10);
    ackermann_pub = n_.advertise<ackermann_msgs::AckermannDriveStamped>("/pure_pursuit/ackermann_cmd", 1);
    if(cmd_vel_mode) cmdvel_pub = n_.advertise<geometry_msgs::Twist>("/pure_pursuit/cmd_vel", 1);    

    //Timer
    timer1 = n_.createTimer(ros::Duration((1.0)/controller_freq), &PurePursuit::controlLoopCB, this); // Duration(0.05) -> 20Hz


    //Init variables
    foundForwardPt = false;
    goal_received = false;
    goal_reached = false;
    velocity = 0.0;
    steering = base_angle;

    //Show info
    ROS_INFO("[param] base_angle: %f", base_angle);
    ROS_INFO("[param] Vcmd: %f", Vcmd);
    ROS_INFO("[param] Lfw: %f", Lfw);

    //Visualization Marker Settings
    initMarker();

    cmd_vel = geometry_msgs::Twist();
    ackermann_cmd = ackermann_msgs::AckermannDriveStamped();
}



void PurePursuit::initMarker()
{
    points.header.frame_id = line_strip.header.frame_id = goal_circle.header.frame_id = "odom";
    points.ns = line_strip.ns = goal_circle.ns = "Markers";
    points.action = line_strip.action = goal_circle.action = visualization_msgs::Marker::ADD;
    points.pose.orientation.w = line_strip.pose.orientation.w = goal_circle.pose.orientation.w = 1.0;
    points.id = 0;
    line_strip.id = 1;
    goal_circle.id = 2;

    points.type = visualization_msgs::Marker::POINTS;
    line_strip.type = visualization_msgs::Marker::LINE_STRIP;
    goal_circle.type = visualization_msgs::Marker::CYLINDER;
    // POINTS markers use x and y scale for width/height respectively
    points.scale.x = 0.2;
    points.scale.y = 0.2;

    //LINE_STRIP markers use only the x component of scale, for the line width
    line_strip.scale.x = 0.1;

    goal_circle.scale.x = goal_radius;
    goal_circle.scale.y = goal_radius;
    goal_circle.scale.z = 0.1;

    // Points are green
    points.color.g = 1.0f;
    points.color.a = 1.0;

    // Line strip is blue
    line_strip.color.b = 1.0;
    line_strip.color.a = 1.0;

    //goal_circle is yellow
    goal_circle.color.r = 1.0;
    goal_circle.color.g = 1.0;
    goal_circle.color.b = 0.0;
    goal_circle.color.a = 0.5;
}


void PurePursuit::odomCB(const nav_msgs::Odometry::ConstPtr& odomMsg)
{
    this->odom = *odomMsg;
}


void PurePursuit::pathCB(const nav_msgs::Path::ConstPtr& pathMsg)
{
    this->map_path = *pathMsg;
}


void PurePursuit::goalCB(const geometry_msgs::PoseStamped::ConstPtr& goalMsg)
{
    this->goal_pos = goalMsg->pose.position;    
    try
    {
        geometry_msgs::PoseStamped odom_goal;
        tf_listener.transformPose("odom", ros::Time(0) , *goalMsg, "map" ,odom_goal);
        odom_goal_pos = odom_goal.pose.position;
        goal_received = true;
        goal_reached = false;

        /*Draw Goal on RVIZ*/
        goal_circle.pose = odom_goal.pose;
        marker_pub.publish(goal_circle);
    }
    catch(tf::TransformException &ex)
    {
        ROS_ERROR("%s",ex.what());
        ros::Duration(1.0).sleep();
    }
}

double PurePursuit::getYawFromPose(const geometry_msgs::Pose& carPose)
{
    float x = carPose.orientation.x;
    float y = carPose.orientation.y;
    float z = carPose.orientation.z;
    float w = carPose.orientation.w;

    double tmp,yaw;
    tf::Quaternion q(x,y,z,w);
    tf::Matrix3x3 quaternion(q);
    quaternion.getRPY(tmp,tmp, yaw);

    return yaw;
}

bool PurePursuit::isForwardWayPt(const geometry_msgs::Point& wayPt, const geometry_msgs::Pose& carPose)
{
    float car2wayPt_x = wayPt.x - carPose.position.x;
    float car2wayPt_y = wayPt.y - carPose.position.y;
    double car_theta = getYawFromPose(carPose);

    float car_car2wayPt_x = cos(car_theta)*car2wayPt_x + sin(car_theta)*car2wayPt_y;
    float car_car2wayPt_y = -sin(car_theta)*car2wayPt_x + cos(car_theta)*car2wayPt_y;

    if(car_car2wayPt_x >0) /*is Forward WayPt*/
        return true;
    else
        return false;
}


bool PurePursuit::isWayPtAwayFromLfwDist(const geometry_msgs::Point& wayPt, const geometry_msgs::Point& car_pos)
{
    double dx = wayPt.x - car_pos.x;
    double dy = wayPt.y - car_pos.y;
    double dist = sqrt(dx*dx + dy*dy);

    if(dist < Lfw)
        return false;
    else if(dist >= Lfw)
        return true;
}

geometry_msgs::Point PurePursuit::get_odom_car2WayPtVec(const geometry_msgs::Pose& carPose)
{
    geometry_msgs::Point carPose_pos = carPose.position;
    double carPose_yaw = getYawFromPose(carPose);
    geometry_msgs::Point forwardPt;
    geometry_msgs::Point odom_car2WayPtVec;
    foundForwardPt = false;

    if(!goal_reached){
        for(int i =0; i< map_path.poses.size(); i++)
        {
            geometry_msgs::PoseStamped map_path_pose = map_path.poses[i];
            geometry_msgs::PoseStamped odom_path_pose;

            try
            {
                tf_listener.transformPose("odom", ros::Time(0) , map_path_pose, "map" ,odom_path_pose);
                geometry_msgs::Point odom_path_wayPt = odom_path_pose.pose.position;
                bool _isForwardWayPt = isForwardWayPt(odom_path_wayPt,carPose);

                if(_isForwardWayPt)
                {
                    bool _isWayPtAwayFromLfwDist = isWayPtAwayFromLfwDist(odom_path_wayPt,carPose_pos);
                    if(_isWayPtAwayFromLfwDist)
                    {
                        forwardPt = odom_path_wayPt;
                        foundForwardPt = true;
                        break;
                    }
                }
            }
            catch(tf::TransformException &ex)
            {
                ROS_ERROR("%s",ex.what());
                ros::Duration(1.0).sleep();
            }
        }
        
    }
    else if(goal_reached)
    {
        forwardPt = odom_goal_pos;
        foundForwardPt = false;
        //ROS_INFO("goal REACHED!");
    }

    /*Visualized Target Point on RVIZ*/
    /*Clear former target point Marker*/
    points.points.clear();
    line_strip.points.clear();
    
    if(foundForwardPt && !goal_reached)
    {
        points.points.push_back(carPose_pos);
        points.points.push_back(forwardPt);
        line_strip.points.push_back(carPose_pos);
        line_strip.points.push_back(forwardPt);
    }

    marker_pub.publish(points);
    marker_pub.publish(line_strip);
    
    odom_car2WayPtVec.x = cos(carPose_yaw)*(forwardPt.x - carPose_pos.x) + sin(carPose_yaw)*(forwardPt.y - carPose_pos.y);
    odom_car2WayPtVec.y = -sin(carPose_yaw)*(forwardPt.x - carPose_pos.x) + cos(carPose_yaw)*(forwardPt.y - carPose_pos.y);
    return odom_car2WayPtVec;
}


double PurePursuit::getEta(const geometry_msgs::Pose& carPose)
{
    geometry_msgs::Point odom_car2WayPtVec = get_odom_car2WayPtVec(carPose);
    return atan2(odom_car2WayPtVec.y,odom_car2WayPtVec.x);
}


double PurePursuit::getCar2GoalDist()
{
    geometry_msgs::Point car_pose = this->odom.pose.pose.position;
    double car2goal_x = this->odom_goal_pos.x - car_pose.x;
    double car2goal_y = this->odom_goal_pos.y - car_pose.y;

    return sqrt(car2goal_x*car2goal_x + car2goal_y*car2goal_y);
}


double PurePursuit::getSteering(double eta)
{
    return atan2((this->L*sin(eta)),(this->Lfw/2 + this->lfw*cos(eta)));
}


void PurePursuit::amclCB(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& amclMsg)
{

    if(this->goal_received)
    {
        double car2goal_x = this->goal_pos.x - amclMsg->pose.pose.position.x;
        double car2goal_y = this->goal_pos.y - amclMsg->pose.pose.position.y;
        double dist2goal = sqrt(car2goal_x*car2goal_x + car2goal_y*car2goal_y);
        if(dist2goal < this->goal_radius)
        {
            this->goal_reached = true;
            this->goal_received = false;
            ROS_INFO("Goal Reached !");
        }
    }
}


void PurePursuit::controlLoopCB(const ros::TimerEvent&)
{

    geometry_msgs::Pose carPose = this->odom.pose.pose;
    geometry_msgs::Twist carVel = this->odom.twist.twist;

    if(this->goal_received)
    {
        /*Estimate Steering Angle*/
        double eta = getEta(carPose);  
        if(foundForwardPt)
        {
            this->steering = this->base_angle + getSteering(eta)*this->steering_gain;
            /*Estimate Gas Input*/
            if(!this->goal_reached)
            {
                if(this->smooth_accel) 
                    this->velocity = std::min(this->velocity + this->speed_incremental, this->Vcmd);
                else
                    this->velocity = this->Vcmd;
                if(debug_mode) ROS_INFO("Velocity = %.2f, Steering = %.2f", this->velocity, this->steering);
            }
        }
    }

    if(this->goal_reached)
    {
        this->velocity = 0.0;
        this->steering = this->base_angle;
    }
    
    this->ackermann_cmd.drive.steering_angle = this->steering;
    this->ackermann_cmd.drive.speed = this->velocity;
    this->ackermann_pub.publish(this->ackermann_cmd);

    if(this->cmd_vel_mode)
    {
        this->cmd_vel.linear.x = this->velocity;
        this->cmd_vel.angular.z = this->steering;
        this->cmdvel_pub.publish(this->cmd_vel);
    }   
}


/*****************/
/* MAIN FUNCTION */
/*****************/
int main(int argc, char **argv)
{
    //Initiate ROS
    ros::init(argc, argv, "PurePursuit");
    PurePursuit controller;
    ros::AsyncSpinner spinner(2); // Use multi threads
    spinner.start();
    ros::waitForShutdown();
    return 0;
}
Download .txt
gitextract_x9qft2fw/

├── CMakeLists.txt
├── LICENSE
├── document/
│   ├── ipopt_install/
│   │   ├── ipopt_arm_install_tutorial.md
│   │   └── ipopt_x86_install_tutorial.md
│   └── udev/
│       ├── stm32base.rules
│       └── udev_install.sh
├── example/
│   ├── CppAD_Ipopt.cpp
│   └── CppAD_started.cpp
├── include/
│   └── MPC.h
├── launch/
│   ├── Desktop/
│   │   ├── HyphaROS_Desktop_Mapping.launch
│   │   └── HyphaROS_Desktop_Racing.launch
│   ├── HyphaROS_MiniCar_Mapping.launch
│   ├── HyphaROS_MiniCar_Racing.launch
│   ├── Simulation/
│   │   ├── HyphaROS_Simulation_Stage.launch
│   │   ├── maps/
│   │   │   └── maze.yaml
│   │   ├── params/
│   │   │   ├── amcl_params.yaml
│   │   │   ├── carlike/
│   │   │   │   ├── costmap_common_params.yaml
│   │   │   │   ├── global_costmap_params.yaml
│   │   │   │   ├── global_planner.yaml
│   │   │   │   ├── local_costmap_params.yaml
│   │   │   │   └── teb_local_planner_params.yaml
│   │   │   ├── mpc_params.yaml
│   │   │   ├── pure_pursuit_params.yaml
│   │   │   └── rviz_navigation.rviz
│   │   └── stage/
│   │       ├── maze_carlike.world
│   │       └── robots/
│   │           └── carlike_robot.inc
│   ├── includes/
│   │   ├── HyphaROS_MiniCar_Drivers.launch.xml
│   │   ├── amcl.launch.xml
│   │   ├── gmapping.launch.xml
│   │   ├── hector_slam.launch.xml
│   │   ├── karto_slam.launch.xml
│   │   ├── minicar_base.launch.xml
│   │   ├── minicar_tf.launch.xml
│   │   ├── mrpt_icp.launch.xml
│   │   └── ydlidar.launch.xml
│   └── params/
│       ├── costmap_common_params.yaml
│       ├── global_costmap_params.yaml
│       ├── global_planner.yaml
│       ├── local_costmap_params.yaml
│       ├── mpc/
│       │   └── mpc_params.yaml
│       ├── pure_pursuit/
│       │   └── pure_pursuit_params.yaml
│       └── teb/
│           └── teb_local_planner_params.yaml
├── map/
│   ├── map_amcl.pgm
│   ├── map_amcl.yaml
│   ├── map_nav.pgm
│   └── map_nav.yaml
├── package.xml
├── readme.md
├── rviz/
│   ├── hypharos_minicar_mapping.rviz
│   └── hypharos_minicar_racing.rviz
├── script/
│   ├── base_control.py
│   └── teleop_keyboard.py
└── src/
    ├── MPC.cpp
    ├── MPC_Node.cpp
    └── Pure_Pursuit.cpp
Download .txt
SYMBOL INDEX (21 symbols across 8 files)

FILE: example/CppAD_Ipopt.cpp
  class FG_eval (line 63) | class FG_eval {
  function get_started (line 88) | bool get_started(void)
  function main (line 168) | int main(void)

FILE: example/CppAD_started.cpp
  function Type (line 89) | Type Poly(const std::vector<double> &a, const Type &x)
  function main (line 102) | int main(void)

FILE: include/MPC.h
  function class (line 27) | class MPC

FILE: script/base_control.py
  class BaseControl (line 28) | class BaseControl:
    method __init__ (line 29) | def __init__(self):
    method ackermannCmdCB (line 102) | def ackermannCmdCB(self, data):
    method ackermannSafeCB (line 117) | def ackermannSafeCB(self, data):
    method timerOdomCB (line 131) | def timerOdomCB(self, event):
    method timerCmdCB (line 197) | def timerCmdCB(self, event):

FILE: script/teleop_keyboard.py
  function getKey (line 58) | def getKey(safety_mode):
  function showInfo (line 76) | def showInfo(speed_bound, angle_bound):

FILE: src/MPC.cpp
  class FG_eval (line 31) | class FG_eval
    method FG_eval (line 42) | FG_eval(Eigen::VectorXd coeffs)
    method LoadParams (line 72) | void LoadParams(const std::map<string, double> &params)

FILE: src/MPC_Node.cpp
  class MPCNode (line 43) | class MPCNode
  function main (line 458) | int main(int argc, char **argv)

FILE: src/Pure_Pursuit.cpp
  class PurePursuit (line 34) | class PurePursuit
  function main (line 403) | int main(int argc, char **argv)
Condensed preview — 55 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (202K chars).
[
  {
    "path": "CMakeLists.txt",
    "chars": 1672,
    "preview": "cmake_minimum_required(VERSION 3.5)\nproject(hypharos_minicar)\n\n## Compile as C++11, supported in ROS Kinetic and newer\na"
  },
  {
    "path": "LICENSE",
    "chars": 11353,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "document/ipopt_install/ipopt_arm_install_tutorial.md",
    "chars": 1021,
    "preview": "# How to install Ipopt on arm environment  \n\n## Inatall CPPAD & Fortran   \n$ sudo apt-get install cppad gfortran  \n\n## G"
  },
  {
    "path": "document/ipopt_install/ipopt_x86_install_tutorial.md",
    "chars": 767,
    "preview": "# How to install Ipopt on x86 environment  \n\n## Inatall CPPAD & Fortran  \n$ sudo apt-get install cppad gfortran  \n    \n#"
  },
  {
    "path": "document/udev/stm32base.rules",
    "chars": 170,
    "preview": "# set the udev rule , make the device_port be fixed by arduino\n#\nKERNEL==\"ttyUSB*\", ATTRS{idVendor}==\"1a86\", ATTRS{idPro"
  },
  {
    "path": "document/udev/udev_install.sh",
    "chars": 1014,
    "preview": "#!/bin/bash\necho \"=========== HyphaROS ===========\"\necho \"Automatically install udev rules\"\n\n# YDLidar\n#echo  'KERNEL==\""
  },
  {
    "path": "example/CppAD_Ipopt.cpp",
    "chars": 4753,
    "preview": "// $Id$\n/* --------------------------------------------------------------------------\nCppAD: C++ Algorithmic Differentia"
  },
  {
    "path": "example/CppAD_started.cpp",
    "chars": 4706,
    "preview": "/* --------------------------------------------------------------------------\nCppAD: C++ Algorithmic Differentiation: Co"
  },
  {
    "path": "include/MPC.h",
    "chars": 1415,
    "preview": "/*\n# Copyright 2018 HyphaROS Workshop.\n# Developer: HaoChih, LIN (hypha.ros@gmail.com)\n#\n# Licensed under the Apache Lic"
  },
  {
    "path": "launch/Desktop/HyphaROS_Desktop_Mapping.launch",
    "chars": 477,
    "preview": "<?xml version=\"1.0\"?>\n\n<launch>\n    <!-- Launch arguments -->\n    <arg name=\"use_rviz\"  default=\"true\" />\n    <arg name="
  },
  {
    "path": "launch/Desktop/HyphaROS_Desktop_Racing.launch",
    "chars": 536,
    "preview": "<?xml version=\"1.0\"?>\n\n<launch>\n    <!-- Launch arguments -->\n    <arg name=\"use_rviz\"  default=\"true\" />\n    <arg name="
  },
  {
    "path": "launch/HyphaROS_MiniCar_Mapping.launch",
    "chars": 2018,
    "preview": "<?xml version=\"1.0\"?>\n\n<launch>\n    <!-- launch file arguments -->\n    <arg name=\"slam_type\"   default=\"gmapping\" doc=\"o"
  },
  {
    "path": "launch/HyphaROS_MiniCar_Racing.launch",
    "chars": 4358,
    "preview": "<?xml version=\"1.0\"?>\n\n<launch>\n    <!-- ********************** -->\n    <!-- Launch file parameters -->\n    <!-- *******"
  },
  {
    "path": "launch/Simulation/HyphaROS_Simulation_Stage.launch",
    "chars": 3768,
    "preview": "<launch>\n\n    <!--  ************** Global Parameters ***************  -->\n    <param name=\"/use_sim_time\" value=\"true\"/>"
  },
  {
    "path": "launch/Simulation/maps/maze.yaml",
    "chars": 108,
    "preview": "image: maze.png\nresolution: 0.05\norigin: [0.0, 0.0, 0.0]\nnegate: 0\noccupied_thresh: 0.65\nfree_thresh: 0.196\n"
  },
  {
    "path": "launch/Simulation/params/amcl_params.yaml",
    "chars": 832,
    "preview": "use_map_topic: true\n\nodom_frame_id: \"odom\"\nbase_frame_id: \"base_footprint\"\nglobal_frame_id: \"/map\"\n\n## Publish scans fro"
  },
  {
    "path": "launch/Simulation/params/carlike/costmap_common_params.yaml",
    "chars": 1024,
    "preview": "\n#---standard pioneer footprint---\n#---(in meters)---\n#footprint: [ [0.254, -0.0508], [0.1778, -0.0508], [0.1778, -0.177"
  },
  {
    "path": "launch/Simulation/params/carlike/global_costmap_params.yaml",
    "chars": 490,
    "preview": "global_costmap:\n    global_frame: /map\n    robot_base_frame: base_link\n    update_frequency: 1.0\n    publish_frequency: "
  },
  {
    "path": "launch/Simulation/params/carlike/global_planner.yaml",
    "chars": 63,
    "preview": "GlobalPlanner:\n    use_dijkstra: true\n    use_grid_path: false\n"
  },
  {
    "path": "launch/Simulation/params/carlike/local_costmap_params.yaml",
    "chars": 380,
    "preview": "local_costmap:\n  global_frame: /map\n  robot_base_frame: base_link\n  update_frequency: 10.0\n  publish_frequency: 10.0\n  s"
  },
  {
    "path": "launch/Simulation/params/carlike/teb_local_planner_params.yaml",
    "chars": 2857,
    "preview": "TebLocalPlannerROS:\n\n odom_topic: odom\n    \n # Trajectory\n  \n teb_autosize: True\n dt_ref: 0.3\n dt_hysteresis: 0.1\n globa"
  },
  {
    "path": "launch/Simulation/params/mpc_params.yaml",
    "chars": 725,
    "preview": "# Parameters for control loop\npub_twist_cmd: true\ndebug_info: false\ndelay_mode: true\nmax_speed: 2.0 # unit: m/s \nwaypoin"
  },
  {
    "path": "launch/Simulation/params/pure_pursuit_params.yaml",
    "chars": 579,
    "preview": "# Parameters for pure pursuit controller\nL: 0.5    # Length of car (m)\nlfw: 0.25 # distance between the front of the veh"
  },
  {
    "path": "launch/Simulation/params/rviz_navigation.rviz",
    "chars": 12277,
    "preview": "Panels:\n  - Class: rviz/Displays\n    Help Height: 81\n    Name: Displays\n    Property Tree Widget:\n      Expanded:\n      "
  },
  {
    "path": "launch/Simulation/stage/maze_carlike.world",
    "chars": 616,
    "preview": "include \"robots/carlike_robot.inc\"\n\n\ndefine floorplan model\n(\n  # sombre, sensible, artistic\n  color \"gray30\"\n\n  # most "
  },
  {
    "path": "launch/Simulation/stage/robots/carlike_robot.inc",
    "chars": 826,
    "preview": "define laser ranger\n(\n  sensor\n  (\n    range_max 6.5\n    fov 180.0\n    samples 640\n  )\n  # generic model properties\n  co"
  },
  {
    "path": "launch/includes/HyphaROS_MiniCar_Drivers.launch.xml",
    "chars": 2317,
    "preview": "<launch>\n    <!-- launch file arguments -->\n    <arg name=\"debug_mode\"  default=\"false\" doc=\"show debug info (bool)\"/> \n"
  },
  {
    "path": "launch/includes/amcl.launch.xml",
    "chars": 2425,
    "preview": "<launch>\n    <arg name=\"init_x\" default=\"0\" />\n    <arg name=\"init_y\" default=\"0\" />\n    <arg name=\"init_a\" default=\"0\" "
  },
  {
    "path": "launch/includes/gmapping.launch.xml",
    "chars": 1666,
    "preview": "<?xml version=\"1.0\"?>\n\n<launch>\n    <!-- Launch file parameters -->\n    <arg name=\"output\"  default=\"log\" />  <!-- optio"
  },
  {
    "path": "launch/includes/hector_slam.launch.xml",
    "chars": 2734,
    "preview": "<?xml version=\"1.0\"?>\n\n<launch>\n    <!-- Launch file parameters -->\n    <arg name=\"output\"  default=\"log\" />  <!-- optio"
  },
  {
    "path": "launch/includes/karto_slam.launch.xml",
    "chars": 433,
    "preview": "<?xml version=\"1.0\"?>\n\n<launch>\n    <!-- Launch file parameters -->\n    <arg name=\"output\"  default=\"log\" />  <!-- optio"
  },
  {
    "path": "launch/includes/minicar_base.launch.xml",
    "chars": 1380,
    "preview": "<launch>\n    <!-- launch file arguments -->\n    <arg name=\"debug_mode\"  default=\"false\" doc=\"show debug info (bool)\"/> \n"
  },
  {
    "path": "launch/includes/minicar_tf.launch.xml",
    "chars": 431,
    "preview": "<launch>\n    <node pkg=\"tf\" type=\"static_transform_publisher\" name=\"base_footprint2base_link\" args=\" 0 0 0 0 0 0 /base_f"
  },
  {
    "path": "launch/includes/mrpt_icp.launch.xml",
    "chars": 697,
    "preview": "<?xml version=\"1.0\"?>\n\n<launch>\n    <!-- Launch file parameters -->\n    <arg name=\"output\"  default=\"log\" />  <!-- optio"
  },
  {
    "path": "launch/includes/ydlidar.launch.xml",
    "chars": 729,
    "preview": "<launch>\n  <node name=\"ydlidar_node\"  pkg=\"ydlidar\"  type=\"ydlidar_node\" output=\"screen\">\n    <param name=\"port\"        "
  },
  {
    "path": "launch/params/costmap_common_params.yaml",
    "chars": 1042,
    "preview": "\n#---standard pioneer footprint---\n#---(in meters)---\n#footprint: [ [0.254, -0.0508], [0.1778, -0.0508], [0.1778, -0.177"
  },
  {
    "path": "launch/params/global_costmap_params.yaml",
    "chars": 490,
    "preview": "global_costmap:\n    global_frame: /map\n    robot_base_frame: base_link\n    update_frequency: 1.0\n    publish_frequency: "
  },
  {
    "path": "launch/params/global_planner.yaml",
    "chars": 63,
    "preview": "GlobalPlanner:\n    use_dijkstra: true\n    use_grid_path: false\n"
  },
  {
    "path": "launch/params/local_costmap_params.yaml",
    "chars": 380,
    "preview": "local_costmap:\n  global_frame: /map\n  robot_base_frame: base_link\n  update_frequency: 10.0\n  publish_frequency: 10.0\n  s"
  },
  {
    "path": "launch/params/mpc/mpc_params.yaml",
    "chars": 727,
    "preview": "# Parameters for control loop\npub_twist_cmd: true\ndebug_info: false\ndelay_mode: true\nmax_speed: 1.5 # unit: m/s \nwaypoin"
  },
  {
    "path": "launch/params/pure_pursuit/pure_pursuit_params.yaml",
    "chars": 586,
    "preview": "# Parameters for pure pursuit controller\nL: 0.1446    # Length of car (m)\nlfw: 0.0723 # distance between the front of th"
  },
  {
    "path": "launch/params/teb/teb_local_planner_params.yaml",
    "chars": 2857,
    "preview": "TebLocalPlannerROS:\n\n odom_topic: odom\n    \n # Trajectory\n  \n teb_autosize: True\n dt_ref: 0.3\n dt_hysteresis: 0.1\n globa"
  },
  {
    "path": "map/map_amcl.pgm",
    "chars": 1527,
    "preview": "P5\n# CREATOR: Map_generator.cpp 0.050 m/pix\n1984 1984\n255\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
  },
  {
    "path": "map/map_amcl.yaml",
    "chars": 136,
    "preview": "image: map_amcl.pgm\nresolution: 0.050000\norigin: [-50.000000, -50.000000, 0.000000]\nnegate: 0\noccupied_thresh: 0.65\nfree"
  },
  {
    "path": "map/map_nav.pgm",
    "chars": 2063,
    "preview": "P5\n# CREATOR: GIMP PNM Filter Version 1.1\n1984 1984\n255\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
  },
  {
    "path": "map/map_nav.yaml",
    "chars": 135,
    "preview": "image: map_nav.pgm\nresolution: 0.050000\norigin: [-50.000000, -50.000000, 0.000000]\nnegate: 0\noccupied_thresh: 0.65\nfree_"
  },
  {
    "path": "package.xml",
    "chars": 2122,
    "preview": "<?xml version=\"1.0\"?>\n<package format=\"2\">\n  <name>hypharos_minicar</name>\n  <version>0.0.0</version>\n  <description>The"
  },
  {
    "path": "readme.md",
    "chars": 4989,
    "preview": "# HyphaROS MiniCar (1/20 Scale MPC Racing Car)\n![alt text](https://github.com/Hypha-ROS/hypharos_minicar/blob/master/doc"
  },
  {
    "path": "rviz/hypharos_minicar_mapping.rviz",
    "chars": 6448,
    "preview": "Panels:\n  - Class: rviz/Displays\n    Help Height: 78\n    Name: Displays\n    Property Tree Widget:\n      Expanded: ~\n    "
  },
  {
    "path": "rviz/hypharos_minicar_racing.rviz",
    "chars": 13539,
    "preview": "Panels:\n  - Class: rviz/Displays\n    Help Height: 81\n    Name: Displays\n    Property Tree Widget:\n      Expanded:\n      "
  },
  {
    "path": "script/base_control.py",
    "chars": 14242,
    "preview": "#!/usr/bin/python\n# Copyright 2018 HyphaROS Workshop.\n# Developer: HaoChih, LIN (hypha.ros@gmail.com)\n#\n# Licensed under"
  },
  {
    "path": "script/teleop_keyboard.py",
    "chars": 6456,
    "preview": "#!/usr/bin/python\n\n# This is a modified verison of turtlebot_teleop.py\n# to fullfill the needs of HyphaROS MiniCar use c"
  },
  {
    "path": "src/MPC.cpp",
    "chars": 13736,
    "preview": "/*\n# Copyright 2018 HyphaROS Workshop.\n# Developer: HaoChih, LIN (hypha.ros@gmail.com)\n#\n# Licensed under the Apache Lic"
  },
  {
    "path": "src/MPC_Node.cpp",
    "chars": 16818,
    "preview": "/*\n# Copyright 2018 HyphaROS Workshop.\n# Developer: HaoChih, LIN (hypha.ros@gmail.com)\n#\n# Licensed under the Apache Lic"
  },
  {
    "path": "src/Pure_Pursuit.cpp",
    "chars": 13608,
    "preview": "/*\n# Copyright 2018 HyphaROS Workshop.\n# Latest Modifier: HaoChih, LIN (hypha.ros@gmail.com)\n# Original Author: ChanYuan"
  }
]

About this extraction

This page contains the full source code of the Hypha-ROS/hypharos_minicar GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 55 files (169.5 KB), approximately 51.7k tokens, and a symbol index with 21 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!