0% found this document useful (0 votes)
4 views23 pages

TurtleBot3 Image Drawing Guide

The document outlines a project to convert a TurtleBot3 Burger robot into an autonomous image drawing system using a servo-controlled pen. It details the hardware setup, G-code pipeline, and ROS control architecture, including the necessary components and software tools for image processing and motion execution. Additionally, it provides calibration procedures to ensure accurate drawing performance.

Uploaded by

adityagaddam1905
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views23 pages

TurtleBot3 Image Drawing Guide

The document outlines a project to convert a TurtleBot3 Burger robot into an autonomous image drawing system using a servo-controlled pen. It details the hardware setup, G-code pipeline, and ROS control architecture, including the necessary components and software tools for image processing and motion execution. Additionally, it provides calibration procedures to ensure accurate drawing performance.

Uploaded by

adityagaddam1905
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

TurtleBot3 Burger — Autonomous Image Drawing System

TurtleBot3 Burger
Autonomous Image Drawing System

Complete Project Guide


Hardware Setup | G-code Pipeline | ROS Control | Challenges & Solutions

ROBOTIS TurtleBot3 Burger Platform


ROS Noetic / ROS2 Humble | Raspberry Pi 4 | OpenCR

Confidential Project Guide | Page 1


TurtleBot3 Burger — Autonomous Image Drawing System

1. Project Overview
This project transforms a TurtleBot3 Burger differential-drive robot into an autonomous drawing
machine. A servo-controlled pen mount is attached to the rear of the robot. A given image is
processed on a PC, converted into G-code waypoints, and transmitted to the robot. A ROS
node on the robot then translates each waypoint into rotate-then-drive motion commands while
simultaneously actuating the servo to lift or lower the pen at the correct moments.

1.1 System at a Glance

Component Description

Robot Platform TurtleBot3 Burger (differential drive, wheel encoder odometry)

Compute Raspberry Pi 4 (onboard) + PC (offline processing)

Pen Actuator SG90 micro servo mounted to rear chassis

Motion Planning Rotate-then-Drive waypoint follower via /cmd_vel

Path Source G-code (.gcode) generated from raster or vector images

ROS Version ROS Noetic (Python 3) or ROS2 Humble

Drawing Surface Hard flat surface: whiteboard, large paper on floor

1.2 Full Pipeline

Input Image (PNG/JPG/SVG)


|
v
[PC] Preprocessing --> Edge detection / vectorization
|
v
[PC] G-code Generator --> .gcode file (X, Y, PenUp/Down commands)
|
(copy to robot via SCP / USB)
|
v
[Robot] gcode_parser node --> waypoint list
|
+-----> servo_control node (M3 = pen down, M5 = pen up)

Confidential Project Guide | Page 2


TurtleBot3 Burger — Autonomous Image Drawing System

|
v
[Robot] motion_executor node --> /cmd_vel (rotate + drive)
|
v
[Robot] odometry tracker --> /odom (position feedback)

Confidential Project Guide | Page 3


TurtleBot3 Burger — Autonomous Image Drawing System

2. Hardware Setup
2.1 Bill of Materials

Item Specification Purpose

SG90 / MG90S Servo 5V, 180 degree, 1.8kg-cm Lifts and lowers the pen

Pen / Marker Thin barrel, 8-12 mm dia. Drawing implement

3D Printed Bracket Custom rear mount Holds servo + pen vertically

Spring (optional) Light compression spring Consistent pen pressure

Jumper wires Female-to-female GPIO to servo signal

Raspberry Pi GPIO BCM pin 18 (PWM0) 50 Hz PWM servo control

USB-C power bank 10,000 mAh min. Powers RPi + servo

2.2 Servo Wiring


The SG90 servo has three wires. Connect them to the Raspberry Pi as follows:

Servo Wire Raspberry Pi Pin

Brown / Black (GND) Pin 6 (GND)

Red (VCC) Pin 4 (5V)

Orange / Yellow (Signal) GPIO 18 (BCM, PWM0)

