Discussion - Nav2 Introduction (Making a Mobile Robot Pt 16)

hello community
When I launch

ros2 launch nav2_bringup navigation_launch.py use_sim_time:=true

and use 2D Goal Pose
There will be a problem.

[planner_server-3] [INFO] [1703402794.884508361] [global_costmap.global_costmap]: Received request to clear entirely the global_costmap
[planner_server-3] [ERROR] [1703402796.096544021] [transformPoseInTargetFrame]: Extrapolation Error looking up target frame: Lookup would require extrapolation into the future.  Requested time 1703402745.783910 but the latest data is at time 731.607000, when looking up transform from frame [odom] to frame [map]
[planner_server-3] 
[planner_server-3] [WARN] [1703402796.096618534] [planner_server]: Could not transform the start or goal pose in the costmap frame
[planner_server-3] [WARN] [1703402796.096663225] [planner_server]: [compute_path_to_pose] [ActionServer] Aborting handle.
[behavior_server-4] [INFO] [1703402796.112731234] [behavior_server]: Running backup
[behavior_server-4] [WARN] [1703402806.118608888] [behavior_server]: Exceeded time allowance before reaching the DriveOnHeading goal - Exiting DriveOnHeading
[behavior_server-4] [WARN] [1703402806.118794687] [behavior_server]: backup failed
[behavior_server-4] [WARN] [1703402806.118853410] [behavior_server]: [backup] [ActionServer] Aborting handle.
[controller_server-1] [INFO] [1703402806.167201610] [local_costmap.local_costmap]: Received request to clear entirely the local_costmap
[planner_server-3] [INFO] [1703402806.194430683] [global_costmap.global_costmap]: Received request to clear entirely the global_costmap
[bt_navigator-5] [WARN] [1703402806.270823741] [bt_navigator_navigate_to_pose_rclcpp_node]: Timed out while waiting for action server to acknowledge goal request for compute_path_to_pose
[planner_server-3] [INFO] [1703402806.275882344] [global_costmap.global_costmap]: Received request to clear entirely the global_costmap
[planner_server-3] [ERROR] [1703402807.097615127] [transformPoseInTargetFrame]: Extrapolation Error looking up target frame: Lookup would require extrapolation into the future.  Requested time 1703402745.783910 but the latest data is at time 736.232000, when looking up transform from frame [odom] to frame [map]
[planner_server-3] 
[planner_server-3] [WARN] [1703402807.103436113] [planner_server]: Could not transform the start or goal pose in the costmap frame
[planner_server-3] [WARN] [1703402807.103546444] [planner_server]: [compute_path_to_pose] [ActionServer] Aborting handle.
[behavior_server-4] [INFO] [1703402807.169281308] [behavior_server]: Running spin
[behavior_server-4] [INFO] [1703402807.169574092] [behavior_server]: Turning 1.57 for spin behavior.
[behavior_server-4] [INFO] [1703402810.275975743] [behavior_server]: spin completed successfully
[planner_server-3] [ERROR] [1703402811.187078389] [transformPoseInTargetFrame]: Extrapolation Error looking up target frame: Lookup would require extrapolation into the future.  Requested time 1703402745.783910 but the latest data is at time 738.292000, when looking up transform from frame [odom] to frame [map]
[planner_server-3] 
[planner_server-3] [WARN] [1703402811.194227126] [planner_server]: Could not transform the start or goal pose in the costmap frame
[planner_server-3] [WARN] [1703402811.194322182] [planner_server]: [compute_path_to_pose] [ActionServer] Aborting handle.
[planner_server-3] [INFO] [1703402811.262905966] [global_costmap.global_costmap]: Received request to clear entirely the global_costmap
[bt_navigator-5] [WARN] [1703402811.268427021] [bt_navigator_navigate_to_pose_rclcpp_node]: Node timed out while executing service call to global_costmap/clear_entirely_global_costmap.
[bt_navigator-5] [ERROR] [1703402811.269075529] [bt_navigator]: Goal failed
[bt_navigator-5] [WARN] [1703402811.269169754] [bt_navigator]: [navigate_to_pose] [ActionServer] Aborting handle.

And then you just run the rotation, and all of a sudden the wheel rolls back.
What should I do?
I’m using humble

Im facing the issue on real robot , the same error message you received . Any advice on how you solved it ?

change spawner.py to spawner in the launch file

Hi Josh,

I have the following problem. Simulatioin has the following Problem, it is possible that real robot also.
If I start my system following your great tutorial every thing works.

If I leave the system for half an hour or more I see my robot on other place without action from my side. After some hours it is on completely different place.

What can I do to overcome this drift ?

Thank you very much in advance!

Cheers,
Ivo

Hi
Just a small query regarding waypoints. So I see how you manually assigned goal pose which the bot was following. I was wondering if there is any way to put multiple waypoints and then save it in the map itself. So that next time I run the simulation the bot follows the same trajectory from the same input goal poses or waypoints. This way I can actually have a fully autonomous simulation model.

I hae a question, If we are using ros2 navigation stack how it is communicating with the hardware. I do know that we have to write the custom hardware interface but how to move motors according the path planning plugins. I am working on similar project. I was able to connect my robot with Arduino through serial communication but I don’t know how to move the motors according the navigation2 path plan.
is there any arduino code.

what I am trying to do is send the encoded values to custom interface, for odometery but I have no idea what commands should be send to arduino, so it can move according to the path planning given by rviz2

Is it possible to use different path tracking algorithm, such as pure pursuit or standley, instead of nav2?

Hello
Thank you for your tutorial set. Thanks to that I finally understood basic levels of nav2. I am trying to create a custom behaviour tree using existing behaviour nodes. However, when I try to give the path to this custom file, it always takes the default nav2 BT. I tried the tutorials of Nav2 website but still not clear on what to do. Could you kindly give me the step by step process on how to give the link to my custom created BT? It would be a grate help!

Continuing the discussion from Discussion - Nav2 Introduction (Making a Mobile Robot Pt 16):

hi , I m really in need of help in navigation, the map creation using slam is perfect but when i try to navigate by giving the goal i m getting exploartion errors, Behavior Tree tick rate,etc and not moving an inch .Every other terminal seems to be working fine except the nav2 terminal

[bt_navigator-5] [INFO] [1743701696.297607268] [bt_navigator]: Begin navigating from current location (-2.62, -0.08) to (-1.36, 0.01)
[planner_server-3] [ERROR] [1743701696.761987230] [transformPoseInTargetFrame]: Extrapolation Error looking up target frame: Lookup would require extrapolation into the future. Requested time 1743701696.294112 but the latest data is at time 844.250000, when looking up transform from frame [odom] to frame [map]
[planner_server-3]
[planner_server-3] [WARN] [1743701696.762257369] [planner_server]: Could not transform the start or goal pose in the costmap frame
[planner_server-3] [WARN] [1743701696.762371245] [planner_server]: [compute_path_to_pose] [ActionServer] Aborting handle.
[planner_server-3] [INFO] [1743701696.782962024] [global_costmap.global_costmap]: Received request to clear entirely the global_costmap
[planner_server-3] [ERROR] [1743701697.872118599] [transformPoseInTargetFrame]: Extrapolation Error looking up target frame: Lookup would require extrapolation into the future. Requested time 1743701696.294112 but the latest data is at time 845.050000, when looking up transform from frame [odom] to frame [map]
[planner_server-3]
[planner_server-3] [WARN] [1743701697.874073618] [planner_server]: Could not transform the start or goal pose in the costmap frame
[planner_server-3] [WARN] [1743701697.874485703] [planner_server]: [compute_path_to_pose] [ActionServer] Aborting handle.
[controller_server-1] [INFO] [1743701697.888284498] [local_costmap.local_costmap]: Received request to clear entirely the local_costmap
[planner_server-3] [INFO] [1743701697.890384788] [global_costmap.global_costmap]: Received request to clear entirely the global_costmap
[bt_navigator-5] [WARN] [1743701698.799354508] [BehaviorTreeEngine]: Behavior Tree tick rate 100.00 was exceeded!

The errors still goes…

i finally made it to work,it was just a silly mistake,What happened was when running the twist mux, instead of cmd_vel_unstamped i typed cmd_vel_unstamed.Yes a typo , so someone had any kind of error check for the spellings of the command

hi
thanks a lot for ROS tutorial series!
i’ve project to make AGV using lidar with mini pc. I use ros humble( of course ubuntu jammy) and so far it is running well with litle change because i’m use humble.

