Roboracer BootCamp 2026 Jan
This page is with both real car and simulation. First, I made a private repo in github and shared the codes. I will go through pure pursuit simulation first and then see the difference with the real car.
I will skip the parts about mapping and connnections here. Pure Pursuit Lookahead distance: If it is big, it will look for further waypoint, which will make the car to crash in the corners If Lookahead distance is small, it will wobble because it is looking at short waypoint and it is reacting too much. Here are the videos with the lookahead distance values:
Lookahead distance is one of the major 4 parameters, the max velocity(threshold), velocity according to curve, pid k for raceline following amplification, and the lookahead distance.
Next test is follow the gap. first, the car is set to 1.0 velocity for whatever distance_ahead for safe test. However, it is wobbling too much at first movement. (It is avoiding walls to opposite direction though) Therefore, I decided to add Moving Average Filter at preprocess_lidar function.
def preprocess_lidar(self, ranges):
#Moving Average Filter
window_size = 5 #how many sample for average, bigger value is smoother but slower
kernel = np.ones(window_size) / window_size #all add up to 1, window_size if 5 so [0.2, 0.2 ,0.2, 0.2, 0.2]
ranges = np.convolve(ranges, kernel, mode='same') #convolution for average value
Not really getting better so adding steering angle smoothing –> adding did not work, so went back to pure code and change parameters (commented out the above moving average filter part also)
only changing the bubble_radius showed little difference, increasing it made it to get further from the wall (obstacle)
I could not solve wobble problem, because adding something only made the car to crash. But testing with bubble radius and moving average filter still made it not to crash to obstacles, and it was hallway (Levine Hall) so bubble radius did not really matter that much. I tried to make it fast by relating the velocity to distance ahead but it only made the car to crash because when the car was turning at curve when there was nothing ahead it speeded up and it crashed. Therefore at this hallway situation slow speed and not so much of bubble radius would be good idea not to crash. I am still wondering how to make it fast. Maybe adding speed limit only when it gets too fast after a curve.
Next part would be MPC, the Model Predictive Control. I am planning to spend most of the time here, to push NVidia Jetson Orin Nano to its extreme efficiency. I will first test with normal python mpc_node.py Then, I will work with mpc_jax.py which is library with enhanced python calculation for GPU. Then I will also test with C++ to consider real world situations. MPC fixes, Python node, and new waypoints settings took a long time in the first place but it worked.
A Problem: Python code has Latency, so there is a mismatch between sensor data processing and control cycle, which causes localization instability.
[Trying Jax library for faster python calculation acceleration]
Setting up mpc_jax.py is not easy because first, reading waypoint file cannot be done with jax numpy (jnp) GPU, so it has to be changed to using normal numpy with CPU. Furthermore, numba accelerator calculations could not use GPU for nearest point calculation also so we changed it to normal CPU numpy with changing all the jnp matrix to normal matrix, and matched float32 type as error showed up.
(imported numpy and made loading waypoint to use numpy, not jax)
sol: _, _, _, idx = nearest_point(np.array([px,py], dtype=np.float32), np.array(wp_xy, dtype=np.float32))
and also changed some configuration for jax decorator errors (should not use static variables) sol for newest jax:
cfg (index 3) variable is static
@jit(static_argnums=(3,)) def linearize_dynamics(v, yaw, steering, cfg: MPCConfig):
sol for old jax: just no jit, nor out of the function packaging. def linearize_dynamics(v, yaw, steering, cfg: MPCConfig): # … (codes) … return A, B # <— end of function
Out of the function, package it with jax.jit to avoid re-compilation for each call
#linearize_dynamics = jax.jit(linearize_dynamics, static_argnums=(3,))
lax.scan function ((A, B), C) error for 3 value transmission -> make it (A, B) only 2 (final value, accumulated record) (_, K_rev), _ = lax.scan( -> _, K_rev = lax.scan(
Problems I had: Numpy/Jax mix use problem, static argument problem, nearest_point type problem, Lax Scan data transmit problem.
The car went straight to the wall. Therefore I slowed down the car and made it look ahead for 7 points after, it wobbled a little bit straight then it went to the wall.
I tried more stuff but nothing worked, and I found that hz is too small, and its delay is too long also. The car is moving faster than data. Jax is having some sort of data processing bottleneck. Therefore I decided to move on to C++, I will try Jax again later on.
C++ shows higher 30 Hz condition. This is because Jax is more for bigger matrix calculation (like 1000X1000), but we are only using 4X4 or 8X8 matrix here, and python needs interpreter, where C++ is already compiled, directly communicating with CPU.
Test with pure pursuit of C++ and waypoint worked, so moving on to real MPC with OSQP
Problems while making the C++ file with OSQP: mainly changing solve_mpc() function and setupQP()
- cast_to_csc 인자 수정: 불필요한 5번째 인자(nzmax)를 제거해서 에러를 없앴습니다.
- csc 구조체 수동 할당: 이전 코드는 data->P가 초기화되지 않은 상태에서 접근하려 해서 위험했습니다. 위 코드처럼 c_malloc으로 먼저 공간을 만들고 값을 넣어야 프로그램이 안 죽습니다.
- %lld 수정: 젯슨(ARM)에서는 c_int가 long long이라서 %d 대신 %lld를 써야 경고가 사라집니다.
with c++ mpc_node it moves alone (without my joystick command) and it goes straight to the wall even faster. So I put Affine Term for calculation + safety code(initial velocity 0: wait for deadman switch).
now it goes straight line really fast but does make throught a corner. It tries to turn once then it turns back to the opposite direction and goes straight. Thus I removed waypoint velocity acceleration part.
ref(2,k)=w[3]*4.0; -> ref(2,k)=w[3] * 1.0;
now it moves slow but it tries to turn too late at the corner. so we changed: TK (8 → 13): (too small step ahead, look at the corner too late)
Rk (100.0 → 30.0): (too high weight on turning cost, so it tries not to turn) Rd (100.0 -> 30.0): just to follow above change
now it corners nicely, but I would like to let it turn a bit earlier and make the whole velocity fast for testing now. this is what we are gonna do, 🛠️ 1. MPCConfig 수정 (공격적인 세팅) mpc_node.cpp 위쪽 MPCConfig를 이렇게 바꾸세요.
[change point]
TK (Horizon): 13 → 20 (look ahead further and react faster) MAX_SPEED: 2.0 → 3.5 (faster velocity) Rk (Steering Cost): 30 → 10 (less cost for steering)
ref(2,k)=w[3] * 1.0; -> ref(2,k)=w[3] * 2.0; (waypoint velocity acce. *2.0 for faster)
some localization crack issue but it works ok. faster than python codes. when we only increase the speed, it wobbles a lot, but it still manages to follow the waypoint.
localization might be solved when we increase particle filter particle count. the /odom topic hz is bigger than mpc /drive topic so data receiving is fast enough. very good.
for faster speed I would like to test: MAX_SPEED: 5.0 (faster velocity) Rk (Steering Cost): 30 (higher cost for steering with faster speed) TK (Horizon): 25 (look ahead further and react faster)
still wobbles, 1 more test today Qk: 13.5 -> 2.0 less weight for correct path for smoothness Rk: 35 more weight on steering to steer less Tk: 18 balanced look ahead
it goes really smooth and fast, no wobble, but it gets in corner too late, so Qk: 5.0 little more weight for correct path Rk: 25 little less weight on steering to steer little bit more Tk: 23 balanced look ahead little bit more
it follows path well and curves well but wobbles again, so Qk: 2.0 the one with no wobble, yaw 5.0 for less weight on angle, v cost stays 5.5 to have correct velocity Rk: 30 little less weight on steering Tk: 23 increase look ahead
wobble is good but late corner, now its my intuition tuning time(look at phone pics)
little bit of wobble but gets in corner (still bit late but success), balanced code for now, Qk: 2.0 the one with no wobble, yaw 7.0 for less weight on angle, v cost stays 5.5 to have correct velocity Rk: 30 little less weight on steering Tk: 18 balanced look ahead
still could not get into second corner and has little wobble, but we are out of battery. We will come back!