Skip to content

Instantly share code, notes, and snippets.

@anasAlsalol
Created January 25, 2026 14:27
Show Gist options
  • Select an option

  • Save anasAlsalol/c47e2f62166bd12304c5056698701a23 to your computer and use it in GitHub Desktop.

Select an option

Save anasAlsalol/c47e2f62166bd12304c5056698701a23 to your computer and use it in GitHub Desktop.
Attached Files: analysis_report.md, statistics.txt, analyze.py, lidar_collector.py.

TurtleBot3 LIDAR Data Analysis Report

1. Executive Summary

  • Robot: TurtleBot3 burger
  • Data Collected: 137 scans
  • Collection Duration: 30.0 seconds
  • Data Quality: 100.0% valid measurements

2. Key Statistics

Metric Value
Total Scans 137
Total Measurements 49320
Valid Measurements 49320
Validity Rate 100.0%
Mean Distance 1.903 m
Std Deviation 0.872 m
Minimum 0.322 m
Maximum 3.395 m

3. Environmental Analysis

  • Close obstacles (< 1m): 12533 measurements (25.4%)
  • Mid-range (1-3m): 33044 measurements (67.0%)
  • Far obstacles (> 3m): 3743 measurements (7.6%)

4. Generated Visualizations

  1. histogram.png - Distribution of range measurements
  2. sample_scan.png - Cartesian view of a single scan
  3. time_series.png - Forward distance over time
  4. data_quality.png - Valid vs invalid measurements

5. Conclusions

  1. Successfully collected and analyzed TurtleBot3 LIDAR data
  2. LIDAR provides consistent 360° environmental sensing
  3. Data shows clear navigation patterns in simulation
  4. Foundation established for future robotics perception tasks

Report generated on: 2026-01-22 17:09:36