unfortunately i didn’t get perfect setting or parameter in urdf file i think? which is wheel separation or radius
i’ve got probem when my agv(both simulation and realrobot) do rotate, my laserscan shift a lot. make my map messy!

any solution for my case?
thanks

Hi everyone,

I watched a video about multi-robot spawning and I’m currently trying to implement it myself. I was able to successfully spawn the robots in Gazebo, but I’m running into issues with the controllers — they don’t seem to load properly, and I can’t figure out why.

After resolving this, I plan to integrate multi-robot navigation using Nav2. If you have any suggestions, I’d be really grateful!

I’m sharing the repository here:
:link: Distributed-Robot-organization repositories · GitHub
You can find the multi-robot implementation in the dev/multi_robot branch.

You can run the code using Docker. Here’s how:

Terminal 1:

ros2 launch dr_description gazebo_env.launch.py

Terminal 2:

ros2 launch dr_description multi_minion.launch.py

The issue I’m currently facing is the following:

The robot spawns correctly in Gazebo, but the controllers are not being created or loaded.

I’ve tried several changes, but I’m not sure whether the issue lies in the Xacro file, the launch files, or one of the YAML configuration files.

Any help or guidance would be greatly appreciated!

Thanks in advance!

[spawner-5] [INFO] [1753819909.846717626] [robot1.robot1_joint_broad_spawner]: waiting for service /robot1/controller_manager/list_controllers to become available…
[spawner-11] [WARN] [1753819909.859256710] [robot2.robot2_joint_broad_spawner]: Could not contact service /robot2/controller_manager/list_controllers
[spawner-11] [INFO] [1753819909.859541419] [robot2.robot2_joint_broad_spawner]: waiting for service /robot2/controller_manager/list_controllers to become available…
[spawner-17] [WARN] [1753819919.766606933] [robot3.robot3_joint_broad_spawner]: Could not contact service /robot3/controller_manager/list_controllers
[spawner-17] [INFO] [1753819919.766873789] [robot3.robot3_joint_broad_spawner]: waiting for service /robot3/controller_manager/list_controllers to become available…
[spawner-18] [WARN] [1753819919.783654267] [robot3.robot3_diff_drive_spawner]: Could not contact service /robot3/controller_manager/list_controllers
[spawner-18] [INFO] [1753819919.783945501] [robot3.robot3_diff_drive_spawner]: waiting for service /robot3/controller_manager/list_controllers to become available…
[spawner-6] [WARN] [1753819919.795212812] [robot1.robot1_diff_drive_spawner]: Could not contact service /robot1/controller_manager/list_controllers
[spawner-6] [INFO] [1753819919.796228473] [robot1.robot1_diff_drive_spawner]: waiting for service /robot1/controller_manager/list_controllers to become available…
[spawner-12] [WARN] [1753819919.798653980] [robot2.robot2_diff_drive_spawner]: Could not contact service /robot2/controller_manager/list_controllers
[spawner-12] [INFO] [1753819919.799080406] [robot2.robot2_diff_drive_spawner]: waiting for service /robot2/controller_manager/list_controllers to become available…
[spawner-5] [WARN] [1753819919.861364254] [robot1.robot1_joint_broad_spawner]: Could not contact service /robot1/controller_manager/list_controllers
[spawner-5] [INFO] [1753819919.861680753] [robot1.robot1_joint_broad_spawner]: waiting for service /robot1/controller_manager/list_controllers to become available…
[spawner-11] [WARN] [1753819919.875408289] [robot2.robot2_joint_broad_spawner]: Could not contact service /robot2/controller_manager/list_controllers
[spawner-11] [INFO] [1753819919.875683579] [robot2.robot2_joint_broad_spawner]: waiting for service /robot2/controller_manager/list_controllers to become available…

My microcontroller code has some issues, and it makes the robot’s navigation not smooth. Could anyone help me fix it?
#include <PID_v1.h>
#include <math.h>

// ---------------- Encoder pins ----------------
#define ENC_IN_LEFT_A 2 // interrupt
#define ENC_IN_LEFT_B 4
#define ENC_IN_RIGHT_A 3 // interrupt
#define ENC_IN_RIGHT_B 5