⚠ Current Warning
Drawing more than ~500 mA through the RPi 5V pin can destabilize the board. If the servo jitters
under load, power it from an external 5V BEC or a small dedicated power module, sharing only GND
with the Pi.

2.3 Pen Mount Design Guidelines


• Mount the pen strictly vertical — any tilt will cause line offset as the robot turns.
• Centre the pen over the robot's midpoint laterally to simplify coordinate math.

Confidential Project Guide | Page 4


TurtleBot3 Burger — Autonomous Image Drawing System

• Position the pen tip exactly at a known, measured offset from the robot's rotation centre
(usually the midpoint between the two drive wheels). Record this as TF offset in your
ROS setup.
• Add a light spring above the pen collar so the pen pressure self-regulates on uneven
paper.
• Servo travel: 0 degrees = pen UP (raised ~15 mm off surface), 90 degrees = pen DOWN
(touching surface).

2.4 Surface Preparation


• Use a rigid, flat surface — a sheet of MDF board with paper taped on top works well.
• Tape the paper firmly; any paper movement will corrupt the drawing.
• Mark a fixed HOME position at the bottom-left of the paper, and always place the robot
at this origin before starting.

Confidential Project Guide | Page 5


TurtleBot3 Burger — Autonomous Image Drawing System

3. Image to G-code Pipeline (PC Side)


3.1 Recommended Tools

Tool Role

OpenCV (Python) Preprocessing, edge detection, contour extraction

Potrace / Autotrace Bitmap to vector (SVG) conversion

vpype + vpype-gcode SVG path optimisation and G-code export

Inkscape + Gcodetools GUI-based alternative for the full pipeline

pygcode (Python) G-code parsing and manipulation

3.2 Step-by-Step Processing


Step 1 — Preprocess the Image
# PSEUDOCODE: image_preprocessor.py

FUNCTION preprocess(image_path, output_size_mm=(200, 200)):


img = load_image(image_path)
img = convert_to_grayscale(img)
img = apply_gaussian_blur(img, kernel=5) # reduce noise
img = apply_canny_edge_detection(img,
low_threshold=50, high_threshold=150)
img = dilate(img, iterations=1) # thicken thin edges
img = resize_to_physical_mm(img, output_size_mm)
RETURN img

Step 2 — Extract Contours / Vector Paths


# PSEUDOCODE: contour_extractor.py

FUNCTION extract_paths(edge_image):
contours = find_contours(edge_image, mode=EXTERNAL+TREE)
paths = []
FOR each contour IN contours:
IF arc_length(contour) < MIN_LENGTH: CONTINUE # skip noise

Confidential Project Guide | Page 6


TurtleBot3 Burger — Autonomous Image Drawing System

simplified = douglas_peucker(contour, epsilon=0.5)


path = convert_to_mm_coordinates(simplified)
[Link](path)
paths = sort_by_nearest_neighbour(paths) # TSP optimisation
RETURN paths

Step 3 — Write G-code


# PSEUDOCODE: gcode_writer.py

FUNCTION write_gcode(paths, output_file):


OPEN output_file FOR WRITING
WRITE 'G21' # units in mm
WRITE 'G90' # absolute coordinates
WRITE 'M5' # pen UP (safe start)
WRITE 'G0 X0 Y0' # move to origin

FOR each path IN paths:


first_point = path[0]
WRITE 'G0 X{first_point.x} Y{first_point.y}' # rapid move to start
WRITE 'M3' # pen DOWN
FOR each point IN path[1:]:
WRITE 'G1 X{point.x} Y{point.y} F{FEED_RATE}'
WRITE 'M5' # pen UP

WRITE 'G0 X0 Y0' # return to origin


WRITE 'M5' # pen UP (final)
WRITE 'M2' # program end
CLOSE output_file

ℹ G-code Command Reference


G0 = Rapid move (pen up travel). G1 = Feed move (pen down drawing). M3 = Pen DOWN (servo to
draw angle). M5 = Pen UP (servo to raised angle). G21 = millimetre units. G90 = absolute positioning.
M2 = End of program.