#!/usr/bin/env python3
"""
TurtleBot3 Assignment Analysis - Simple & Reliable
Complete analysis script used for this assignment
"""
import pandas as pd
import os
import glob
import math
print("="*60)
print("TURTLEBOT3 ASSIGNMENT ANALYSIS")
print("="*60)
# Find data directory
data_dirs = glob.glob('/home/user/tb3_data_*')
if not data_dirs:
print("❌ No data found! Run data collection first.")
exit()
data_dir = sorted(data_dirs)[-1]
print(f"📁 Data directory: {data_dir}")
# Load and analyze data
csv_file = os.path.join(data_dir, 'lidar_data.csv')
data_lines = []
with open(csv_file, 'r') as f:
for line in f:
if not line.strip().startswith('#'):
data_lines.append(line.strip())
# Parse and process
header = data_lines[0].split(',')
data = []
for line in data_lines[1:]:
try:
row = [float(x) for x in line.split(',')]
data.append(row)
except:
continue
df = pd.DataFrame(data, columns=header)
print(f"✅ Loaded {len(df)} scans")
# Statistical analysis
beam_cols = [col for col in df.columns if col != 'timestamp']
num_beams = len(beam_cols)
all_values = df[beam_cols].values.flatten()
valid_values = [x for x in all_values if 0.1 < x < 30.0]
print("\n" + "="*60)
print("STATISTICAL ANALYSIS")
print("="*60)
print(f"Total measurements: {len(all_values):,}")
print(f"Valid measurements: {len(valid_values):,}")
print(f"Data quality: {len(valid_values)/len(all_values)*100:.1f}%")
# Calculate statistics
if valid_values:
mean_val = sum(valid_values) / len(valid_values)
min_val = min(valid_values)
max_val = max(valid_values)
variance = sum((x - mean_val) ** 2 for x in valid_values) / len(valid_values)
std_dev = math.sqrt(variance)
print(f"\n📈 Range Statistics:")
print(f" Mean distance: {mean_val:.3f} m")
print(f" Std deviation: {std_dev:.3f} m")
print(f" Minimum: {min_val:.3f} m")
print(f" Maximum: {max_val:.3f} m")
# Generate report and visualizations
try:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
# Create analysis directory
analysis_dir = os.path.join(data_dir, 'analysis')
os.makedirs(analysis_dir, exist_ok=True)
# Plot 1: Sample scan
if len(df) > 0:
plt.figure(figsize=(10, 10))
sample = df.iloc[0]
ranges = sample[beam_cols].values
# Convert to Cartesian
angles = [i * (2 * math.pi / num_beams) - math.pi for i in range(num_beams)]
x = ranges * [math.cos(a) for a in angles]
y = ranges * [math.sin(a) for a in angles]
plt.scatter(x, y, s=5, alpha=0.6, color='blue')
plt.scatter(0, 0, color='red', s=100, marker='^', label='TurtleBot3')
plt.title('Sample LIDAR Scan (360° View)')
plt.xlabel('X (m)')
plt.ylabel('Y (m)')
plt.axis('equal')
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
scan_file = os.path.join(analysis_dir, 'sample_scan.png')
plt.savefig(scan_file, dpi=100)
plt.close()
print(f"✅ Sample scan: {scan_file}")
# Plot 2: Histogram
if valid_values:
plt.figure(figsize=(10, 6))
plt.hist(valid_values, bins=50, edgecolor='black', alpha=0.7)
plt.title('LIDAR Range Distribution')
plt.xlabel('Distance (m)')
plt.ylabel('Frequency')
plt.grid(True, alpha=0.3)
plt.tight_layout()
hist_file = os.path.join(analysis_dir, 'histogram.png')
plt.savefig(hist_file, dpi=100)
plt.close()
print(f"✅ Histogram: {hist_file}")
# Plot 3: Data quality
plt.figure(figsize=(8, 6))
labels = ['Valid', 'Invalid']
sizes = [len(valid_values), len(all_values) - len(valid_values)]
colors = ['#4CAF50', '#F44336']
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', startangle=90)
plt.title('Data Quality\nTotal measurements: {:,}'.format(len(all_values)))
plt.tight_layout()
quality_file = os.path.join(analysis_dir, 'data_quality.png')
plt.savefig(quality_file, dpi=100)
plt.close()
print(f"✅ Data quality: {quality_file}")
except ImportError:
print("⚠️ Matplotlib not available, skipping plots")
except Exception as e:
print(f"⚠️ Could not create plots: {e}")
print("\n" + "="*60)
print("ANALYSIS COMPLETE!")
print("="*60)
#!/usr/bin/env python3
"""
TurtleBot3 LIDAR Data Collector - Assignment Version
Simple, reliable, and tested implementation used in this assignment
"""
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import LaserScan
import csv
import time
import os
from datetime import datetime
class TurtleBot3Collector(Node):
def __init__(self):
super().__init__('tb3_collector')
# Subscribe to LIDAR topic
self.subscription = self.create_subscription(
LaserScan,
'/scan',
self.scan_callback,
10)
# Data storage and parameters
self.scan_data = []
self.start_time = None
self.collection_time = 30 # seconds
self.is_collecting = False
# Create timestamped data directory
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
self.data_dir = f"/home/user/tb3_data_{timestamp}"
os.makedirs(self.data_dir, exist_ok=True)
# Initialization message
print("\n" + "="*60)
print("TURTLEBOT3 DATA COLLECTOR - ASSIGNMENT")
print("="*60)
print("Instructions:")
print("1. Robot simulation should be running")
print("2. Open another terminal for robot control")
print("3. Drive robot while data is collected")
print("="*60)
print(f"Data will be saved to: {self.data_dir}")
print("Starting in 5 seconds...")
print("="*60)
time.sleep(5)
self.start_time = time.time()
self.is_collecting = True
print("🎯 COLLECTION STARTED! Drive the robot now!")
def scan_callback(self, msg):
if not self.is_collecting:
return
current_time = time.time() - self.start_time
# Stop after specified duration
if current_time > self.collection_time:
self.is_collecting = False
self.save_data()
print(f"\n✅ Collection complete! ({len(self.scan_data)} scans)")
rclpy.shutdown()
return
# Store scan data
scan = {
'timestamp': current_time,
'ranges': list(msg.ranges),
'angle_min': msg.angle_min,
'angle_max': msg.angle_max,
'range_min': msg.range_min,
'range_max': msg.range_max
}
self.scan_data.append(scan)
# Progress updates
if len(self.scan_data) % 20 == 0:
progress = (current_time / self.collection_time) * 100
print(f"📊 Progress: {progress:5.1f}% | Scans: {len(self.scan_data)}")
def save_data(self):
"""Save collected data to CSV and summary files"""
print("\n💾 Saving data...")
# Save as CSV
csv_file = os.path.join(self.data_dir, 'lidar_data.csv')
with open(csv_file, 'w', newline='') as f:
writer = csv.writer(f)
# Metadata header
writer.writerow(['# TurtleBot3 LIDAR Data - Assignment'])
writer.writerow(['# Date:', datetime.now().strftime('%Y-%m-%d')])
writer.writerow(['# Robot:', os.environ.get('TURTLEBOT3_MODEL', 'burger')])
writer.writerow(['# Scans:', len(self.scan_data)])
writer.writerow(['# Duration:', f'{self.collection_time}s'])
# Data header
if self.scan_data:
num_beams = len(self.scan_data[0]['ranges'])
header = ['timestamp'] + [f'beam_{i}' for i in range(num_beams)]
writer.writerow(header)
# Data rows
for scan in self.scan_data:
row = [scan['timestamp']] + scan['ranges']
writer.writerow(row)
# Save summary
summary_file = os.path.join(self.data_dir, 'summary.txt')
with open(summary_file, 'w') as f:
f.write("ASSIGNMENT DATA COLLECTION SUMMARY\n")
f.write("="*50 + "\n\n")
f.write(f"Robot: TurtleBot3 {os.environ.get('TURTLEBOT3_MODEL', 'burger')}\n")
f.write(f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"Duration: {self.collection_time} seconds\n")
f.write(f"Total scans: {len(self.scan_data)}\n")
f.write(f"Scan rate: {len(self.scan_data)/self.collection_time:.2f} Hz\n")
f.write(f"Beams per scan: {len(self.scan_data[0]['ranges']) if self.scan_data else 0}\n")
f.write(f"LIDAR FOV: 360°\n")
f.write(f"Data saved to: {self.data_dir}\n")
print(f"✅ CSV saved: {csv_file}")
print(f"✅ Summary saved: {summary_file}")
print("\n🎉 DATA COLLECTION COMPLETE!")
def main(args=None):
rclpy.init(args=args)
collector = TurtleBot3Collector()
rclpy.spin(collector)
rclpy.shutdown()
if __name__ == '__main__':
main()
STATISTICS SUMMARY
========================================
Total Scans: 137
Total Measurements: 49320
Valid Measurements: 49320
Validity Rate: 100.0%
Mean Distance: 1.903 m
Std Deviation: 0.872 m
Minimum: 0.322 m
Maximum: 3.395 m
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment