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!