3.3 Path Optimisation (Minimising Pen Lifts)


Every pen lift introduces position error when the robot re-approaches the paper. Minimise lifts
by:

Confidential Project Guide | Page 7


TurtleBot3 Burger — Autonomous Image Drawing System

1. Use a nearest-neighbour TSP heuristic to reorder path start/end points.


2. Connect paths that are within a threshold distance without lifting (stitching).
3. Use the vpype reloop and linesort commands if using SVG-based workflow.

# PSEUDOCODE: path_optimiser.py

FUNCTION optimise_paths(paths, stitch_threshold_mm=2.0):


ordered = []
remaining = copy(paths)
current_pos = (0, 0)

WHILE remaining is not empty:


nearest = find_nearest_path_start(current_pos, remaining)
[Link](nearest)
[Link](nearest)
current_pos = nearest.last_point

# Stitch: if next nearest start is very close, skip pen lift


IF remaining:
next_nearest = find_nearest_path_start(current_pos, remaining)
IF distance(current_pos, next_nearest.start) < stitch_threshold_mm:
next_nearest.prepend_travel_line(from=current_pos)
next_nearest.no_pen_lift = True

RETURN ordered

Confidential Project Guide | Page 8


TurtleBot3 Burger — Autonomous Image Drawing System

4. ROS Node Architecture


4.1 Node Overview

Node Topics Used Responsibility

gcode_parser Publishes: /waypoints Reads .gcode, emits waypoint + pen


commands

motion_executor Sub: /waypoints, /odom Pub: Rotate-then-drive to each waypoint


/cmd_vel

servo_control Sub: /pen_state Drives GPIO PWM for pen up/down

pose_tracker Sub: /odom Pub: /robot_pose Maintains X, Y, theta from odometry

4.2 Node 1 — G-code Parser


# PSEUDOCODE: gcode_parser_node.py

IMPORT rospy, Waypoint, PenState

waypoint_pub = Publisher('/waypoints', Waypoint)


pen_pub = Publisher('/pen_state', PenState)

FUNCTION parse_and_publish(gcode_file):
FOR each line IN read_lines(gcode_file):
line = strip_comments(line).strip()
IF line == '': CONTINUE

IF [Link]('M3'): # pen DOWN


pen_pub.publish(state='DOWN')
WAIT for servo_ack # optional handshake

ELIF [Link]('M5'): # pen UP


pen_pub.publish(state='UP')
WAIT for servo_ack

ELIF [Link]('G0') or [Link]('G1'):


x, y = parse_xy(line) # extract X__ Y__ values
wpt = Waypoint(x=x/1000.0, # mm -> metres

Confidential Project Guide | Page 9


TurtleBot3 Burger — Autonomous Image Drawing System

y=y/1000.0,
is_rapid = [Link]('G0'))
waypoint_pub.publish(wpt)
WAIT for motion_done_ack # block until robot arrives

[Link]('G-code execution complete')

4.3 Node 2 — Motion Executor


# PSEUDOCODE: motion_executor_node.py

IMPORT rospy, Twist, Odometry, Waypoint

cmd_pub = Publisher('/cmd_vel', Twist)


pose = Pose(x=0, y=0, theta=0) # current robot pose

CONSTANTS:
LINEAR_SPEED = 0.05 # m/s (slow for accuracy)
ANGULAR_SPEED = 0.3 # rad/s
XY_TOLERANCE = 0.005 # 5 mm position tolerance
ANGLE_TOL = 0.02 # radians (~1 degree)

FUNCTION on_odometry(odom_msg):
pose.x = odom_msg.[Link].x
pose.y = odom_msg.[Link].y
[Link] = quaternion_to_yaw(odom_msg.[Link])

FUNCTION move_to_waypoint(wpt):
# ── Phase 1: Rotate to face the target ──
dx = wpt.x - pose.x
dy = wpt.y - pose.y
target_angle = atan2(dy, dx)
angle_diff = normalise_angle(target_angle - [Link])

WHILE abs(angle_diff) > ANGLE_TOL:


