Preface 


When we first encounter the TPBot smart car, it might just seem like a simple toy car, but as 
we delve deeper into its programming capabilities, we'll discover that it's actually a powerful educational robotics platform. In this guide, we'll go beyond basic driving control and explore the limitless possibilities of TPBot, turning it into a valuable assistant for exploring artificial intelligence, IoT, and robotics through creative programming.

This document contains rich code examples, project practices, and in-depth analyses to help you start from scratch, gradually master advanced programming techniques for TPBot, and inspire you to create your own smart car projects. Whether you're a programming novice or
an experienced enthusiast, this guide will provide valuable references and inspiration.

Chapter 1: TPBot Basics Exploration


1.1 TPBot Introduction


TPBot is an educational robot based on the micro:bit development board. It integrates various 
sensors and actuators, including line tracking sensors, ultrasonic sensors, LED lights, motors, and more. These components enable TPBot to perceive its environment, make decisions, and execute actions.

The micro:bit is a small computer designed by the British Broadcasting Corporation (BBC) specifically for youth programming education. It features a small size, powerful functionality, and ease of programming, making it ideal for beginners learning programming and electronics. TPBot leverages these advantages of micro:bit to provide users with a hands-on practice platform.

1.2 Development Environment Setup


To start your TPBot programming journey, you first need to set up the development 
environment. We use Microsoft's MakeCode platform, which is a web-based graphical programming environment perfect for beginners.

Step 1: Visit the MakeCode Website


Open your browser and visit the official Microsoft MakeCode website: https://makecode.micr obit.org/

Step 2: Add TPBot Extension


In the MakeCode interface, click the "Extensions" button at the bottom, then enter "tpbot" in the search box, and click on the TPBot extension in the search results to add it to your programming environment.

Step 3: Explore Basic Blocks 


After adding the extension, TPBot-related blocks will appear in the code drawer. These blocks can be categorized into several types:

1. Movement Control: Control the carto move forward, backward, left, right, etc.
2. Sensor Reading: Read data from line tracking sensors, ultrasonic sensors, etc.
3. Light Control: Control the LED lights on the car
4. Basic Operations: Basic functions like delays, displays, etc.

1.3 First Programming Experience


Let's write our first program to make TPBot move forward at 50% speed for 3 seconds and
then stop.
input.onButtonPressed(Button.A, function () { TPBot.setWheels(50, 50) basic.pause(3000) TPBot.stopCar() })

This program is very simple, but it demonstrates the basic structure of TPBot programming.
When we press the A button on the micro:bit, the car moves forward at 50% speed and automatically stops after 3 seconds.