// ---------------- LEDs / buttons ----------------
const int buttonPin = 26;
const int red = 22;
const int yellow = 24;
const int pos1 = 34;
const int pos2 = 44;

// ---------------- BTS7960 pins ----------------
const int RPWM_L = 11; // forward left
const int LPWM_L = 7; // reverse left
const int RPWM_R = 10; // forward right
const int LPWM_R = 12; // reverse right

// ---------------- Robot geometry ----------------
const double BASE_WIDTH_M = 0.345; // distance between wheels (m)
const double WHEEL_DIAM_M = 0.085; // diameter (m)
const double WHEEL_CIRC_M = M_PI * WHEEL_DIAM_M;
const long TICKS_PER_REV = 300;
const double DT_LOOP_MS = 30.0; // control loop period (ms)

// ---------------- PID gains ----------------
double left_kp = 15, left_ki = 0.5, left_kd = 0.05;
double right_kp = 15, right_ki = 0.5, right_kd = 0.05;
const double K_V2PWM = 160.0;

// Convert keyboard pulse to setpoints
const double K_PULSE2V = 0.00013;
const double K_PULSE2W = 0.0035;

// ---------------- Runtime state ----------------
volatile long left_ticks_cum = 0;
volatile long right_ticks_cum = 0;
volatile long enc_left_dt = 0;
volatile long enc_right_dt = 0;
boolean Direction_left = true;
boolean Direction_right = true;
double v_left_meas = 0, v_right_meas = 0;
double v_left_sp = 0, v_right_sp = 0;
double left_input = 0, left_output = 0, left_setpoint = 0;
double right_input = 0, right_output = 0, right_setpoint = 0;
PID leftPID (&left_input, &left_output, &left_setpoint, left_kp, left_ki, left_kd, DIRECT);
PID rightPID(&right_input, &right_output, &right_setpoint, right_kp, right_ki, right_kd, DIRECT);

// Bổ sung: Biến lưu trữ Odometry
double x_pos = 0.0;
double y_pos = 0.0;
double theta_angle = 0.0; // Góc hiện tại của robot (radian)

// Smooth PWM for soft start/stop
int smooth_pwmL = 0, smooth_pwmR = 0;
const int PWM_STEP_UP = 5; // tăng dần
const int PWM_STEP_DOWN = 4; // giảm dần
const int PWM_LIMIT = 80; // giới hạn PWM

// UART buffer & watchdog
String inbuf;
unsigned long last_cmd_ms = 0;
const unsigned long CMD_TIMEOUT_MS = 100;

// PID state enable flag
bool pidEnabled = false;

// UART xuất tín hiệu encoder cho UNO tay rung
#define ENCODER_TX Serial1

// ---------------- Encoder ISRs ----------------
void right_wheel_tick() {
int val = digitalRead(ENC_IN_RIGHT_B);
Direction_right = (val == LOW);
if (Direction_right) {
right_ticks_cum++;
enc_right_dt++;
} else {
right_ticks_cum–;
enc_right_dt–;
}
}

void left_wheel_tick() {
int val = digitalRead(ENC_IN_LEFT_B);
Direction_left = (val != LOW);
if (Direction_left) {
left_ticks_cum++;
enc_left_dt++;
} else {
left_ticks_cum–;
enc_left_dt–;
}
}

// ---------------- BTS7960 helper ----------------
static inline void driveBTS(int pwmCmd, int pinRPWM, int pinLPWM, int &smoothRef) {
pwmCmd = constrain(pwmCmd, -PWM_LIMIT, PWM_LIMIT);

// ramp PWM để phanh mượt
if (smoothRef < pwmCmd) smoothRef += PWM_STEP_UP;
else if (smoothRef > pwmCmd) smoothRef -= PWM_STEP_DOWN;

// giới hạn sau ramp
smoothRef = constrain(smoothRef, -PWM_LIMIT, PWM_LIMIT);

int mag = abs(smoothRef);
if (smoothRef >= 0) {
analogWrite(pinRPWM, mag);
analogWrite(pinLPWM, 0);
} else {
analogWrite(pinRPWM, 0);
analogWrite(pinLPWM, mag);
}
}