cmd = Twist()
[Link].z = sign(angle_diff) * ANGULAR_SPEED
cmd_pub.publish(cmd)
SLEEP(0.05)

Confidential Project Guide | Page 10


TurtleBot3 Burger — Autonomous Image Drawing System

angle_diff = normalise_angle(target_angle - [Link])


STOP_ROBOT()

# ── Phase 2: Drive straight to target ──


distance = sqrt(dx*dx + dy*dy)
WHILE distance > XY_TOLERANCE:
cmd = Twist()
[Link].x = min(LINEAR_SPEED,
distance * 2.0) # slow down near target
cmd_pub.publish(cmd)
SLEEP(0.05)
dx = wpt.x - pose.x
dy = wpt.y - pose.y
distance = sqrt(dx*dx + dy*dy)
STOP_ROBOT()
PUBLISH motion_done_ack

FUNCTION STOP_ROBOT():
cmd_pub.publish(Twist()) # all zeros = full stop

4.4 Node 3 — Servo Control


# PSEUDOCODE: servo_control_node.py

IMPORT rospy, pigpio, PenState

SERVO_PIN = 18 # BCM GPIO 18


FREQ = 50 # Hz
PULSE_UP = 1500 # microseconds (pen raised ~15 mm)
PULSE_DOWN = 1900 # microseconds (pen on paper)
MOVE_DELAY = 0.4 # seconds to complete servo travel

pi = [Link]() # connect to pigpiod daemon

FUNCTION on_pen_state(msg):
IF [Link] == 'DOWN':
pi.set_servo_pulsewidth(SERVO_PIN, PULSE_DOWN)
SLEEP(MOVE_DELAY) # wait for servo to settle
PUBLISH servo_ack

Confidential Project Guide | Page 11


TurtleBot3 Burger — Autonomous Image Drawing System

ELIF [Link] == 'UP':


pi.set_servo_pulsewidth(SERVO_PIN, PULSE_UP)
SLEEP(MOVE_DELAY)
PUBLISH servo_ack

[Link]('/pen_state', PenState, on_pen_state)

# Calibration helper (run separately before drawing):


FUNCTION calibrate_servo():
FOR pulse IN [1000, 1500, 1900, 2000]:
pi.set_servo_pulsewidth(SERVO_PIN, pulse)
PRINT 'Pulse:', pulse, ' pen position?'
INPUT 'Press Enter for next...'

Confidential Project Guide | Page 12


TurtleBot3 Burger — Autonomous Image Drawing System

5. Calibration Procedures
5.1 Odometry Wheel Calibration
TurtleBot3 uses encoder counts and nominal wheel radius to estimate pose. Even small errors
in wheel radius or wheelbase cause significant drift over a drawing. Run this calibration before
the first drawing session.

# PSEUDOCODE: odometry_calibration.py

CONSTANTS:
NOMINAL_RADIUS = 0.033 # metres (TurtleBot3 Burger spec)
NOMINAL_WHEELBASE = 0.160 # metres

PROCEDURE calibrate_linear():
# Drive exactly 1 metre (measured with tape measure on floor)
PLACE robot at tape mark 0
DRIVE_FORWARD(target_odom_dist=1.0)
actual_dist = MEASURE_WITH_TAPE()
correction_factor = actual_dist / 1.0
new_wheel_radius = NOMINAL_RADIUS * correction_factor
UPDATE turtlebot3_burger.yaml: wheel_radius = new_wheel_radius

PROCEDURE calibrate_angular():
# Rotate exactly 360 degrees and measure real angle
PLACE robot, mark orientation
ROTATE(target_odom_angle = 2*PI)
actual_angle = MEASURE_WITH_PROTRACTOR()
correction_factor = actual_angle / (2*PI)
new_wheelbase = NOMINAL_WHEELBASE * correction_factor
UPDATE turtlebot3_burger.yaml: wheel_separation = new_wheelbase

5.2 Drawing a Calibration Square


Before attempting any real image, command the robot to draw a 100 mm x 100 mm square.
Measure the actual square with a ruler. Adjust scale factors in your G-code generator
accordingly.