Let's try a more interesting program that makes the car change its driving state based on the intensity of ambient light: 
basic.forever(function () { let lightLevel = input.lightLevel() if (lightLevel < 30) { // In darker environments, move forward slowly TPBot.setWheels(30, 30) TPBot.headlightColor(0xffffff) // Turn on headlights } else if (lightLevel < 70) { // In medium brightness environments, move forward at medium speed TPBot.setWheels(60, 60) TPBot.headlightColor(0x000000) // Turn off headlights } else { // In brighter environments, move forward quickly TPBot.setWheels(90, 90) TPBot.headlightColor(0x000000) // Turn off headlights } })

This program allows the car to automatically adjust its driving speed and headlight status based on ambient light intensity, demonstrating the concepts of simple environmental perception and adaptive control.

Chapter 2: The Secrets of Sensors


2.1 Working Principle and Application of Line Tracking Sensors 


Line tracking sensors are among the most important sensors on TPBot. They can detect color 
changes on the ground and are typically used to guide the car along specific routes.

Working Principle: Line tracking sensors contain an infrared emitter and an infrared receiver.
When infrared light hits objects of different colors, the intensity of the reflected light varies.
Black objects absorb most of the infrared light, reflecting very little; white objects reflect most of the infrared light. By detecting the intensity of reflected light, the sensor can determine whetherthe current position is a black line or a white surface.

Basic Line Tracking Program: 

basic.forever(function () { if (TPBot.trackLine(TPBot.TrackingState.L_R_Line)) { // Both left and right sensors detect black line TPBot.setWheels(40, 40) } else if (TPBot.trackLine(TPBot.TrackingState.L_Line_R_Line)) { // Left sensor detects black line, right sensor doesn't TPBot.setWheels(0, 60) } else if (TPBot.trackLine(TPBot.TrackingState.L_UnLine_R_Line)) { // Right sensor detects black line, left sensor doesn't TPBot.setWheels(60, 0) } else { // Neither sensor detects black line TPBot.setWheels(40, 40) } })

This basic line tracking program may not perform well in some complex road conditions, so let's improve it by adding some intelligent decision-making: 

let lastState = TPBot.TrackingState.L_R_unline let correctionCount = 0 basic.forever(function () { // Determine current state by checking each possible tracking state let currentState = TPBot.TrackingState.L_R_unline if (TPBot.trackLine(TPBot.TrackingState.L_R_line)) { currentState = TPBot.TrackingState.L_R_line } else if (TPBot.trackLine(TPBot.TrackingState.L_line_R_unline)) { currentState = TPBot.TrackingState.L_line_R_unline } else if (TPBot.trackLine(TPBot.TrackingState.L_unline_R_line)) { currentState = TPBot.TrackingState.L_unline_R_line } // Increase correction count if state hasn't changed if (currentState == lastState) { correctionCount++ } else { correctionCount = 0 lastState = currentState } // Adjust driving strategy based on current state and duration if (TPBot.trackLine(TPBot.TrackingState.L_R_line)) { TPBot.setWheels(40, 40) } else if (TPBot.trackLine(TPBot.TrackingState.L_line_R_unline)) { if (correctionCount > 10) { // If left turn state continues for more than 10 cycles, // increase right turn correction TPBot.setWheels(-20, 80) } else { TPBot.setWheels(0, 60) } } else if (TPBot.trackLine(TPBot.TrackingState.L_unline_R_line)) { if (correctionCount > 10) { // If right turn state continues for more than 10 cycles, // increase left turn correction TPBot.setWheels(80, -20) } else { TPBot.setWheels(60, 0) } } else { // Lost the line, search based on last known state if (lastState == TPBot.TrackingState.L_line_R_unline) { // Last was left turn state, try right turn search TPBot.setWheels(60, -20) } else { // Last was right turn state or initial state, try left turn search TPBot.setWheels(-20, 60) } } basic.pause(50) })


This improved line tracking program adds state memory and adaptive adjustment functions, enabling it to better handle complex line tracking conditions such as intersections and curves.

2.2 Creative Applications of Ultrasonic Sensors


Ultrasonic sensors are another important type of sensor that measures distance by emitting and receiving ultrasonic waves. The ultrasonic sensor equipped on TPBot can measure distances in the range of 2-400 centimeters, making it ideal for obstacle avoidance and distance detection.

Working Principle: The ultrasonic sensor emits a high-frequency sound wave pulse and then starts timing. When the sound wave reflects back after hitting an obstacle, the sensor receives the reflected wave and stops timing. Based on the propagation time and speed of the sound wave, the distance from the sensorto the obstacle can be calculated.

Basic Obstacle Avoidance Program:


let distance = 0 basic.forever(function () { distance = TPBot.sonarReturn(TPBot.SonarUnit.Centimeters) if (distance < 15 && distance > 0) { // Obstacle ahead, stop and turn TPBot.stopCar() TPBot.setWheels(-40, -40) basic.pause(500) // Randomly choose to turn left or right if (Math.randomBoolean()) { TPBot.setWheels(-40, 40) basic.pause(500) } else { TPBot.setWheels(40, -40) basic.pause(500) } } else { // No obstacle ahead, drive normally TPBot.setWheels(50, 50) } basic.pause(100) })

Let's try a more advanced application: using the ultrasonic sensor to measure distance and display distance information through the LED matrix:

let distance = 0 let lastDistance = 0 let distanceChange = 0 basic.forever(function () { distance = TPBot.sonarReturn(TPBot.SonarUnit.Centimeters) // Calculate distance change distanceChange = Math.abs(distance - lastDistance) lastDistance = distance // Display different icons based on distance if (distance < 10) { basic.showIcon(IconNames.Skull) TPBot.headlightColor(0xff0000) // Red warning } else if (distance < 30) { basic.showIcon(IconNames.Sad) TPBot.headlightColor(0xffff00) // Yellow warning } else if (distance < 50) { basic.showIcon(IconNames.Happy) TPBot.headlightColor(0x00ff00) // Green normal } else { // For longer distances, display numerical distance if (distance > 0) { basic.showNumber(distance) } else { basic.showString("-") } TPBot.headlightColor(0x000000) // Turn off headlights } // If distance changes suddenly a lot, it might be a moving obstacle if (distanceChange > 10) { TPBot.setWheels(20, 20) // Slow down } else { TPBot.setWheels(50, 50) // Normal speed } basic.pause(200) })

This program not only detects obstacles ahead but also displays different icons and light colors based on distance, and can even detect moving obstacles and respond with appropriate deceleration.

2.3 Application Expansion of Ambient Light Sensors


The ambient light sensor onboard the micro:bit can detect the intensity of light in the surrounding environment, providing us with another way to perceive the environment.

Working Principle: The ambient light sensor is actually the micro:bit's LED matrix working in reverse. Normally, the LED matrix is used for emitting light and displaying; when used as a light sensor, the LED matrix measures capacitance changes at different brightness levels to determine the intensity of ambient light.

Intelligent Light Control Program: 

let lightLevel = 0 let lastLightLevel = 0 let lightChange = 0 basic.forever(function () { lightLevel = input.lightLevel() // Calculate light change lightChange = Math.abs(lightLevel - lastLightLevel) lastLightLevel = lightLevel // Adjust headlight brightness based on light intensity if (lightLevel < 10) { // Very dark, maximum brightness TPBot.headlightColor(0xffffff) } else if (lightLevel < 30) { // Dark, medium brightness TPBot.headlightColor(0x808080) } else if (lightLevel < 60) { // Slightly dark, low brightness TPBot.headlightColor(0x404040) } else { // Bright, turn off headlights TPBot.headlightColor(0x000000) } // If light changes suddenly a lot, it might be entering a tunnel or strong light exposure if (lightChange > 20) { // Flash headlights to alert for (let i = 0; i < 3; i++) { TPBot.headlightColor(0x0000ff) basic.pause(100) TPBot.headlightColor(0x000000) basic.pause(100) } } // Display approximate value of current light intensity (0-9) let displayLevel = Math.floor(lightLevel / 10) if (displayLevel > 9) displayLevel = 9 basic.showNumber(displayLevel) basic.pause(500) })

This program implements intelligent light control, automatically adjusting headlight brightness based on ambient light, and can detect sudden changes in light and issue alerts.

Chapter 3: Creative Programming Project Practices


3.1 Intelligent Following Car


Let's create an intelligent car that can follow objects moving ahead. This project requires using the ultrasonic sensor to detect the distance to objects ahead and adjust the car's driving state based on distance changes.

Functional Requirements:

1. Detect distance to objects ahead 
2. Follow objects if they are within a certain range 
3. Stop following if objects are too far 
4. Move backward to maintain distance if objects are too close 

Implementation Code: 


let targetDistance = 20 // Target following distance (centimeters) let distance = 0 let followState = false // Following state flag // When button A is pressed, start following mode input.onButtonPressed(Button.A, function () { followState = true basic.showIcon(IconNames.Yes) TPBot.headlightColor(0x00ff00) // Green indicates following mode }) // When button B is pressed, stop following mode input.onButtonPressed(Button.B, function () { followState = false basic.showIcon(IconNames.No) TPBot.headlightColor(0x000000) // Turn off headlights TPBot.stopCar() // Stop the car }) basic.forever(function () { if (followState) { distance = TPBot.sonarReturn(TPBot.SonarUnit.Centimeters) // Only follow if within effective distance if (distance > 0) { let distanceDiff = distance - targetDistance // Adjust speed based on distance difference if (Math.abs(distanceDiff) < 3) { // Distance appropriate, stop TPBot.stopCar() } else if (distanceDiff > 0) { // Object too far, move forward to follow // Greater distance difference, faster speed let speed = Math.min(50, Math.abs(distanceDiff) * 3) TPBot.setWheels(speed, speed) } else { // Object too close, move backward to maintain distance // Greater distance difference, faster backward speed let speed = Math.min(50, Math.abs(distanceDiff) * 3) TPBot.setWheels(-speed, -speed) } // Display distance on LED matrix basic.showNumber(distance) } else { // No object detected, stop TPBot.stopCar() basic.showString("-") } } basic.pause(100) })

Project Extensions:


1. Add left-right turning functionality to allow the carto follow objects moving left and right 
2. Add follow sensitivity adjustment function 
3. Add sound prompts to emit specific sounds when following 

3.2 Intelligent Line Tracking Racing Car


Line tracking races are common in robotics competitions. We can transform TPBot into a dedicated line tracking racing car, improving its line tracking speed and stability.

Functional Requirements:


1. High-speed stable line tracking 
2. Intelligently identify curves and straight lines, adjust speed 
3. Quick response to route changes 

Implementation Code: 

 

let straightLineCount = 0 // Straight line count let curveCount = 0 // Curve count let lastState = TPBot.TrackingState.L_R_unline let speedBoost = false // Speed boost flag // When button A is pressed, start line tracking input.onButtonPressed(Button.A, function () { straightLineCount = 0 curveCount = 0 lastState = TPBot.TrackingState.L_R_unline speedBoost = false basic.showIcon(IconNames.Rabbit) }) // When button B is pressed, switch speed mode input.onButtonPressed(Button.B, function () { speedBoost = !speedBoost if (speedBoost) { basic.showIcon(IconNames.Triangle) // Use Triangle instead of Rocket TPBot.headlightColor(0xff0000) // Red indicates high-speed mode } else { basic.showIcon(IconNames.Triangle) // Use Triangle instead of Rabbit TPBot.headlightColor(0x00ff00) // Green indicates standard mode } }) basic.forever(function () { // Determine current state by checking each possible tracking state let currentState = TPBot.TrackingState.L_R_unline if (TPBot.trackLine(TPBot.TrackingState.L_R_line)) { currentState = TPBot.TrackingState.L_R_line } else if (TPBot.trackLine(TPBot.TrackingState.L_line_R_unline)) { currentState = TPBot.TrackingState.L_line_R_unline } else if (TPBot.trackLine(TPBot.TrackingState.L_unline_R_line)) { currentState = TPBot.TrackingState.L_unline_R_line } let baseSpeed = speedBoost ? 80 : 50 // Detect if on straight line if (TPBot.trackLine(TPBot.TrackingState.L_R_line)) { straightLineCount++ curveCount = 0 // If driving on straight line for a long time, can accelerate appropriately let straightSpeed = baseSpeed if (straightLineCount > 20) { straightSpeed = Math.min(baseSpeed + 20, 100) } TPBot.setWheels(straightSpeed, straightSpeed) } else if (TPBot.trackLine(TPBot.TrackingState.L_line_R_unline)) { // Turn left curveCount++ straightLineCount = 0 // Adjust speed based on curve degree let turnSpeed = baseSpeed if (curveCount > 5) { // Continuous left turns, possibly sharp curve, slow down turnSpeed = Math.max(baseSpeed - 20, 30) } TPBot.setWheels(turnSpeed * 0.3, turnSpeed) } else if (TPBot.trackLine(TPBot.TrackingState.L_unline_R_line)) { // Turn right curveCount++ straightLineCount = 0 // Adjust speed based on curve degree let turnSpeed = baseSpeed if (curveCount > 5) { // Continuous right turns, possibly sharp curve, slow down turnSpeed = Math.max(baseSpeed - 20, 30) } TPBot.setWheels(turnSpeed, turnSpeed * 0.3) } else { // Lost the line, need to search if (lastState == TPBot.TrackingState.L_line_R_unline) { // Last was left turn state, try right turn search TPBot.setWheels(baseSpeed, -baseSpeed * 0.5) } else { // Last was right turn state or initial state, try left turn search TPBot.setWheels(-baseSpeed * 0.5, baseSpeed) } // Flash headlights to alert TPBot.headlightColor(0xff0000) basic.pause(50) TPBot.headlightColor(0x000000) } lastState = currentState basic.pause(20) // Increase response frequency })


Tuning Tips:


1. Adjust base speed and turning speed ratio according to actual track 
2. Adjust the judgment thresholds for straight lines and curves 
3. Fortracks of different materials and colors, you may need to adjust the sensor sensitivity 

3.3 Smart Home Patrol Car


Imagine having a smart car that can patrol your room, monitor environmental safety, and notify you in time when abnormalities are detected. This project will transform TPBot into a smart home patrol robot.

Functional Requirements:


1. Automatically patrol the room 
2. Detect obstacles and detour around them 
3. Monitor environmental light changes (may indicate windows being opened) 

4. Issue alerts when abnormalities are detected 

Implementation Code:

let patrolMode = false let lastLightLevel = input.lightLevel() let obstacleCount = 0 let patrolTime = 0
// When buttons A+B are pressed, start patrol mode input.onButtonPressed(Button.AB, function () { patrolMode = !patrolMode if (patrolMode) { patrolTime = 0 obstacleCount = 0 lastLightLevel = input.lightLevel() basic.showIcon(IconNames.Happy) // Use Happy instead of Shield TPBot.headlightColor(0x0000ff) // Blue indicates patrol mode } else { basic.showIcon(IconNames.Asleep) // Use Asleep instead of Sleepy TPBot.headlightColor(0x000000) TPBot.stopCar() } }) function alert异常() { // Abnormality alert for (let i = 0; i < 5; i++) { TPBot.headlightColor(0xff0000) basic.showIcon(IconNames.Skull) basic.pause(200) TPBot.headlightColor(0x000000) basic.showIcon(IconNames.Happy) basic.pause(200) } } basic.forever(function () { if (patrolMode) { patrolTime++ // Environmental light change detection let currentLightLevel = input.lightLevel() if (Math.abs(currentLightLevel - lastLightLevel) > 30) { // Large light change, possibly a window being opened alert异常() lastLightLevel = currentLightLevel } // Obstacle detection and detour let distance = TPBot.sonarReturn(TPBot.SonarUnit.Centimeters) if (distance > 0 && distance < 20) { // Obstacle detected obstacleCount++ if (obstacleCount > 10) { // Obstacle detected continuously, possibly a fixed obstacle, need to detour TPBot.stopCar() TPBot.setWheels(-40, -40) basic.pause(500) // Randomly choose to turn left or right if (Math.randomBoolean()) { TPBot.setWheels(-40, 40) basic.pause(800) } else { TPBot.setWheels(40, -40) basic.pause(800) } obstacleCount = 0 } else { // Temporarily stop, possibly a moving obstacle TPBot.stopCar() } } else { obstacleCount = 0 // Normal patrol if (patrolTime % 100 == 0) { // Every once in a while, randomly adjust direction to increase patrol coverage if (Math.randomBoolean()) { TPBot.setWheels(-30, 30) basic.pause(300) } else { TPBot.setWheels(30, -30) basic.pause(300) } } else { // Normal forward patrol TPBot.setWheels(40, 40) } } // Display patrol status basic.showIcon(IconNames.Happy) // Use Happy instead of Shield } basic.pause(100) })

Project Upgrades:


1. Add sound sensors to detect abnormal sounds 
2. Connect to mobile phones via Bluetooth forremote monitoring 
3. Add memory function to remember patrol paths 

Chapter 4: Advanced Programming Techniques


4.1 State Machine Design Pattern 


A state machine is a programming design pattern that divides a program's behavior into several states, each corresponding to different behavior logic. This pattern is particularly suitable for smart car control because smart cars need to exhibit different behaviors in different situations.

Basic State Definitions:


Forward state
Backward state
Left turn state
Right turn state
Stop state
Obstacle avoidance state
Line tracking state

State Machine Implementation Example:  


// Define state enumeration enum CarState { Forward, Backward, Left, Right, Stop, Avoiding, Tracking } let currentState = CarState.Stop let stateTimer = 0 let obstacleDistance = 0 let trackingState = TPBot.TrackingState.L_R_unline // State processing function function processState() { stateTimer++ switch (currentState) { case CarState.Forward: TPBot.setWheels(50, 50) basic.showIcon(IconNames.Triangle) // Check if state transition is needed obstacleDistance = TPBot.sonarReturn(TPBot.SonarUnit.Centimeters) if (obstacleDistance > 0 && obstacleDistance < 15) { currentState = CarState.Avoiding stateTimer = 0 } else if (TPBot.trackLine(TPBot.TrackingState.L_line_R_unline) || TPBot.trackLine(TPBot.TrackingState.L_unline_R_line)) { currentState = CarState.Tracking stateTimer = 0 } else if (stateTimer > 100) { // Forward time too long, random turn if (Math.randomBoolean()) { currentState = CarState.Left } else { currentState = CarState.Right } stateTimer = 0 } break case CarState.Backward: TPBot.setWheels(-40, -40) basic.showIcon(IconNames.Square) // Switch to stop state after backing up for a while if (stateTimer > 30) { currentState = CarState.Stop stateTimer = 0 } break case CarState.Left: TPBot.setWheels(-30, 30) basic.showIcon(IconNames.Diamond) // Switch to forward state after turning left for a while if (stateTimer > 20) { currentState = CarState.Forward stateTimer = 0 } break case CarState.Right: TPBot.setWheels(30, -30) basic.showIcon(IconNames.SmallDiamond) // Switch to forward state after turning right for a while if (stateTimer > 20) { currentState = CarState.Forward stateTimer = 0 } break case CarState.Stop: TPBot.stopCar() basic.showIcon(IconNames.Square) // Switch to forward state after stopping for a while if (stateTimer > 50) { currentState = CarState.Forward stateTimer = 0 } break case CarState.Avoiding: TPBot.stopCar() basic.showIcon(IconNames.Skull) TPBot.headlightColor(0xff0000) if (stateTimer == 1) { // First entering obstacle avoidance state, back up TPBot.setWheels(-50, -50) basic.pause(500) } else if (stateTimer > 10 && stateTimer < 30) { // After backing up, randomly choose to turn left or right if (Math.randomBoolean()) { TPBot.setWheels(-40, 40) // Left turn } else { TPBot.setWheels(40, -40) // Right turn } } else if (stateTimer > 30) { // After turning, return to forward state currentState = CarState.Forward stateTimer = 0 TPBot.headlightColor(0x000000) } break case CarState.Tracking: // Determine tracking state by checking each possible state if (TPBot.trackLine(TPBot.TrackingState.L_R_line)) { trackingState = TPBot.TrackingState.L_R_line } else if (TPBot.trackLine(TPBot.TrackingState.L_line_R_unline)) { trackingState = TPBot.TrackingState.L_line_R_unline } else if (TPBot.trackLine(TPBot.TrackingState.L_unline_R_line)) { trackingState = TPBot.TrackingState.L_unline_R_line } else { trackingState = TPBot.TrackingState.L_R_unline } if (TPBot.trackLine(TPBot.TrackingState.L_R_line)) { TPBot.setWheels(40, 40) basic.showIcon(IconNames.Diamond) } else if (TPBot.trackLine(TPBot.TrackingState.L_line_R_unline)) { TPBot.setWheels(0, 60) basic.showIcon(IconNames.Diamond) } else if (TPBot.trackLine(TPBot.TrackingState.L_unline_R_line)) { TPBot.setWheels(60, 0) basic.showIcon(IconNames.SmallDiamond) } else { // Lost the line, return to forward state currentState = CarState.Forward stateTimer = 0 } // Check for obstacles obstacleDistance = TPBot.sonarReturn(TPBot.SonarUnit.Centimeters) if (obstacleDistance > 0 && obstacleDistance < 15) { currentState = CarState.Avoiding stateTimer = 0 } break } } // Button control for state switching input.onButtonPressed(Button.A, function () { currentState = CarState.Forward stateTimer = 0 }) input.onButtonPressed(Button.B, function () { currentState = CarState.Stop stateTimer = 0 }) // Main loop basic.forever(function () { processState() basic.pause(50) })

The benefits of using the state maching pattern are:

1. Clear code structure, easy to maintain and extend 
2. Clear state transition logic, easy to debug 
3. Can easily add new states and behaviors 

4.2 PID Control Algorithm


PID (Proportional-Integral-Derivative) control is a widely used algorithm in industrial control that can make control systems more stable and precise. In smart car control, PID algorithms are often used forline tracking control, enabling the carto drive along routes more smoothly.

Three Parameters of PID Controller:


P (Proportional): Control quantity proportional to the current error
I (Integral): Control quantity proportional to the error integral, used to eliminate static error
D (Derivative): Control quantity proportional to the error change rate, used to predict error change trends


PID Line Tracking Control Implementation:


// PID parameters let kp = 0.5 // Proportional coefficient let ki = 0.1 // Integral coefficient let kd = 0.3 // Derivative coefficient // Control variables let error = 0 // Current error let lastError = 0 // Previous error let integral = 0 // Error integral let derivative = 0 // Error derivative let pidOutput = 0 // PID output let baseSpeed = 50 // Base speed // Calculate error function calculateError() { // Use line tracking sensor state to calculate error here // -100 indicates completely left, 0 indicates middle, 100 indicates completely right if (TPBot.trackLine(TPBot.TrackingState.L_line_R_unline)) { return -50 } else if (TPBot.trackLine(TPBot.TrackingState.L_R_line)) { return 0 } else if (TPBot.trackLine(TPBot.TrackingState.L_unline_R_line)) { return 50 } else { // Lost the line, predict based on last error if (lastError > 0) { return 100 } else if (lastError < 0) { return -100 } else { return 0 } } } // Calculate PID output function calculatePID() { error = calculateError() // Calculate integral term integral = integral + error // Limit integral range to prevent integral saturation if (integral > 1000) integral = 1000 if (integral < -1000) integral = -1000 // Calculate derivative term derivative = error - lastError // Calculate PID output pidOutput = kp * error + ki * integral + kd * derivative // Save current error as previous error lastError = error return pidOutput } // Use PID to control line tracking function pidTracking() { let output = calculatePID() // Calculate left and right wheel speeds let leftSpeed = baseSpeed - output let rightSpeed = baseSpeed + output // Limit speed range if (leftSpeed > 100) leftSpeed = 100 if (leftSpeed < -100) leftSpeed = -100 if (rightSpeed > 100) rightSpeed = 100 if (rightSpeed < -100) rightSpeed = -100 // Set wheel speeds TPBot.setWheels(leftSpeed, rightSpeed) // Display PID output (approximate value) let displayValue = Math.floor(pidOutput / 10) if (displayValue > 9) displayValue = 9 if (displayValue < -9) displayValue = -9 if (displayValue != 0) { basic.showNumber(displayValue) } else { basic.showString("-" + Math.abs(displayValue)) } } // Button control input.onButtonPressed(Button.A, function () { // Start line tracking baseSpeed = 50 integral = 0 lastError = 0 basic.showIcon(IconNames.Rabbit) }) input.onButtonPressed(Button.B, function () { // Stop line tracking TPBot.stopCar() basic.showIcon(IconNames.Square) }) // Main loop basic.forever(function () { pidTracking() basic.pause(20) })

 
Parameter Tuning Tips
:

1. First set ki and kd to 0, adjust kp until the system oscillates slightly 
2. Then increase kd to suppress oscillation 
3. Finally increase ki to eliminate static error 
4. Fine-tune these three parameters repeatedly until the system performs best 

4.3 Sensor Data Fusion

Sensor data fusion refers to combining data from multiple sensors to obtain more accurate and comprehensive environmental information. In TPBot, we can fuse data from line tracking sensors, ultrasonic sensors, and ambient light sensors to give the car a more comprehensive perception of its environment.

Data Fusion Implementation Example:

 

// Define sensor data structure let sensorData = { distance: 0, // Ultrasonic distance lightLevel: 0, // Ambient light intensity trackingState: TPBot.TrackingState.L_R_unline, // Line tracking state lastUpdated: 0 // Last update time } // Define behavior decision enumeration enum BehaviorDecision { Forward, Backward, Left, Right, Stop, FastForward, SlowForward } // Update sensor data function updateSensorData() { sensorData.distance = TPBot.sonarReturn(TPBot.SonarUnit.Centimeters) sensorData.lightLevel = input.lightLevel() // Use appropriate method to check tracking state // Track line directly using trackLine method if (TPBot.trackLine(TPBot.TrackingState.L_R_line)) { sensorData.trackingState = TPBot.TrackingState.L_R_line } else if (TPBot.trackLine(TPBot.TrackingState.L_unline_R_line)) { sensorData.trackingState = TPBot.TrackingState.L_unline_R_line } else if (TPBot.trackLine(TPBot.TrackingState.L_line_R_unline)) { sensorData.trackingState = TPBot.TrackingState.L_line_R_unline } else { sensorData.trackingState = TPBot.TrackingState.L_R_unline } sensorData.lastUpdated = input.runningTime() } // Make decisions based on fused data function makeDecision(): BehaviorDecision { // Priority 1: Obstacle detection if (sensorData.distance > 0 && sensorData.distance < 15) { return BehaviorDecision.Stop } // Priority 2: Line tracking state if (TPBot.trackLine(sensorData.trackingState)) { // On the line tracking path if (sensorData.trackingState == TPBot.TrackingState.L_R_line) { // Straight driving, can accelerate appropriately return BehaviorDecision.FastForward } else { // Curve driving, slow down return BehaviorDecision.SlowForward } } // Priority 3: Ambient light intensity if (sensorData.lightLevel < 20) { // Dark environment, slow driving return BehaviorDecision.SlowForward } else if (sensorData.lightLevel > 80) { // Bright environment, can drive quickly return BehaviorDecision.FastForward } // Default behavior return BehaviorDecision.Forward } // Execute decision function executeDecision(decision: BehaviorDecision) { switch (decision) { case BehaviorDecision.Forward: TPBot.setWheels(50, 50) basic.showIcon(IconNames.Triangle) break case BehaviorDecision.Backward: TPBot.setWheels(-40, -40) basic.showIcon(IconNames.Square) break case BehaviorDecision.Left: TPBot.setWheels(-30, 30) basic.showIcon(IconNames.Diamond) break case BehaviorDecision.Right: TPBot.setWheels(30, -30) basic.showIcon(IconNames.SmallDiamond) break case BehaviorDecision.Stop: TPBot.stopCar() basic.showIcon(IconNames.Square) break case BehaviorDecision.FastForward: TPBot.setWheels(80, 80) basic.showIcon(IconNames.Triangle) break case BehaviorDecision.SlowForward: TPBot.setWheels(30, 30) basic.showIcon(IconNames.Square) // Use Square instead of Snail break } // Adjust headlights based on ambient light intensity if (sensorData.lightLevel < 30) { TPBot.headlightColor(0xffffff) } else { TPBot.headlightColor(0x000000) } } // Main loop basic.forever(function () { updateSensorData() let decision = makeDecision() executeDecision(decision) basic.pause(50) })


The advantages of data fusion are:
1. Improved accuracy and reliability of environmental perception 
2. When data from a certain sensor is unavailable, the system can still work relying on other sensors
3. Can implement more intelligent behavior decisions 

Chapter 5: Creative Expansion and Future Outlook


5.1 Basic Control and Simple Interaction

We can control TPBot through buttons to implement simple interactive functions.

Button Control Example:


// Button A: Forward input.onButtonPressed(Button.A, function () { TPBot.setWheels(50, 50) // Forward basic.showIcon(IconNames.Triangle) }) // Button B: Backward input.onButtonPressed(Button.B, function () { TPBot.setWheels(-50, -50) // Backward basic.showIcon(IconNames.Square) }) // Press both A and B buttons simultaneously: Stop input.onButtonPressed(Button.AB, function () { TPBot.stopCar() // Stop basic.showIcon(IconNames.Square) })


Display SensorInformation:


// Regularly display sensor data basic.forever(function () { // Display ultrasonic distance let distance = TPBot.sonarReturn(TPBot.SonarUnit.Centimeters) if (distance > 0) { basic.showString("D:") basic.showNumber(distance) } else { basic.showString("No") } basic.pause(1000) // Display line tracking state if (TPBot.trackLine(TPBot.TrackingState.L_R_line)) { basic.showString("LINE") } else if (TPBot.trackLine(TPBot.TrackingState.L_line_R_unline)) { basic.showString("LEFT") } else if (TPBot.trackLine(TPBot.TrackingState.L_unline_R_line)) { basic.showString("RIGHT") } else { basic.showString("NONE") } basic.pause(1000) })


5.2 Combination Use of Basic Functions


We can combine TPBot's basic functions to create more interesting effects. 

Light and Action Combination:

 
// Light show and action combination demonstration input.onButtonPressed(Button.A, function () { // Move forward and flash lights TPBot.setWheels(30, 30) for (let i = 0; i < 5; i++) { TPBot.headlightColor(0xff0000) // Red basic.pause(200) TPBot.headlightColor(0x00ff00) // Green basic.pause(200) } TPBot.stopCar() TPBot.headlightColor(0x000000) }) // Swinging light effect input.onButtonPressed(Button.B, function () { // Rotate in place and change light colors TPBot.setWheels(-20, 20) // Turn left in place let colors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff] for (let i = 0; i < colors.length; i++) { TPBot.headlightColor(colors[i]) basic.pause(500) } TPBot.stopCar() TPBot.headlightColor(0x000000) })


Comprehensive Sensor Application:

 
// Adjust behavior based on ambient Light distance
let lightThreshold = 50 // Light threshold let distanceThreshold = 20 // Distance threshold
basic.forever(function () { let lightLevel = input.lightLevel() let distance = TPBot.sonarReturn(TPBot.SonarUnit.Centimeters) // Adjust headlights and speed based on light intensity if (lightLevel < lightThreshold) { // Dark light, turn on lights and drive slowly TPBot.headlightColor(0xffffff) if (distance > 0 && distance < distanceThreshold) { // Dark and obstacle present, stop and warn TPBot.stopCar() basic.showIcon(IconNames.Skull) // Flash warning lights for (let i = 0; i < 3; i++) { TPBot.headlightColor(0xff0000) basic.pause(200) TPBot.headlightColor(0x000000) basic.pause(200) } } else { // Dark but no obstacle, drive forward slowly TPBot.setWheels(30, 30) } } else { // Bright light, turn off lights and drive normally TPBot.headlightColor(0x000000) if (distance > 0 && distance < distanceThreshold) { // Bright but obstacle present, turn to avoid TPBot.stopCar() // Randomly choose turning direction if (Math.randomBoolean()) { TPBot.setWheels(-30, 30) // Left turn } else { TPBot.setWheels(30, -30) // Right turn } basic.pause(500) } else { // Bright and no obstacle, drive forward normally TPBot.setWheels(50, 50) } } basic.pause(100) })


5.3 Fun Programming Project Examples


We can use TPBot's basic functions to create interesting games and interactive projects.


Traffic Light Game:


// Traffic Light Game: Control the car according to light colors let gameState = 0 // 0: Red light, 1: Green light, 2: Yellow light let score = 0 // Initialization basic.showString("GO!") TPBot.stopCar() // Button A: Press A to score when green light is on, lose points when red light is on input.onButtonPressed(Button.A, function () { if (gameState == 1) { // Green light score++ basic.showString("+") TPBot.headlightColor(0x00ff00) } else if (gameState == 0) { // Red light score-- basic.showString("-") TPBot.headlightColor(0xff0000) } basic.pause(300) showScore() }) // Display score function showScore() { basic.clearScreen() basic.showString("S:") basic.showNumber(score) } // Game main loop basic.forever(function () { // Randomly set light color state gameState = Math.randomRange(0, 2) if (gameState == 0) { // Red light basic.showLeds(` # # # # # # . . . # # . . . # # . . . # # # # # # `) TPBot.headlightColor(0xff0000) } else if (gameState == 1) { // Green light basic.showLeds(` # # # # # # . . . # # . . . # # . . . # # # # # # `) TPBot.headlightColor(0x00ff00) } else { // Yellow light basic.showLeds(` # # # # # # . . . # # . . . # # . . . # # # # # # `) TPBot.headlightColor(0xffff00) } // Random duration basic.pause(Math.randomRange(500, 2000)) })


Automatic Obstacle Avoidance Patrol Mode:

 

//Simple obstacle avoidance patrol mode let patrolMode = false // Button A: Turn patrol mode on/off input.onButtonPressed(Button.A, function () { patrolMode = !patrolMode if (patrolMode) { basic.showString("ON") TPBot.headlightColor(0x0000ff) } else { basic.showString("OFF") TPBot.stopCar() TPBot.headlightColor(0x000000) } }) // Patrol main loop basic.forever(function () { if (patrolMode) { let distance = TPBot.sonarReturn(TPBot.SonarUnit.Centimeters) if (distance > 0 && distance < 20) { // Obstacle detected, stop and turn TPBot.stopCar() TPBot.headlightColor(0xff0000) // Back up a short distance TPBot.setWheels(-30, -30) basic.pause(500) // Randomly choose to turn left or right if (Math.randomBoolean()) { TPBot.setWheels(-40, 40) // Left turn } else { TPBot.setWheels(40, -40) // Right turn } basic.pause(800) TPBot.headlightColor(0x0000ff) } else { // No obstacle, drive normally TPBot.setWheels(40, 40) } } basic.pause(100) })


Chapter 6: Troubleshooting and Common Problem Solutions


6.1 Car Cannot Start Normally

 

Possible Causes:

1. Low battery power 
2. Incorrect battery installation 
3. Poor connection between micro:bit and car 

Solutions:


1. Replace with new batteries or charge the batteries 
2. Check if battery polarity is installed correctly 
3. Reconnect the micro:bit, ensure the connection is secure 

6.2 Inaccurate Line Tracking

Possible Causes: 

1. Ground reflection too strong ortoo weak 
2. Incorrect line tracking sensor height 
3. Improper parameter settings in the code 

Solutions:


1. Adjust the line tracking area, avoid direct strong light 
2. Adjust the sensor height to maintain an appropriate distance from the ground 

3. Modify speed parameters and judgment thresholds in the code 

6.3 Ultrasonic Sensor Measurement Inaccuracies


Possible Causes
:


1. Multiple obstacles within measurement range 
2. Obstacle surface absorbs ultrasonic waves 
3. Sensor angle offset 

Solutions:


1. Ensure only one main obstacle is within the measurement range 
2. Avoid using soft, sound-absorbing material obstacles 
3. Adjust the sensor angle to face the measured object directly 

6.4 Uneven Motor Speed


Possible Causes:

1. Differences in left and right motor characteristics 
2. Low battery power 
3. Asymmetric wheel installation 

Solutions:


1. Compensate forleft and right wheel speeds in the code 
2. Replace with new batteries 
3. Reinstall the wheels to ensure symmetry 


Conclusion


Through this TPBot Creative Programming Guide, we have started from basic driving control and gradually explored sensor applications, creative project practices, advanced programming techniques, and future expansion directions. TPBot is not just a simple toy, but a platform that stimulates creativity and learning interest.

During the programming process, we may encounter various problems, but it is these challenges that make us continue to grow and progress. By solving problems, we not only master programming skills but also develop problem-solving thinking patterns and innovation abilities.

I hope this guide can provide you with inspiration and help, allowing you to find joy in the programming world of TPBot and create more wonderful projects!

In the future, with the continuous development of technology, TPBot's application potential will be even broader. There are infinite possibilities waiting for us to explore in the fields of education, smart home, and artificial intelligence research.

Let's work together, using creativity and code, to make TPBot move and let our imagination soar!