Skip to content

Commit 692ff2a

Browse files
committed
trim
1 parent f705f9b commit 692ff2a

6 files changed

Lines changed: 158 additions & 21 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ src/f1tenth_course/
88
src/ut_automata/
99
*.kdev*
1010
config/car.lua
11+
config/car.lua.*
1112
.vscode

config/vesc.lua

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,4 @@ i2c_bus_number = 7; -- I2C bus number for MPU6050 sensor
3535
calibrate_imu = true; -- Calibrate IMU on startup
3636
imu_gyro_range = 0; -- 0=250, 1=500, 2=1000, 3=2000 deg/s
3737
imu_accel_range = 0; -- 0=2g, 1=4g, 2=8g, 3=16g
38-
imu_dlpf_bandwidth = 0; -- 0=260Hz, 1=184Hz, 2=94Hz, 3=44Hz, 4=21Hz, 5=10Hz, 6=5Hz
39-
40-
-- Debug EKF logging for drift analysis
41-
debug_ekf = true; -- Set to true to log EKF data
42-
debug_log_path = "/home/orin/roboracer_ws/data/debug/ekf_debug.csv"; -- Path to debug log file
43-
44-
-- IMU mounting orientation is configured in vesc_driver.cpp
45-
-- Common orientations:
46-
-- Standard (IMU +x forward, +y left): {1, 0, 1, 1, 1, 2}
47-
-- IMU +x rear, +y right: {-1, 0, -1, 1, -1, 0}
48-
-- IMU +x right, +y forward: {1, 1, -1, 0, 1, 2}
38+
imu_dlpf_bandwidth = 0; -- 0=260Hz, 1=184Hz, 2=94Hz, 3=44Hz, 4=21Hz, 5=10Hz, 6=5Hz

launch/hokuyo_10lx.launch.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,24 @@ def generate_launch_description():
1919
output='screen',
2020
parameters=[{
2121
'ip_address': '192.168.0.10',
22+
'ip_port': 10940,
2223
'serial_port': '',
2324
'serial_baud': 115200,
24-
'frame_id': 'laser',
25-
'calibrate_time': False,
26-
'publish_intensity': True,
25+
'laser_frame_id': 'laser',
26+
'angle_max': 2.35619,
27+
'angle_min': -2.35619,
28+
'publish_intensity': False,
2729
'publish_multiecho': False,
28-
'angle_min': -2.25,
29-
'angle_max': 2.25,
30+
'calibrate_time': False,
31+
'default_user_latency': 0.0,
32+
'diagnostics_tolerance': 0.05,
33+
'diagnostics_window_time': 5.0,
34+
'error_limit': 4,
35+
'get_detailed_status': False,
36+
'cluster': 1,
37+
'skip': 1,
3038
}],
3139
))
3240

41+
3342
return ld

scripts/joystick_teleop.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ def readJoystick(self):
8888
joy_msg.axes.append(self.joystick.get_axis(i))
8989
#if (self.joystick.get_axis(i)):
9090
# self.last_active_time = time.time()
91+
92+
# Get hat (d-pad)
93+
if self.joystick.get_numhats() > 0:
94+
hat = self.joystick.get_hat(0)
95+
joy_msg.axes.append(hat[0]) # Left/Right (Axis 6)
96+
joy_msg.axes.append(hat[1]) # Up/Down (Axis 7)
97+
else:
98+
joy_msg.axes.append(0.0)
99+
joy_msg.axes.append(0.0)
91100
for i in range(10): #10
92101
joy_msg.buttons.append(self.joystick.get_button(i))
93102
if (self.joystick.get_button(i)):

src/vesc_driver/vesc_driver.cpp

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <iomanip>
1111
#include <unistd.h>
1212
#include <regex>
13+
#include <ctime>
1314