# PSEUDOCODE: calibration_square.py

Confidential Project Guide | Page 13


TurtleBot3 Burger — Autonomous Image Drawing System

SIDE = 0.10 # 100 mm in metres

waypoints = [(0,0), (SIDE,0), (SIDE,SIDE), (0,SIDE), (0,0)]

FOR pt IN waypoints:
move_to_waypoint(pt)

# After drawing:
# Measure actual width -> scale_x = measured_x / SIDE
# Measure actual height -> scale_y = measured_y / SIDE
# Apply scale_x, scale_y corrections in gcode_writer.py

5.3 Servo Calibration


• Run calibrate_servo() and move the pen holder by hand.
• Record the pulse width where the pen JUST lifts clear of the paper.
• Record the pulse width where the pen rests with gentle consistent pressure.
• Store these two values as PULSE_UP and PULSE_DOWN in your config.

Confidential Project Guide | Page 14


TurtleBot3 Burger — Autonomous Image Drawing System

6. Challenges and How to Overcome Them


6.1 Odometry Drift ★ Biggest Challenge
Wheel slip, floor inconsistencies, and encoder quantisation cause cumulative position error.
Over a 500 mm drawing, uncorrected drift can reach 20-40 mm.

Mitigation Strategy Implementation Expected Improvement

Slow linear speed Set linear.x to 0.04-0.06 m/s Reduces wheel slip significantly

Small drawing area Keep paths within 300 x 300 mm Less distance = less accumulated
error

Wheel calibration Run linear + angular calib routine Cuts baseline error by ~60-70%

Low-vibration surface Smooth hard floor or rigid board Eliminates surface-induced slip

Frequent pen lifts Break drawing into small segments Error does not compound within
segment

⚠ No Absolute Position Feedback


The TurtleBot3 Burger has no external localisation (no camera, no lidar-SLAM for this use case). All
positioning is dead-reckoning only. This is the fundamental constraint of this project. Keep drawings
simple and small.

6.2 Differential Drive vs. Cartesian Motion


Unlike a CNC machine, the robot cannot move diagonally in a straight line natively. It must
rotate first, then drive straight. This rotate-then-drive approach introduces a small positional
error at every waypoint if the rotation is not precise.
• Solution: After each rotation, wait 200 ms for oscillations to settle before driving.
• Solution: Use a PD controller on angular velocity rather than bang-bang control.
• Solution: For dense paths, use arc interpolation (G2/G3) for smooth curves rather than
many short G1 segments.

# PSEUDOCODE: smooth_angular_control (PD controller)

Kp = 1.5 # proportional gain


Kd = 0.3 # derivative gain
prev_error = 0

FUNCTION rotate_to_angle(target_theta):

Confidential Project Guide | Page 15


TurtleBot3 Burger — Autonomous Image Drawing System

WHILE True:
error = normalise_angle(target_theta - [Link])
IF abs(error) < ANGLE_TOL: BREAK
derivative = (error - prev_error) / dt
omega = Kp * error + Kd * derivative
omega = clamp(omega, -MAX_OMEGA, MAX_OMEGA)
[Link].z = omega
cmd_pub.publish(cmd)
prev_error = error
SLEEP(dt)
STOP_ROBOT()

6.3 Pen Pressure Inconsistency


A rigid pen mount means the pen either presses too hard (drags paper) or lifts off on slight floor
bumps.
• Solution: Use a spring-loaded mount — the pen floats 5 mm and a compression spring
maintains gentle contact force.
• Solution: Set servo DOWN angle so the pen mount rests at neutral spring compression.
• Solution: Use a felt-tip or rollerball pen rather than a ballpoint (requires less pressure).

6.4 Communication Latency / Timing


The servo must fully complete its motion before the robot starts moving, and vice versa.
Unsynchronised movement and pen actuation causes smeared lines.
• Solution: Use the acknowledgement / blocking scheme described in the node
pseudocode — the G-code parser waits for servo_ack before publishing the next
waypoint.
• Solution: Add MOVE_DELAY = 0.4 s after every servo command and verify
experimentally.
• Solution: In ROS2, use Action servers for motion and servo nodes rather than topic-
based fire-and-forget.

