Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
153 commits
Select commit Hold shift + click to select a range
210bef9
Update reactive_node.py
Nitish4144 Sep 26, 2025
e29021c
Update gym_bridge.py
Nitish4144 Sep 27, 2025
8454936
Updated repo
Nitish4144 Oct 2, 2025
08c2a51
Merge branch 'main' of https://github.com/GoldenHawk004/RC-CAR-ROS2
Nitish4144 Oct 2, 2025
28f9c9f
Create Manual_ctrl
Nitish4144 Oct 13, 2025
4a47c5c
Update README.md
Nitish4144 Oct 13, 2025
16b1a6f
Create joy_raw.py
Nitish4144 Oct 13, 2025
53ce7dc
Create joy_config.py
Nitish4144 Oct 13, 2025
f9cc95d
Create motor_signals.py
Nitish4144 Oct 13, 2025
15686fa
Rename motor_signals.py to joy_PWM.py
Nitish4144 Oct 13, 2025
7b6faef
Create motor_signals.py
Nitish4144 Oct 13, 2025
69797ad
Update motor_signals.py
Nitish4144 Oct 13, 2025
ab3e0f0
Update joy_raw.py , fixing a typo
Nitish4144 Oct 14, 2025
05a7562
Update joy_config.py, fixing a typo
Nitish4144 Oct 14, 2025
f7a3b2b
added code related joy, code for motro to pwm signls and made setup.py
Nitish4144 Oct 14, 2025
65a07e6
fixing typos
Nitish4144 Oct 16, 2025
435ad69
Update README.md
Nitish4144 Oct 16, 2025
257c9f8
Enhance README with clearer instructions
Nitish4144 Oct 16, 2025
74052d9
Rename joy_PWM.py to joy_drive.py
Nitish4144 Oct 16, 2025
0718b2b
adding readme
Nitish4144 Oct 16, 2025
c63cf20
added launuch files for Manual_ctrl
Nitish4144 Oct 16, 2025
70cf957
added instructions to run launch files and described nodes in Manual_…
Nitish4144 Oct 16, 2025
bf33443
fixing a typo
Nitish4144 Oct 16, 2025
dbd09df
fixed a typo
Nitish4144 Oct 16, 2025
b52f9fc
finall commit of the day 16/10/25
Nitish4144 Oct 16, 2025
b11a3b4
fixed code for physical car
Nitish4144 Oct 22, 2025
9f45b51
Create lcd_eyes
kmanojkr12-bit Oct 26, 2025
3df12e5
Delete src/lcd_eyes
kmanojkr12-bit Oct 26, 2025
21066d7
Create __init__.py
kmanojkr12-bit Oct 26, 2025
84da9db
Create package.xml
kmanojkr12-bit Oct 26, 2025
d569db4
Create setup.py
kmanojkr12-bit Oct 26, 2025
364d972
Create README.md
kmanojkr12-bit Oct 26, 2025
b90caec
Create eye_display.py
kmanojkr12-bit Oct 26, 2025
79b6cf8
Implement EyeDisplay class for LCD eyes simulation
kmanojkr12-bit Oct 26, 2025
abc7b0e
Add package.xml for lcd_eyes node
kmanojkr12-bit Oct 26, 2025
ab50d1c
Add setup.py for lcd_eyes package
kmanojkr12-bit Oct 26, 2025
ef94ff6
updated gym bridge code for rviz and added requirements.txt
Nitish4144 Oct 26, 2025
4ec8d9f
the viz is working again without throtle
Nitish4144 Oct 27, 2025
b3d37d1
updated viz and manual_ctrl, joy controls working for viz .
Nitish4144 Oct 28, 2025
7c7689c
updated step function in gym_bridge.py for proper steering action in …
Nitish4144 Oct 28, 2025
882f880
Add OLEDEyes node for OLED display control
kmanojkr12-bit Nov 1, 2025
f39a733
Create __init__.py
kmanojkr12-bit Nov 1, 2025
3553178
Delete roboeyes/roboeyes.py
kmanojkr12-bit Nov 1, 2025
6b05c24
Delete roboeyes directory
kmanojkr12-bit Nov 1, 2025
8c9af4b
Create roboeyes.py
kmanojkr12-bit Nov 1, 2025
2aafe14
Create __init__.py
kmanojkr12-bit Nov 1, 2025
3c80467
Create setup.py
kmanojkr12-bit Nov 1, 2025
394c178
Delete src/roboeyes/roboeyes/setup.py
kmanojkr12-bit Nov 1, 2025
d59d75a
Create setup.py
kmanojkr12-bit Nov 1, 2025
ceaab40
Add launch file for oled_eyes node
kmanojkr12-bit Nov 1, 2025
bb58b35
Create package.xml
kmanojkr12-bit Nov 1, 2025
c241e86
updated motor signals and replaced pigpio with gpiozero
Nitish4144 Nov 1, 2025
d308cd4
Updated oled eyes
Nitish4144 Nov 1, 2025
ac58c06
changed README.md file
Nitish4144 Dec 2, 2025
0c0efa5
Create __init__.py
Nitish4144 Dec 25, 2025
e4be682
Implement command parser for RC car control
Nitish4144 Dec 25, 2025
009affd
Implement LlmAckermannNode for drive command input
Nitish4144 Dec 25, 2025
05bab30
Implement RC Car PWM Driver for bidirectional control
Nitish4144 Dec 25, 2025
131a0f7
Create package.xml
Nitish4144 Dec 25, 2025
6d74c1f
Create setup.py
Nitish4144 Dec 25, 2025
254d37c
Create setup.config
Nitish4144 Dec 25, 2025
a3f1264
completed setup for new sd card with llm_ctrl
Nitish4144 Dec 25, 2025
0f21dbb
Update package.xml
Nitish4144 Dec 25, 2025
82c2a5c
Enhance LlmAckermannNode with safety limits and input handling
Nitish4144 Dec 25, 2025
2b9f849
LETS SEE
kmanojkr12-bit Dec 25, 2025
246563b
Fix spacing in console script entry for model
Nitish4144 Dec 25, 2025
179d27c
Change ESC calibration and stop signal to reverse
kmanojkr12-bit Dec 25, 2025
b8d71f4
ll
kmanojkr12-bit Dec 25, 2025
0508402
FINALE
kmanojkr12-bit Dec 25, 2025
7312dda
Update motor_signals.py
kmanojkr12-bit Dec 26, 2025
ea7f521
unidirectional
kmanojkr12-bit Dec 26, 2025
3cd7369
Resolve merge conflict: GPIO pin definitions
Nitish4144 Dec 27, 2025
dd2c3c4
changed axis
Nitish4144 Dec 27, 2025
b37851b
msg
Nitish4144 Dec 27, 2025
49ae5a8
Merge branch 'monitor'
Nitish4144 Dec 27, 2025
efcc984
added new files in llm_ctrl and changed motor_signals.py
Nitish4144 Dec 28, 2025
812f4a5
Update oled_eyes.py
aarushsainukala-oss Dec 28, 2025
08261d9
llm_ctrl complete for rpi
Nitish4144 Dec 29, 2025
71e6262
Merge branch 'Nitish4144:main' into main
aarushsainukala-oss Dec 29, 2025
393affb
Enhance OLED Eyes functionality and behavior
Nitish4144 Dec 30, 2025
45f3726
Merge branch 'Nitish4144:main' into main
aarushsainukala-oss Dec 30, 2025
d187306
Update oled_eyes.py
aarushsainukala-oss Dec 30, 2025
4bad702
added credits (#1)
aarushsainukala-oss Dec 30, 2025
24cead4
Add TextInputApp for audio ankeyboard as input
Nitish4144 Dec 30, 2025
5ad4562
added LLM controller
Nitish4144 Dec 30, 2025
ee0a47c
Add ollama_test script for Llama 3.2 chat
Nitish4144 Dec 30, 2025
ad5cb82
Add shared memory reader script in shm.py
Nitish4144 Dec 30, 2025
0b3c792
Add requirements for LLM control scripts
Nitish4144 Dec 30, 2025
e456900
Create README.md with Windows setup instructions
Nitish4144 Dec 30, 2025
e2b0143
Merge branch 'Nitish4144:main' into main
aarushsainukala-oss Dec 30, 2025
943f903
json_to_ackermann
aarushsainukala-oss Dec 30, 2025
3b9493a
Update setup.py
aarushsainukala-oss Dec 30, 2025
02467e3
Update llm_ctrl.launch.py
aarushsainukala-oss Dec 30, 2025
1c6b8bc
Update and rename llm_drive.launch.py to json_to_ackermann.launch.py
aarushsainukala-oss Dec 30, 2025
8d55c82
Update llm_ctrl.launch.py
aarushsainukala-oss Dec 30, 2025
517d9a3
Merge pull request #2 from aarushsainukala-oss/main
Nitish4144 Dec 30, 2025
d04cdf5
msg update in oled eyes
Nitish4144 Dec 30, 2025
f4a4096
removed pip_venv
Nitish4144 Dec 30, 2025
2f5b083
Rename src/llm_ctrl/json_to_ackermann.py to src/llm_ctrl/llm_ctrl/jso…
aarushsainukala-oss Dec 30, 2025
9455df8
Merge branch 'Nitish4144:main' into main
aarushsainukala-oss Dec 30, 2025
121dba8
Merge pull request #3 from aarushsainukala-oss/main
Nitish4144 Dec 30, 2025
316c7a0
Update oled_eyes.py
aarushsainukala-oss Dec 30, 2025
1bc7955
Merge branch 'Nitish4144:main' into main
aarushsainukala-oss Dec 30, 2025
27c8a4f
Merge pull request #4 from aarushsainukala-oss/main
Nitish4144 Dec 30, 2025
f24660d
eod
Nitish4144 Dec 30, 2025
d3b7873
confilcts resolved
Nitish4144 Dec 30, 2025
d0e50b7
Change publisher topic from '/cmd_ackermann' to 'ackermann_cmd'
Nitish4144 Dec 31, 2025
b1922ab
before sim
Nitish4144 Jan 1, 2026
0cfdd6f
Merge branch 'main' of https://github.com/Nitish4144/RC-CAR-ROS2
Nitish4144 Jan 1, 2026
203b523
Create Ackerman_sender.py
Nitish4144 Jan 2, 2026
5aba4f4
Create ackermann_receiver.py
Nitish4144 Jan 2, 2026
9c869a0
Create Arduino_ide.txt
Nitish4144 Jan 2, 2026
e0e2ffe
Update input.py for linux
Nitish4144 Jan 5, 2026
ed4c393
Update controller.py for linux
Nitish4144 Jan 5, 2026
c9c4415
Create requirements,txt for windows
Nitish4144 Jan 5, 2026
feb865a
Refactor joystick handling and add ramping for throttle
Nitish4144 Jan 5, 2026
1d77692
Delete src/manual_ctrl/manual_ctrl/joy_config.py
Nitish4144 Jan 5, 2026
2394f88
Added ramp functioning
Nitish4144 Jan 5, 2026
1ccdc3e
Refactor ReactiveFollowGap node and improve LIDAR handling
na24b064 Jan 20, 2026
f8839d4
Update __init__.py
na24b064 Jan 20, 2026
c47aed5
Bump version from 0.0.0 to 0.0.1
na24b064 Jan 20, 2026
281d660
Create setup.py
na24b064 Jan 20, 2026
ceda969
Update setup.py
na24b064 Jan 22, 2026
7ac5103
Add files via upload
na24b064 Jan 22, 2026
73c0466
Rename executable from reactive_node to reactive_node_cpp
Nitish4144 Jan 22, 2026
db44af6
Refactor simulator to use SimpleSimulator class
Nitish4144 Jan 22, 2026
32d1e77
Lidar (#6) by riyan das
Nitish4144 Jan 22, 2026
012e54a
Update setup.py
Nitish4144 Jan 22, 2026
275e29c
Update manual_ctrl.launch.py
Nitish4144 Jan 22, 2026
d276baf
Add files via upload
na24b064 Jan 23, 2026
131860e
Update ld_ctrl.launch.py
na24b064 Jan 23, 2026
85ed13c
Create lane_detector.py
na24b064 Jan 23, 2026
c2c3a55
Implement lane controller node with PID control
na24b064 Jan 23, 2026
27d19ff
Create lane_detection.launch.py for lane detection
na24b064 Jan 23, 2026
1d81360
Update setup.py
na24b064 Jan 23, 2026
8c861a4
Update package.xml
na24b064 Jan 23, 2026
5e1f4a1
adding gear system
kmanojkr12-bit Jan 25, 2026
4870c30
adding gear system
kmanojkr12-bit Jan 25, 2026
c15dc0e
gears
kmanojkr12-bit Jan 25, 2026
3e97d6f
Refactor convert_speed_to_pwm to include gear parameter
kmanojkr12-bit Jan 25, 2026
6533253
Fix indentation in convert_speed_to_pwm method
kmanojkr12-bit Jan 25, 2026
ab66ddb
gears
kmanojkr12-bit Jan 25, 2026
a3d12ab
Fix indentation and structure in convert_speed_to_pwm
kmanojkr12-bit Jan 25, 2026
253d01e
Update joy_drive.py
kmanojkr12-bit Jan 25, 2026
58bfb66
Refactor convert_speed_to_pwm for gear handling
kmanojkr12-bit Jan 25, 2026
091489c
gears
kmanojkr12-bit Jan 25, 2026
018696e
Refactor joystick control and remove gear management
kmanojkr12-bit Jan 26, 2026
613eb5c
remove gears
kmanojkr12-bit Jan 26, 2026
a2bb225
remove gears
kmanojkr12-bit Jan 26, 2026
58c848d
Refactor speed conversion to PWM without gear
kmanojkr12-bit Jan 26, 2026
7acd6a7
Add files via upload
na24b064 Jan 27, 2026
19fec50
Initialize control parameters and timer in __init__.py
na24b064 Jan 28, 2026
34660dc
Update json_to_ackermann.py
na24b064 Jan 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,3 @@ ros2 run teleop_twist_keyboard teleop_twist_keyboard

Then, press `i` to move forward, `u` and `o` to move forward and turn, `,` to move backwards, `m` and `.` to move backwards and turn, and `k` to stop in the terminal window running the teleop node.

## About Us

S7our Squad team at the University of Ibn Tofail, we work on autonomous systems (cars), led by professor BOUKIR Khawla. Current members composed of OKHADIR Hamza, GHIATI Mustapha, KHATIB Mouad and EL-LOUH Youssef.
737 changes: 737 additions & 0 deletions error

Large diffs are not rendered by default.

Binary file removed img/IntertiaPID.png
Binary file not shown.
Binary file removed img/wall_following_lab_figure_1.png
Binary file not shown.
Binary file removed img/wall_following_lab_figure_2.png
Binary file not shown.
Binary file added master.zip
Binary file not shown.
1 change: 1 addition & 0 deletions src/f1tenth_gym
Submodule f1tenth_gym added at 4fdb9c
8 changes: 4 additions & 4 deletions src/gap_follow/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ project(gap_follow)

# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
Expand All @@ -30,14 +30,14 @@ endforeach()
include_directories(include)

# Create Cpp executable
add_executable(reactive_node src/reactive_node.cpp)
ament_target_dependencies(reactive_node
add_executable(reactive_node_cpp src/reactive_node.cpp)
ament_target_dependencies(reactive_node_cpp
rclcpp geometry_msgs ackermann_msgs nav_msgs sensor_msgs std_msgs
)

# Install Cpp executables
install(TARGETS
reactive_node
reactive_node_cpp
DESTINATION lib/${PROJECT_NAME})

# Install Python modules
Expand Down
1 change: 1 addition & 0 deletions src/gap_follow/gap_follow/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
self.prev_steering = 0.0
146 changes: 146 additions & 0 deletions src/gap_follow/gap_follow/gap_follow_node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#!/usr/bin/env python3

import rclpy
from rclpy.node import Node
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
import math
import numpy as np

class GapFollowNode(Node):
def __init__(self):
super().__init__('gap_follow')

# Subscribe to LiDAR scan
self.scan_subscription = self.create_subscription(
LaserScan,
'/scan',
self.scan_callback,
10
)

# Publish velocity commands
self.velocity_publisher = self.create_publisher(
Twist,
'/cmd_vel',
10
)

# Parameters
self.declare_parameter('linear_velocity', 0.5)
self.declare_parameter('gap_threshold', 0.5) # meters
self.declare_parameter('min_gap_width', 5) # degrees
self.declare_parameter('max_angular_velocity', 1.5)

self.linear_velocity = self.get_parameter('linear_velocity').value
self.gap_threshold = self.get_parameter('gap_threshold').value
self.min_gap_width = self.get_parameter('min_gap_width').value
self.max_angular_velocity = self.get_parameter('max_angular_velocity').value

self.get_logger().info('Gap Follow Node started')
self.get_logger().info(f'Target gap threshold: {self.gap_threshold}m')

def scan_callback(self, msg: LaserScan):
"""
Process LiDAR scan and find largest gap.
"""
try:
# Convert ranges to numpy for easier processing
ranges = np.array(msg.ranges)

# Replace infinities with max range
ranges = np.nan_to_num(ranges, nan=msg.range_max,
posinf=msg.range_max,
neginf=msg.range_max)

# Find gaps (free space where range > threshold)
gaps = self.find_gaps(ranges, msg)

if gaps:
# Get largest gap
largest_gap = max(gaps, key=lambda x: x[1] - x[0])
gap_center = (largest_gap[0] + largest_gap[1]) / 2

# Calculate angle to gap center
gap_angle = (msg.angle_min +
gap_center * msg.angle_increment)

# Generate movement command toward gap
cmd = Twist()
cmd.linear.x = self.linear_velocity
cmd.angular.z = self.saturate_angular_velocity(
gap_angle * 0.5,
self.max_angular_velocity
)

self.velocity_publisher.publish(cmd)

self.get_logger().debug(
f'Gap found at {math.degrees(gap_angle):.2f}°'
)
else:
# No gap found - stop
self.get_logger().warn('No gap found - stopping')
cmd = Twist()
self.velocity_publisher.publish(cmd)

except Exception as e:
self.get_logger().error(f'Error in scan callback: {str(e)}')

def find_gaps(self, ranges, msg):
"""
Find all gaps in range data.
A gap is a continuous region where range > gap_threshold.
Returns list of (start_index, end_index) tuples.
"""
gaps = []
gap_start = None

for i, r in enumerate(ranges):
if r > self.gap_threshold: # Free space
if gap_start is None:
gap_start = i
else: # Obstacle
if gap_start is not None:
# Check gap width
gap_width = i - gap_start
gap_width_degrees = gap_width * math.degrees(msg.angle_increment)

if gap_width_degrees >= self.min_gap_width:
gaps.append((gap_start, i))
gap_start = None

# Handle gap that extends to end of scan
if gap_start is not None:
gap_width = len(ranges) - gap_start
gap_width_degrees = gap_width * math.degrees(msg.angle_increment)

if gap_width_degrees >= self.min_gap_width:
gaps.append((gap_start, len(ranges)))

return gaps

def saturate_angular_velocity(self, angular_vel, max_vel):
"""Limit angular velocity to maximum value."""
if angular_vel > max_vel:
return max_vel
elif angular_vel < -max_vel:
return -max_vel
return angular_vel


def main(args=None):
rclpy.init(args=args)
gap_follow_node = GapFollowNode()

try:
rclpy.spin(gap_follow_node)
except KeyboardInterrupt:
pass
finally:
gap_follow_node.destroy_node()
rclpy.shutdown()


if __name__ == '__main__':
main()
1 change: 1 addition & 0 deletions src/gap_follow/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<depend>sensor_msgs</depend>
<depend>ackermann_msgs</depend>
<depend>geometry_msgs</depend>
<depend>ydlidar_ros2_driver</depend>

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
Expand Down
176 changes: 129 additions & 47 deletions src/gap_follow/scripts/reactive_node.py
Original file line number Diff line number Diff line change
@@ -1,72 +1,154 @@
#!/usr/bin/env python3

import rclpy
from rclpy.node import Node

import numpy as np

from sensor_msgs.msg import LaserScan
from ackermann_msgs.msg import AckermannDriveStamped, AckermannDrive
from ackermann_msgs.msg import AckermannDriveStamped


class ReactiveFollowGap(Node):
"""
Implement Wall Following on the car
This is just a template, you are free to implement your own node!
"""

def __init__(self):
super().__init__('reactive_node')
# Topics & Subs, Pubs
lidarscan_topic = '/scan'
drive_topic = '/drive'
super().__init__('reactive_follow_gap')

# Topics
self.scan_topic = '/scan'
self.drive_topic = '/drive'

# ===== CAR + LIDAR TUNING (FOR YOUR SETUP) =====
self.max_range = 4.0 # meters (X2 reliable range)
self.bubble_radius = 0.45 # meters (1/10 car safety)
self.max_steering_angle = 0.34 # rad (~19.5 deg)
self.steering_gain = 0.9
self.front_fov_deg = 70 # +- degrees
self.prev_steering = 0.0

# TODO: Subscribe to LIDAR
# TODO: Publish to drive
# ROS interfaces
self.scan_sub = self.create_subscription(
LaserScan,
self.scan_topic,
self.lidar_callback,
10
)

self.drive_pub = self.create_publisher(
AckermannDriveStamped,
self.drive_topic,
10
)

self.get_logger().info("Follow-the-Gap initialized (YDLIDAR X2, 1/10 RC)")

# ------------------------------------------------
def preprocess_lidar(self, ranges):
""" Preprocess the LiDAR scan array. Expert implementation includes:
1.Setting each value to the mean over some window
2.Rejecting high values (eg. > 3m)
"""
proc_ranges = ranges
return proc_ranges

def find_max_gap(self, free_space_ranges):
""" Return the start index & end index of the max gap in free_space_ranges
"""
return None

def find_best_point(self, start_i, end_i, ranges):
"""Start_i & end_i are start and end indicies of max-gap range, respectively
Return index of best point in ranges
Naive: Choose the furthest point within ranges and go there
"""
return None
ranges = np.array(ranges)
ranges[np.isnan(ranges)] = 0.0
ranges[np.isinf(ranges)] = self.max_range
ranges = np.clip(ranges, 0.0, self.max_range)
return ranges

# ------------------------------------------------
def find_max_gap(self, ranges):
gaps = []
start = None

for i, r in enumerate(ranges):
if r > 0 and start is None:
start = i
elif r == 0 and start is not None:
gaps.append((start, i - 1))
start = None

if start is not None:
gaps.append((start, len(ranges) - 1))

if not gaps:
return None, None

return max(gaps, key=lambda g: g[1] - g[0])

# ------------------------------------------------
def find_best_point(self, start, end, ranges):
segment = ranges[start:end + 1]
return start + np.argmax(segment)

# ------------------------------------------------
def lidar_callback(self, data):
""" Process each LiDAR scan as per the Follow Gap algorithm & publish an AckermannDriveStamped Message
"""
ranges = data.ranges
proc_ranges = self.preprocess_lidar(ranges)

# TODO:
#Find closest point to LiDAR
ranges = self.preprocess_lidar(data.ranges)

# ===== FRONT-ONLY FOV =====
front_angle = np.deg2rad(self.front_fov_deg)

start_i = int((-front_angle - data.angle_min) / data.angle_increment)
end_i = int(( front_angle - data.angle_min) / data.angle_increment)

start_i = max(start_i, 0)
end_i = min(end_i, len(ranges) - 1)

ranges = ranges[start_i:end_i]

# ===== FIND CLOSEST OBSTACLE =====
closest_idx = np.argmin(ranges)
closest_dist = ranges[closest_idx]

# ===== DISTANCE-AWARE BUBBLE =====
if closest_dist > 0.0:
bubble_angle = int(
self.bubble_radius /
(closest_dist * data.angle_increment)
)
bubble_start = max(0, closest_idx - bubble_angle)
bubble_end = min(len(ranges) - 1, closest_idx + bubble_angle)
ranges[bubble_start:bubble_end] = 0.0

#Eliminate all points inside 'bubble' (set them to zero)
# ===== FIND GAP =====
gap_start, gap_end = self.find_max_gap(ranges)
if gap_start is None:
return

#Find max length gap
best_idx = self.find_best_point(gap_start, gap_end, ranges)

#Find the best point in the gap
# ===== STEERING =====
angle = (
data.angle_min +
(best_idx + start_i) * data.angle_increment
) * self.steering_gain

#Publish Drive message
angle = np.clip(angle,
-self.max_steering_angle,
self.max_steering_angle)

# Steering smoothing (ESC & traction safety)
angle = 0.7 * self.prev_steering + 0.3 * angle
self.prev_steering = angle

# ===== SPEED CONTROL (CRITICAL FOR 4300KV) =====
min_dist = np.min(ranges)

if min_dist < 0.8:
speed = 0.7
elif min_dist < 1.2:
speed = 1.1
else:
speed = 1.6

# ===== PUBLISH =====
drive_msg = AckermannDriveStamped()
drive_msg.drive.steering_angle = angle
drive_msg.drive.speed = speed

self.drive_pub.publish(drive_msg)


def main(args=None):
rclpy.init(args=args)
print("WallFollow Initialized")
reactive_node = ReactiveFollowGap()
rclpy.spin(reactive_node)

reactive_node.destroy_node()
node = ReactiveFollowGap()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()


if __name__ == '__main__':
main()
main()
Loading