1415
#include "boost/bind/bind.hpp"
1516
#include "gflags/gflags.h"
@@ -87,6 +88,10 @@ VescDriver::VescDriver(rclcpp::Node::SharedPtr nh,
8788
t_last_command_(0),
8889
t_last_joystick_(0),
8990
last_smooth_speed_(0),
91+
last_dpad_x_(0),
92+
last_dpad_y_(0),
93+
steering_offset_trim_(0),
94+
speed_offset_trim_(0),
9095
imu_available_(false) {
9196
// Load config. Ensure car.lua exists; if it doesn't, create it using
9297
// the hostname. Hostnames like "orin07" will produce car_name = "car07".
@@ -187,6 +192,13 @@ VescDriver::VescDriver(rclcpp::Node::SharedPtr nh,
187192
wheelbase_ / tan(max_steering_angle_));
188193
RCLCPP_INFO(nh_->get_logger(), "===================================");
189194

195+
// Initialize trim offsets from config values
196+
steering_offset_trim_ = steering_to_servo_offset_;
197+
speed_offset_trim_ = speed_to_erpm_offset_;
198+
199+
200+
state_msg_.header.frame_id = "base_link";
201+
190202
state_msg_.header.frame_id = "base_link";
191203
car_status_msg_.header = state_msg_.header;
192204

@@ -351,6 +363,39 @@ void VescDriver::joystickCallback(const sensor_msgs::msg::Joy::SharedPtr msg) {
351363
static const size_t kAutonomousDriveButton = 5;
352364
static const size_t kAutonomousDriveToggleButton = 7;
353365
if (msg->buttons.size() < 6) return;
366+
367+
// Trim logic using D-pad (axes 6 and 7)
368+
if (msg->axes.size() >= 8) {
369+
int dpad_x = static_cast<int>(msg->axes[6]);
370+
int dpad_y = static_cast<int>(msg->axes[7]);
371+
372+
// Steering trim (Left/Right)
373+
if (dpad_x != 0 && dpad_x != last_dpad_x_) {
374+
// Left (-1) decreases offset, Right (+1) increases offset
375+
float step = 0.01f;
376+
steering_offset_trim_ += dpad_x * step;
377+
saveTrimOffsetsToConfig();
378+
RCLCPP_INFO(nh_->get_logger(), "Steering Trim: %.3f (delta from config: %.3f)",
379+
steering_offset_trim_, steering_offset_trim_ - steering_to_servo_offset_);
380+
}
381+
382+
// Speed trim (Up/Down)
383+
if (dpad_y != 0 && dpad_y != last_dpad_y_) {
384+
// Up (+1) increases offset, Down (-1) decreases offset
385+
// ERPM values are typically in thousands, so 100 is a small adjustment
386+
float step = 100.0f;
387+
speed_offset_trim_ += dpad_y * step;
388+
saveTrimOffsetsToConfig();
389+
RCLCPP_INFO(nh_->get_logger(), "Speed Trim: %.2f (delta from config: %.2f)",
390+
speed_offset_trim_, speed_offset_trim_ - speed_to_erpm_offset_);
391+
}
392+
393+
last_dpad_x_ = dpad_x;
394+
last_dpad_y_ = dpad_y;
395+
}
396+
397+
398+
354399
t_last_joystick_ = rclcpp::Clock(RCL_ROS_TIME).now().seconds();
355400
int toggle = toggleState(msg->buttons[kAutonomousDriveToggleButton]);
356401

@@ -509,11 +554,11 @@ void VescDriver::sendDriveCommands() {
509554
mux_drive_speed_, smooth_speed, mux_steering_angle_);
510555
}
511556
const float erpm =
512-
speed_to_erpm_gain_ * smooth_speed + speed_to_erpm_offset_;
557+
speed_to_erpm_gain_ * smooth_speed + speed_offset_trim_;
513558

514559
// calc steering angle (servo)
515560
const float servo = steering_to_servo_gain_ * mux_steering_angle_ +
516-
steering_to_servo_offset_;
561+
steering_offset_trim_;
517562

518563
// Set speed command.
519564
const float erpm_clipped = Clip(erpm, -erpm_speed_limit_, erpm_speed_limit_, "erpm");
@@ -522,11 +567,11 @@ void VescDriver::sendDriveCommands() {
522567
// Set servo position command.
523568
const float clipped_servo = Clip(servo, servo_min_, servo_max_, "servo");
524569
vesc_.setServo(clipped_servo);
525-
mux_steering_angle_ = (clipped_servo - steering_to_servo_offset_)
570+
mux_steering_angle_ = (clipped_servo - steering_offset_trim_)
526571
/ steering_to_servo_gain_;
527572
last_steering_angle_ = mux_steering_angle_;
528573

529-
const float clipped_speed = (erpm_clipped - speed_to_erpm_offset_) / speed_to_erpm_gain_;
574+
const float clipped_speed = (erpm_clipped - speed_offset_trim_) / speed_to_erpm_gain_;
530575
drive_pub_->publish(CalculateDriveCmd(clipped_speed, mux_steering_angle_));
531576
}
532577

@@ -701,7 +746,7 @@ void VescDriver::updateOdometry(float rpm, float tachometer, float steering_angl
701746
} else {
702747
// Standard odometry without EKF fusion
703748
// Calcuate linear velocity
704-
lin_vel = (rpm - speed_to_erpm_offset_) / speed_to_erpm_gain_;
749+
lin_vel = (rpm - speed_offset_trim_) / speed_to_erpm_gain_;
705750
// Clamp velocity to zero for minuscule values - a VESC drift issue.
706751
if (fabs(lin_vel) < 0.01) {
707752
lin_vel = 0.0;
@@ -833,6 +878,78 @@ void VescDriver::ackermannCurvatureCallback(
833878
}
834879

835880

881+
void VescDriver::saveTrimOffsetsToConfig() {
882+
std::string car_path = FLAGS_config_dir + "/car.lua";
883+
884+
// Read existing content
885+
std::ifstream file_in(car_path);
886+
std::string content;
887+
if (file_in.good()) {
888+
std::stringstream buffer;
889+
buffer << file_in.rdbuf();
890+
content = buffer.str();
891+
file_in.close();
892+
893+
// Create backup
894+
auto now = std::chrono::system_clock::now();
895+
auto in_time_t = std::chrono::system_clock::to_time_t(now);
896+
std::stringstream ss;
897+
ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d-%H-%M-%S");
898+
std::string backup_path = car_path + ".bk-" + ss.str();
899+
900+
std::ofstream backup_out(backup_path);
901+
if (backup_out.good()) {
902+
backup_out << content;
903+
backup_out.close();
904+
RCLCPP_INFO(nh_->get_logger(), "Created backup config: %s", backup_path.c_str());
905+
} else {
906+
RCLCPP_WARN(nh_->get_logger(), "Failed to create backup config: %s", backup_path.c_str());
907+
}
908+
}
909+
910+
// Prepare the offset lines with current absolute values
911+
std::string steering_line = "steering_angle_to_servo_offset = " +
912+
std::to_string(steering_offset_trim_) + ";\n";
913+
std::string speed_line = "speed_to_erpm_offset = " +
914+
std::to_string(speed_offset_trim_) + ";\n";
915+
916+
// Check if values already exist and update them, or append if not
917+
// Regex to match existing assignments. Note: values can be negative.
918+
std::regex steering_regex(R"(steering_angle_to_servo_offset\s*=\s*[-+]?[0-9]*\.?[0-9]+;)");
919+
std::regex speed_regex(R"(speed_to_erpm_offset\s*=\s*[-+]?[0-9]*\.?[0-9]+;)");
920+
921+
bool has_steering = std::regex_search(content, steering_regex);
922+
bool has_speed = std::regex_search(content, speed_regex);
923+
924+
if (has_steering) {
925+
content = std::regex_replace(content, steering_regex,
926+
"steering_angle_to_servo_offset = " +
927+
std::to_string(steering_offset_trim_) + ";");
928+
} else {
929+
content += steering_line;
930+
}
931+
932+
if (has_speed) {
933+
content = std::regex_replace(content, speed_regex,
934+
"speed_to_erpm_offset = " +
935+
std::to_string(speed_offset_trim_) + ";");
936+
} else {
937+
content += speed_line;
938+
}
939+
940+
// Write back to file
941+
std::ofstream file_out(car_path);
942+
if (file_out.good()) {
943+
file_out << content;
944+
file_out.close();
945+
RCLCPP_INFO(nh_->get_logger(),
946+
"Saved offsets to %s: steering=%.3f, speed=%.2f",
947+
car_path.c_str(), steering_offset_trim_, speed_offset_trim_);
948+
} else {
949+
RCLCPP_ERROR(nh_->get_logger(), "Failed to write offsets to %s", car_path.c_str());
950+
}
951+
}
952+
836953
bool VescDriver::isAutonomous(){
837954
return drive_mode_ == kAutonomousDrive || drive_mode_ == kAutonomousContinuousDrive;
838955
}

src/vesc_driver/vesc_driver.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ class VescDriver
101101
float last_steering_angle_;
102102
// Last smoothed speed actually sent to motor (for EKF)
103103
float last_smooth_speed_;
104+
105+
// Last D-pad state for trim control
106+
int last_dpad_x_;
107+
int last_dpad_y_;
108+
109+
// Runtime-adjustable trim offsets (initialized from config)
110+
float steering_offset_trim_;
111+
float speed_offset_trim_;
104112

105113
// Create an odometry message
106114
nav_msgs::msg::Odometry odom_msg_;
@@ -131,6 +139,9 @@ class VescDriver
131139

132140
void updateOdometry(float rpm, float tachometer, float steering_angle);
133141

142+
// Save trim offsets to car.lua configuration file
143+
void saveTrimOffsetsToConfig();
144+
134145
// true if car is running autonomously, false otherwise
135146
bool isAutonomous();
136147
// report current state of the autonomy toggle button

0 commit comments

Comments
 (0)