// ---------------- Emergency STOP ----------------
static inline void stopAll() {
v_left_sp = 0;
v_right_sp = 0;

pidEnabled = false;
leftPID.SetMode(MANUAL);
rightPID.SetMode(MANUAL);
left_output = 0;
right_output = 0;

smooth_pwmL = 0;
smooth_pwmR = 0;
driveBTS(0, RPWM_R, LPWM_R, smooth_pwmR);
driveBTS(0, RPWM_L, LPWM_L, smooth_pwmL);

analogWrite(RPWM_R, 0); analogWrite(LPWM_R, 0);
analogWrite(RPWM_L, 0); analogWrite(LPWM_L, 0);

// Đặt lại Odometry khi dừng hoàn toàn
x_pos = 0.0;
y_pos = 0.0;
theta_angle = 0.0;

Serial.println(“[STOP_CMD_RX]”);
digitalWrite(red, HIGH);
digitalWrite(yellow, LOW);
}

// ---------------- UART command parsing ----------------
void handleUartCmd(const String &s) {
if (s.length() == 0) return;
if (s.equalsIgnoreCase(“stop”)) { stopAll(); return; }

char c = s[0];
if (c == ‘x’ || c == ‘X’) { stopAll(); return; }

long val = (s.length() > 1) ? s.substring(1).toInt() : 0;

double linear = 0.0, angular = 0.0;
if (c == ‘w’) linear = K_PULSE2V * val;
if (c == ‘s’) linear = -K_PULSE2V * val;
if (c == ‘a’) angular = K_PULSE2W * val;
if (c == ‘d’) angular = -K_PULSE2W * val;

double v_r = linear + angular * (BASE_WIDTH_M / 2.0);
double v_l = linear - angular * (BASE_WIDTH_M / 2.0);

if (fabs(linear) > 1e-9 || fabs(angular) > 1e-9) {
if (!pidEnabled) {
pidEnabled = true;
leftPID.SetMode(AUTOMATIC);
rightPID.SetMode(AUTOMATIC);
Serial.println(“[PID ON]”);
}
v_left_sp = v_l;
v_right_sp = v_r;
} else {
stopAll();
}
}

// ---------------- Setup ----------------
void setup() {
Serial.begin(115200);
ENCODER_TX.begin(9600);

pinMode(ENC_IN_LEFT_A , INPUT_PULLUP);
pinMode(ENC_IN_LEFT_B , INPUT);
pinMode(ENC_IN_RIGHT_A, INPUT_PULLUP);
pinMode(ENC_IN_RIGHT_B, INPUT);
attachInterrupt(digitalPinToInterrupt(ENC_IN_LEFT_A), left_wheel_tick, RISING);
attachInterrupt(digitalPinToInterrupt(ENC_IN_RIGHT_A), right_wheel_tick, RISING);

pinMode(RPWM_R, OUTPUT); pinMode(LPWM_R, OUTPUT);
pinMode(RPWM_L, OUTPUT); pinMode(LPWM_L, OUTPUT);
pinMode(yellow, OUTPUT); pinMode(red, OUTPUT);
pinMode(pos1, OUTPUT); pinMode(pos2, OUTPUT);

analogWrite(RPWM_R, 0);
analogWrite(LPWM_R, 0);
analogWrite(RPWM_L, 0);
analogWrite(LPWM_L, 0);

digitalWrite(red, HIGH);
digitalWrite(yellow, LOW);
digitalWrite(pos1, LOW);
digitalWrite(pos2, LOW);

leftPID.SetMode(MANUAL);
rightPID.SetMode(MANUAL);
leftPID.SetSampleTime((int)DT_LOOP_MS);
rightPID.SetSampleTime((int)DT_LOOP_MS);
leftPID.SetOutputLimits(-1.0, 1.0);
rightPID.SetOutputLimits(-1.0, 1.0);

stopAll();
last_cmd_ms = millis();
Serial.println(“System ready. Motors stopped.”);
}