6.5 RPi GPIO Servo Jitter


Software PWM on the Raspberry Pi produces jitter because the OS scheduler interrupts the
signal, causing the servo to twitch randomly.
# SOLUTION: Use pigpiod hardware-timed PWM (no jitter)

# Terminal:

Confidential Project Guide | Page 16


TurtleBot3 Burger — Autonomous Image Drawing System

sudo pigpiod # start daemon

# Python (in servo_control_node.py):


import pigpio
pi = [Link]()
pi.set_servo_pulsewidth(SERVO_PIN, PULSE_UP) # hardware PWM

# DO NOT use [Link] software PWM for servo control:


# import [Link] as GPIO # AVOID for servo
# [Link](18, [Link]) # jitter-prone
# pwm = [Link](18, 50) # AVOID

6.6 Image Complexity vs. Robot Capability


Highly detailed images produce thousands of short G-code segments. Each segment requires a
rotate-then-drive cycle, making execution extremely slow and error-prone.
• Recommendation: Simplify images to under 500 total path segments for a first build.
• Recommendation: Use simple line art, logos, or hand-traced sketches rather than
photographs.
• Recommendation: Apply aggressive epsilon in Douglas-Peucker simplification (try
epsilon = 1.5 to 3.0 mm).
• Recommendation: Use vpype's splitall and linesimplify commands to pre-clean paths.

Image Type Feasibility Rating

Simple logo / geometric shape Excellent — ideal starting point

Hand-drawn cartoon outline Very Good

Typography / bold text Good

Line art from a photo Moderate — needs heavy simplification

Portrait or detailed photograph Difficult — requires many segments, high drift risk

Photo-realistic image Not recommended for this platform

Confidential Project Guide | Page 17


TurtleBot3 Burger — Autonomous Image Drawing System

7. Step-by-Step Launch Workflow


7.1 PC Side (Offline Preparation)
4. Install dependencies: OpenCV, vpype, vpype-gcode, pygcode.
5. Run image_preprocessor.py on your input image.
6. Run contour_extractor.py to get path list.
7. Run path_optimiser.py to minimise pen lifts.
8. Run gcode_writer.py to produce [Link].
9. Copy [Link] to the Raspberry Pi via SCP or USB.

# PC terminal
python [Link] --input [Link] --output [Link]
python extract_contours.py --input [Link] --output [Link]
python optimise_paths.py --input [Link] --output [Link]
python write_gcode.py --input [Link] --output [Link]
scp [Link] ubuntu@<robot_ip>:~/catkin_ws/src/tb3_draw/gcode/

7.2 Robot Side (Pre-flight Checklist)


10. Place robot at HOME position (pen tip directly over paper origin corner).
11. Confirm pen is loaded and servo moves freely.
12. Start ROS core: roscore (Noetic) or ros2 launch (Humble).
13. Launch TurtleBot3 bringup: roslaunch turtlebot3_bringup [Link]
14. Start pigpiod daemon on the RPi: sudo pigpiod
15. Launch the drawing stack:

# Robot terminal (ROS Noetic)


roslaunch tb3_draw [Link] gcode:=[Link]

# [Link] starts these nodes:


# servo_control_node.py
# motion_executor_node.py
# gcode_parser_node.py

16. Monitor /robot_pose and /pen_state topics to verify correct operation.


17. Use CTRL+C at any time to e-stop. The robot will stop and pen will raise on shutdown
hook.

Confidential Project Guide | Page 18


TurtleBot3 Burger — Autonomous Image Drawing System

7.3 Emergency Stop Hook


# PSEUDOCODE: e_stop_handler

FUNCTION on_shutdown():
cmd_pub.publish(Twist()) # zero velocity
pi.set_servo_pulsewidth(SERVO_PIN, PULSE_UP) # raise pen
SLEEP(0.5)
[Link]()