// ---------------- Main loop ----------------
void loop() {
// UART đọc lệnh
while (Serial.available()) {
char c = (char)Serial.read();
Serial.print("[RX] "); Serial.println(c);

if (c == 'x' || c == 'X' || c == ' ') {
  stopAll();
  inbuf = "";
  unsigned long start_clean = millis();
  while (Serial.available() && (millis() - start_clean < 5)) Serial.read();
  last_cmd_ms = millis();
  continue;
}

if (c == '\r' || c == '\n') {
  if (inbuf.length() > 0) {
    handleUartCmd(inbuf);
    inbuf = "";
    last_cmd_ms = millis();
  }
} else {
  if (isAlphaNumeric(c)) {
    inbuf += c;
    if (inbuf.length() > 32) inbuf = "";
  }
}

}

// Watchdog timeout
if (millis() - last_cmd_ms > CMD_TIMEOUT_MS) {
v_left_sp = 0;
v_right_sp = 0;
}

static unsigned long prev_ms = 0, prev_print = 0;
unsigned long now = millis();

// Control loop
if (now - prev_ms >= (unsigned long)DT_LOOP_MS) {
prev_ms = now;

// 1. Lấy dữ liệu Encoder
noInterrupts();
long dL = enc_left_dt;
long dR = enc_right_dt;
enc_left_dt = 0;
enc_right_dt = 0;
long total_left_ticks = left_ticks_cum;
long total_right_ticks = right_ticks_cum;
interrupts();

// 2. Tính vận tốc và quãng đường (Cho PID và Odometry)
double ticks_per_sec = 1000.0 / DT_LOOP_MS;
v_left_meas  = (dL * ticks_per_sec / (double)TICKS_PER_REV) * WHEEL_CIRC_M;
v_right_meas = (dR * ticks_per_sec / (double)TICKS_PER_REV) * WHEEL_CIRC_M;

// Tính quãng đường di chuyển của từng bánh xe (m)
double dist_L = ((double)dL / TICKS_PER_REV) * WHEEL_CIRC_M;
double dist_R = ((double)dR / TICKS_PER_REV) * WHEEL_CIRC_M;

// 3. Tính Kinematics chuyển tiếp (Odometry)
double d_theta = (dist_R - dist_L) / BASE_WIDTH_M; // Thay đổi góc
double d_center = (dist_R + dist_L) / 2.0;         // Quãng đường trung tâm

// Tích hợp Odometry (sử dụng xấp xỉ cung tròn nhỏ)
double avg_theta = theta_angle + (d_theta / 2.0); // Góc trung bình cho đoạn di chuyển

double d_x = d_center * cos(avg_theta);
double d_y = d_center * sin(avg_theta);

x_pos += d_x;
y_pos += d_y;
theta_angle += d_theta;

// Chuẩn hóa góc theta (-PI đến PI) để tránh tràn số (optional)
while (theta_angle > M_PI) theta_angle -= 2 * M_PI;
while (theta_angle < -M_PI) theta_angle += 2 * M_PI;


// 4. PID Control
left_setpoint  = v_left_sp;
right_setpoint = v_right_sp;
left_input  = v_left_meas;
right_input = v_right_meas;

if (pidEnabled) {
  leftPID.Compute();
  rightPID.Compute();
} else {
  left_output = 0;
  right_output = 0;
}

int pwmL = (int)round(left_output  * K_V2PWM);
int pwmR = (int)round(right_output * K_V2PWM);

// 5. Điều khiển động cơ
driveBTS(pwmR, RPWM_R, LPWM_R, smooth_pwmR);
driveBTS(pwmL, RPWM_L, LPWM_L, smooth_pwmL);

if (fabs(v_left_sp) < 1e-3 && fabs(v_right_sp) < 1e-3) {
  digitalWrite(red, HIGH);
  digitalWrite(yellow, LOW);
} else {
  digitalWrite(red, LOW);
  digitalWrite(yellow, HIGH);
}

}

// Xuất encoder và Odometry định kỳ 100ms
if (now - prev_print >= 100) {
prev_print = now;

// Xuất Odometry và ticks qua Serial1 để đọc bằng ROS
// Format: x,y,theta,ticksL,ticksR
ENCODER_TX.print(x_pos);
ENCODER_TX.print(",");
ENCODER_TX.print(y_pos);
ENCODER_TX.print(",");
ENCODER_TX.print(theta_angle);
ENCODER_TX.print(",");
ENCODER_TX.print(left_ticks_cum);
ENCODER_TX.print(",");
ENCODER_TX.println(right_ticks_cum);

// In ra Serial (Debug)
Serial.print("X="); Serial.print(x_pos, 4);
Serial.print(" Y="); Serial.print(y_pos, 4);
Serial.print(" Theta="); Serial.println(theta_angle, 4);

}
}