rospy.on_shutdown(on_shutdown) # register with ROS

Confidential Project Guide | Page 19


TurtleBot3 Burger — Autonomous Image Drawing System

8. Recommended Software Stack

Layer Tool / Library Install Command

PC — Image processing OpenCV 4.x pip install opencv-python

PC — Path optimisation vpype 1.x pip install vpype

PC — G-code export vpype-gcode pip install vpype-gcode

PC — G-code handling pygcode pip install pygcode

Robot — ROS ROS Noetic (Ubuntu 20.04) [Link]/install

Robot — Servo PWM pigpio sudo apt install pigpio python3-


pigpio

Robot — Python Python 3.8+ Pre-installed on Ubuntu 20.04

Robot — Transform tf2_ros Part of ROS Noetic

ℹ ROS2 Note
If using ROS2 Humble on Ubuntu 22.04, replace rospy with rclpy, use ros2 launch instead of
roslaunch, and use Action servers (not topic ACKs) for the motion executor to properly handle goal
feedback and cancellation.

Confidential Project Guide | Page 20


TurtleBot3 Burger — Autonomous Image Drawing System

9. Future Improvements
9.1 External Localisation (Eliminates Drift)
• Mount an overhead USB camera pointing down at the drawing surface.
• Print an ArUco marker on the robot and use OpenCV ArUco detection to get absolute X,
Y, theta.
• Fuse camera pose with odometry in an EKF (robot_localization ROS package).
• This upgrade alone would make photorealistic drawings feasible.

9.2 Smoother Motion with Arc Interpolation


• Implement G2 (clockwise arc) and G3 (counter-clockwise arc) G-code commands.
• Use pure-pursuit or DWA local planner instead of rotate-then-drive for curved paths.

9.3 Multi-Colour Drawing


• Add a second servo to actuate a colour selector (marker carousel).
• Use T-commands in G-code (tool change) to select different marker colours.

9.4 Web Dashboard


• Build a simple Flask or rosbridge web interface to upload images, monitor progress, and
view a live trace of drawn paths.

Confidential Project Guide | Page 21


TurtleBot3 Burger — Autonomous Image Drawing System

10. Quick Reference Cheat Sheet


Key Physical Parameters

Parameter Value

Robot max linear speed (safe for 0.05 m/s


drawing)

Robot max angular speed 0.3 rad/s


(drawing turns)

Recommended drawing area 300 x 300 mm


(max)

Servo signal frequency 50 Hz

Servo pulse — pen UP 1500 us (tune per servo)

Servo pulse — pen DOWN 1900 us (tune per servo)

Servo settle delay 400 ms

XY arrival tolerance 5 mm

Angle arrival tolerance 0.02 rad (~1 deg)

Min path length to keep (noise 5 mm arc length


filter)

G-code Command Summary

G-code Meaning in this project

G21 Set units to millimetres

G90 Use absolute coordinates

G0 X__ Y__ Rapid (pen-up) move to coordinate

G1 X__ Y__ F__ Feed (pen-down) draw move

M3 Pen DOWN (servo to draw angle)

M5 Pen UP (servo to raised angle)

M2 End of program

Confidential Project Guide | Page 22


TurtleBot3 Burger — Autonomous Image Drawing System

Common Failure Symptoms and Fixes

Symptom Likely Cause Fix

Drawing is scaled wrong Unit mismatch mm vs m Ensure G21 in G-code and divide by
1000 in parser

Robot overshoots Speed too high Reduce LINEAR_SPEED to 0.04 m/s


waypoints

Lines are smeared at start Servo not settled before move Increase MOVE_DELAY to 0.5 s

Servo jitters continuously Software PWM interruption Switch to pigpiod hardware PWM

Drawing drifts rightward Left wheel slightly faster Recalibrate wheel radius individually

Robot spins indefinitely angle_diff not normalised Ensure normalise_angle() wraps to -


PI..PI

Pen scratches paper on PULSE_UP insufficient Increase PULSE_UP value (e.g.


travel 1300 us)

Confidential Project Guide | Page 23

You might also like