How to Use Functions and Pointers in C++

In this tutorial, we will explore functions and pointers in C++.

Prerequisites

Using Mathematical Functions

Let’s explore how to use mathematical functions in C++ for robotics. Mathematical functions are essential for performing various calculations in robotic applications.

Open a terminal window, and type this:

cd ~/Documents/cpp_tutorial

code .

Let’s create a new C++ file and name it robot_math_functions.cpp.

Type the following code into the editor:

#include <iostream>
#include <cmath>

using namespace std;

int main() {
    double angle = 45.0;
    double radians = angle * M_PI / 180.0;

    double sine = sin(radians);
    double cosine = cos(radians);

    cout << "Sine: " << sine << endl;
    cout << "Cosine: " << cosine << endl;

    return 0;
}

In this example, we demonstrate how to use mathematical functions to calculate the sine and cosine of an angle.

First, we include the <cmath> header to use the mathematical functions. Then, we declare a double variable angle and assign it the value 45.0, representing an angle in degrees.

To convert the angle from degrees to radians, we multiply it by M_PI (which represents the mathematical constant pi) and divide by 180.0. We store the result in the radians variable.

To calculate the sine and cosine of the angle, we use the sin() and cos() functions, respectively. These functions expect the angle to be in radians. 

We pass the radians variable as an argument to these functions and store the results in the sine and cosine variables.

Finally, we print the values of sine and cosine using cout.

Run the code.

1-robot-math-functions

You should see the values of sine and cosine printed in the terminal.

In robotic projects, mathematical functions are commonly used for tasks such as calculating robot positions, orientations, sensor data processing, control algorithms, and motion planning.

Implementing Functions

Let’s explore how to implement functions in C++ for robotics. Functions are essential for organizing and reusing code in robotic applications.

Let’s create a new C++ file and name it robot_functions.cpp.

Type the following code into the editor:

#include <iostream>
#include <cmath>  // Added header for sqrt()
using namespace std;

// Function declaration 
double calculate_distance(double x1, double y1, double x2, double y2);

int main() {
    double distance = calculate_distance(0, 0, 3, 4);
    cout << "Distance: " << distance << endl;
    return 0;
}

// Function definition
double calculate_distance(double x1, double y1, double x2, double y2) {
    double dx = x2 - x1;
    double dy = y2 - y1;
    double distance = sqrt(dx * dx + dy * dy);
    return distance;
}

In this example, we demonstrate how to implement a function to calculate the distance between two points.

First, we declare the calculate_distance function before the main function. The function takes four parameters: x1, y1, x2, and y2, representing the coordinates of two points. It returns a double value, which is the calculated distance.

In the main function, we call the calculate_distance function with the coordinates (0, 0) and (3, 4). The returned distance is stored in the distance variable and then printed using cout.

After the main function, we provide the function definition for calculate_distance. Inside the function, we calculate the differences in x and y coordinates (dx and dy). 

Then, we use the distance formula (Pythagorean theorem) to calculate the distance between the points. 

Finally, we return the calculated distance.

Run the code.

2-robot-functions

You should see the calculated distance printed in the terminal.

In robotic projects, you can use functions for various purposes, such as calculating sensor data, controlling robot movements, implementing algorithms, and more.

Handling Pointers

Let’s explore how to handle pointers in C++ for robotics. Pointers are variables that store memory addresses and allow you to manipulate data directly in memory.

Let’s create a new C++ file and name it robot_pointers.cpp.

Type the following code into the editor:

#include <iostream>

using namespace std;

int main() {
    int robot_id = 42;
    int* ptr = &robot_id;

    cout << "Robot ID: " << robot_id << endl;
    cout << "Pointer Value: " << ptr << endl;
    cout << "Dereferenced Pointer: " << *ptr << endl;

    *ptr = 99;
    cout << "Updated Robot ID: " << robot_id << endl;

    return 0;
}

In this example, we demonstrate how to handle pointers to manipulate data in memory.

First, we declare an integer variable robot_id and assign it the value 42. Then, we declare a pointer variable ptr and initialize it with the address of robot_id using the address-of operator &. The & operator retrieves the memory address of a variable.

We print the value of robot_id, the value of ptr (which is the memory address), and the dereferenced value of ptr using the dereference operator *. The * operator, when used in front of a pointer variable, retrieves the value stored at the memory address pointed to by the pointer. This is called dereferencing.

Next, we use the dereference operator * to modify the value at the memory address pointed to by ptr. 

We assign the value 99 to *ptr, which effectively updates the value of robot_id. By dereferencing ptr and assigning a new value, we are changing the value stored at the memory address pointed to by ptr, which is the memory address of robot_id.

Finally, we print the updated value of robot_id to confirm that it has been modified through the pointer.

Run the code.

3-robot-pointers

You should see the original robot ID, the pointer value (memory address), the dereferenced pointer value (which is the same as the original robot ID), and the updated robot ID printed in the terminal.

In robotics projects, pointers allow you to directly access and modify data without needing to move or copy it, which makes programs run faster and use less memory.

Managing Exceptions

Let’s learn how to manage exceptions in C++ for robotics applications. Proper exception handling is important for robust and reliable software systems, especially in the field of robotics where errors can have significant consequences.

Let’s start by creating a new C++ file called exception_handling.cpp.

Type the following code into the editor:

#include <iostream>
#include <stdexcept>

double divide(double a, double b) {
    if (b == 0) {
        throw std::runtime_error("Division by zero");
    }
    return a / b;
}

int main() {
    try {
        double result = divide(10, 0);
        std::cout << "Result: " << result << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
    return 0;
}

In this example, we define a function divide that throws a std::runtime_error exception if the denominator is zero. In the main function, we wrap the call to divide in a try block and handle any potential exceptions in the catch block.

Run the code.

4-exception-handling

You should see the error message “Error: Division by zero” printed in the terminal, as we intentionally passed 0 as the second argument to the divide function.

Proper exception handling is important in robotics applications, where unexpected situations or sensor failures can occur. By using exceptions and handling them appropriately, you can ensure that your code gracefully handles errors and maintains a consistent state, preventing potential damage or safety issues.

Thanks, and I’ll see you in the next tutorial.

Keep building!

How to Use Arrays, Vectors, and Strings in C++

In this tutorial, we will explore arrays, vectors, and strings using C++.

Prerequisites

Managing Arrays

Let’s explore how to manage arrays in C++ for robotics. Arrays are a fundamental data structure that allows you to store and manipulate multiple values of the same type.

Open a terminal window, and type this:

cd ~/Documents/cpp_tutorial
code .

Let’s create a new C++ file and name it robot_arrays.cpp.

Type the following code into the editor:

#include <iostream>

using namespace std;

int main() {
    const int size = 5;
    int sensor_readings[size];

    // Initializing the array
    for (int i = 0; i < size; i++) {
        sensor_readings[i] = i * 10;
    }

    // Accessing array elements
    cout << "Sensor Readings:" << endl;
    for (int i = 0; i < size; i++) {
        cout << "Sensor " << i + 1 << ": " << sensor_readings[i] << endl;
    }

    return 0;
}

In this example, we demonstrate how to declare, initialize, and access elements of an array.

First, we declare a constant size to represent the size of the array. Then, we declare an integer array sensor_readings with a size of size.

Next, we use a for loop to initialize the array elements. In this case, we assign each element a value that is a multiple of 10 based on its index.

After initializing the array, we use another for loop to access and print each element of the array. We use the array indexing syntax sensor_readings[i] to access individual elements, where i is the index of the element.

Run the code.

1-robot-arrays

You should see the sensor readings printed in the terminal.

This example demonstrates the basic management of arrays in C++ for robotics. Arrays are useful for storing and processing collections of related data, such as sensor readings, robot positions, or any other data that needs to be organized and accessed efficiently.

When working with arrays, it’s important to be mindful of the array size and ensure that you don’t access elements outside the valid range to avoid undefined behavior.

Arrays are a powerful tool in robotic programming, allowing you to store and manipulate data efficiently. They are commonly used for tasks such as storing sensor data, tracking robot positions, or representing configuration parameters.

Employing Vectors

Let’s explore how to employ vectors in C++ for robotics. Vectors are a dynamic array container provided by the C++ Standard Library that offer flexibility and convenience when working with resizable arrays.

Let’s create a new C++ file and name it robot_vectors.cpp.

Type the following code into the editor:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> motor_speeds;

    // Adding elements to the vector
    motor_speeds.push_back(100);
    motor_speeds.push_back(200);
    motor_speeds.push_back(150);

    // Accessing vector elements
    cout << "Motor Speeds:" << endl;
    for (int i = 0; i < motor_speeds.size(); i++) {
        cout << "Motor " << i + 1 << ": " << motor_speeds[i] << endl;
    }

    return 0;
}

In this example, we demonstrate how to declare, add elements to, and access elements of a vector.

First, we include the <vector> header to use the vector container. Then, we declare a vector named motor_speeds that will store integer values.

To add elements to the vector, we use the push_back() member function. In this case, we add three motor speed values to the vector.

To access the elements of the vector, we use a for loop that iterates from 0 to the size of the vector. 

We use the size() member function to get the number of elements in the vector. Inside the loop, we access each element using the array indexing syntax motor_speeds[i], where i is the index of the element.

Run the code.

2-robot-vectors

You should see the motor speeds printed in the terminal.

In robotic projects, you can use vectors to store and process sensor readings, track robot trajectories, manage lists of tasks, or any other scenario where dynamic arrays are needed.

Manipulating Strings

Let’s explore how to manipulate strings in C++ for robotics. Strings are a fundamental data type used to represent and work with text data.

Let’s create a new C++ file and name it robot_strings.cpp.

Type the following code into the editor:

#include <iostream>
#include <string>

using namespace std;

int main() {
    string robot_name = "AutomaticAddisonBot";
    
    // Accessing string characters
    cout << "Robot Name: " << robot_name << endl;
    cout << "First Character: " << robot_name[0] << endl;
    
    // Modifying string
    robot_name[8] = '-';
    cout << "Modified Robot Name: " << robot_name << endl;
    
    // Concatenating strings
    string model = "X100";
    string full_name = robot_name + " " + model;
    cout << "Full Name: " << full_name << endl;
    
    return 0;
}

In this example, we demonstrate how to declare, access, modify, and concatenate strings.

First, we include the <string> header to use the string data type. 

Then, we declare a string variable named robot_name and assign it the value “AutomaticAddisonBot”.

To access individual characters of the string, we use the array indexing syntax. We print the first character of the robot name using robot_name[0].

To modify a character in the string, we use the array indexing syntax and assign a new value to a specific position. In this case, we change the character at index 4 to a hyphen.

To concatenate strings, we use the + operator. We declare a new string variable model and assign it the value “X100”. 

Then, we concatenate robot_name, a space character, and model to create a new string full_name, which represents the complete name of the robot.

Run the code.

3-robot-strings

You should see the robot name, the first character, the modified robot name, and the full name printed in the terminal.

This example demonstrates the basic manipulation of strings in C++ for robotics. Strings are essential for working with text data, such as robot names, commands, or messages.

Employing Character Functions

Let’s explore how to employ character functions in C++ for robotics. Character functions are useful for manipulating and analyzing individual characters in a string.

Let’s create a new C++ file and name it robot_char_functions.cpp.

Type the following code into the editor:

#include <iostream>
#include <cctype>

using namespace std;

int main() {
    char command = 'f';

    // Checking character properties
    if (islower(command)) {
        cout << "Command is lowercase" << endl;
    }

    // Converting character case
    char uppercase_command = toupper(command);
    cout << "Uppercase Command: " << uppercase_command << endl;

    // Checking character equality
    if (command == 'f') {
        cout << "Command is 'f'" << endl;
    }

    return 0;
}

In this example, we demonstrate how to use character functions to check character properties, convert character case, and compare characters.

First, we include the <cctype> header to use the character functions. 

Then, we declare a character variable command and assign it the value ‘f’.

To check if a character is lowercase, we use the islower() function. It returns a non-zero value if the character is lowercase, and zero otherwise. 

We use an if statement to check the result and print a message if the command is lowercase.

To convert a character to uppercase, we use the toupper() function. It returns the uppercase equivalent of the character. We assign the result to a new character variable uppercase_command and print it.

To compare characters, we use the equality operator ==. In this case, we check if the command is equal to the character ‘f’. If the condition is true, we print a message indicating that the command is ‘f’.

Run the code.

4-robot-char-functions

You should see the messages indicating that the command is lowercase, the uppercase equivalent of the command, and that the command is ‘f’ printed in the terminal.

In robotic projects, you can use character functions for tasks such as validating user input, processing command strings, or analyzing sensor data that involves individual characters.

Keep building!

How to Use Operators and Control Flow in C++

In this tutorial, we will explore operators and control flow structures in C++, which are essential for creating logic and making decisions in your robotics programs.

Prerequisites

Using Mathematical Operators

Let’s look at an example of using mathematical operators in C++ for performing calculations in robotic projects.

Open a terminal window, and type this:

cd ~/Documents/cpp_tutorial
code .

Let’s create a new C++ file and name it robot_basic_math.cpp.

Type the following code into the editor:

#include <iostream>

int main() {
    // Basic arithmetic operations
    int motor_speed = 100;    // Base speed
    int speed_increment = 20; // Speed adjustment

    // Addition
    int increased_speed = motor_speed + speed_increment;
    
    // Subtraction
    int decreased_speed = motor_speed - speed_increment;
    
    // Multiplication
    int double_speed = motor_speed * 2;
    
    // Division
    int half_speed = motor_speed / 2;
    
    // Modulus (remainder)
    int remainder = motor_speed % 30;

    // Output results
    std::cout << "Original Speed: " << motor_speed << std::endl;
    std::cout << "Increased Speed: " << increased_speed << std::endl;
    std::cout << "Decreased Speed: " << decreased_speed << std::endl;
    std::cout << "Double Speed: " << double_speed << std::endl;
    std::cout << "Half Speed: " << half_speed << std::endl;
    std::cout << "Remainder: " << remainder << std::endl;

    return 0;
}

In this program, we demonstrate the five basic mathematical operators:

  • + for addition
  • – for subtraction
  • * for multiplication
  • / for division
  • % for modulus (remainder)

Run the code.

1-robot-basic-math

These operators are essential for various calculations in robotics, from adjusting motor speeds to processing sensor data.

Implementing Conditional and Logical Operators

Let’s explore the use of conditional and logical operators in C++ and their relevance to robotics. Conditional and logical operators are essential for making decisions and controlling the flow of your robotic programs.

Let’s create a new C++ file and name it robot_conditions.cpp.

Type the following code into the editor:

#include <iostream>

int main() {
    double battery_level = 0.75;
    bool obstacle_detected = true;

    if (battery_level > 0.5 && !obstacle_detected) {
        std::cout << "Robot is moving forward." << std::endl;
    } else if (battery_level > 0.5 && obstacle_detected) {
        std::cout << "Robot is avoiding the obstacle." << std::endl;
    } else {
        std::cout << "Robot is stopping due to low battery." << std::endl;
    }

    return 0;
}

In this code, we include the iostream header for input/output operations. Inside the main function, we declare variables for battery_level and obstacle_detected, representing the robot’s battery level and whether an obstacle is detected.

We then use conditional and logical operators to make decisions based on these variables. The if statement checks if the battery level is greater than 0.5 (using the > operator) and if no obstacle is detected (using the ! operator for logical NOT). If both conditions are true, the robot moves forward.

The else if statement checks if the battery level is greater than 0.5 and if an obstacle is detected. If both conditions are true, the robot avoids the obstacle.

Finally, the else statement is executed if none of the previous conditions are met, indicating that the robot is stopping due to low battery.

Run the code.

2-robot-conditions

You should see the appropriate message printed in the terminal based on the values of battery_level and obstacle_detected.

This example demonstrates how to use conditional and logical operators in C++ to make decisions based on the robot’s battery level and obstacle detection. 

Handling if, else if, and else statements

Let’s learn how to handle if, else if, and else statements in C++. These statements allow you to create complex decision-making structures in your robotic programs.

Let’s create a new C++ file and name it robot_decision_making.cpp.

Type the following code into the editor:

#include <iostream>

int main() {
    int distance_to_obstacle = 50;

    if (distance_to_obstacle < 30) {
        std::cout << "Robot is stopping to avoid collision." << std::endl;
    } else if (distance_to_obstacle < 60) {
        std::cout << "Robot is slowing down." << std::endl;
    } else if (distance_to_obstacle < 100) {
        std::cout << "Robot is moving forward cautiously." << std::endl;
    } else {
        std::cout << "Robot is moving forward at full speed." << std::endl;
    }

    return 0;
}

In this code, we include the iostream header for input/output operations. Inside the main function, we declare a variable distance_to_obstacle representing the distance between the robot and an obstacle.

We then use a series of if, else if, and else statements to make decisions based on the value of distance_to_obstacle.

The first if statement checks if the distance is less than 30 units. If true, the robot stops to avoid collision.

The first else if statement checks if the distance is less than 60 units. If true, the robot slows down.

The second else if statement checks if the distance is less than 100 units. If true, the robot moves forward cautiously.

Finally, the else statement is executed if none of the previous conditions are met, indicating that the robot can move forward at full speed.

Run the code.

3-robot-decision-making

You should see the appropriate message printed in the terminal based on the value of distance_to_obstacle.

Iterating with for loop

Let’s look at a concise example of using the for loop in C++ for iterating in robotic projects.

Let’s create a new C++ file and name it robot_for_loop_short.cpp.

Type the following code into the editor:

#include <iostream>

using namespace std;

int main() {
    int robot_positions[] = {0, 10, 20, 30, 40};

    for (int i = 0; i < 5; i++) {
        cout << "Robot Position: " << robot_positions[i] << endl;
    }

    return 0;
}

In this example, we demonstrate the use of the for loop to iterate over an array of robot positions.

We declare an array robot_positions that stores the positions of a robot at different points in time. 

We use a for loop to iterate over each position in the array. The loop starts from 0 and goes up to 4 (since there are 5 elements in the array). Inside the loop, we print the current robot position using cout.

Run the code.

4-robot-for-loop

You should see the robot positions printed in the terminal.

Using Ternary Operator

Let’s explore the use of the ternary operator in C++ for making concise conditional statements in robotic projects. The ternary operator allows you to write simple if-else statements in a single line of code.

Let’s create a new C++ file and name it robot_ternary_operator.cpp.

Type the following code into the editor:

#include <iostream>

using namespace std;

int main() {
    int battery_level = 75;
    int battery_threshold = 20;

    string battery_status = (battery_level > battery_threshold) ? "Sufficient" : "Low";
    cout << "Battery Status: " << battery_status << endl;

    int distance_to_obstacle = 30;
    int safety_distance = 50;

    string action = (distance_to_obstacle < safety_distance) ? "Stop" : "Continue";
    cout << "Action: " << action << endl;

    return 0;
}

In this example, we demonstrate the use of the ternary operator for making conditional statements.

First, we check the battery level of the robot. 

We compare the battery_level with the battery_threshold using the ternary operator. If the battery level is greater than the threshold, the ternary operator returns “Sufficient”; otherwise, it returns “Low”. The result is stored in the battery_status variable.

Next, we check the distance to an obstacle. We compare the distance_to_obstacle with the safety_distance using the ternary operator. If the distance to the obstacle is less than the safety distance, the ternary operator returns “Stop”; otherwise, it returns “Continue”. The result is stored in the action variable.

We print the battery status and the action using cout.

Run the code.

5-robot-ternary

You should see the battery status and the action printed in the terminal.

This example demonstrates how the ternary operator can be used to write concise conditional statements in C++ for robotic projects. The ternary operator has the following syntax:

(condition) ? expression1 : expression2

If the condition evaluates to true, expression1 is executed; otherwise, expression2 is executed. 

The ternary operator is a convenient way to write simple if-else statements in a single line of code, making your code more readable and concise.

Iterating with while loop

Let’s explore the use of the while loop in C++ for iterating and repeating code blocks in robotic projects. The while loop allows you to execute a block of code repeatedly as long as a specified condition is true.

Let’s create a new C++ file and name it robot_while_loop.cpp.

Type the following code into the editor:

#include <iostream>

using namespace std;

int main() {
    int distance = 0;
    int target_distance = 100;
    int step_size = 10;

    while (distance < target_distance) {
        distance += step_size;
        cout << "Robot moved " << distance << " units" << endl;
    }

    cout << "Robot reached the target distance." << endl;

    int countdown = 5;
    while (countdown > 0) {
        cout << "Countdown: " << countdown << endl;
        countdown--;
    }

    cout << "Countdown finished. Launching the robot!" << endl;

    return 0;
}

In this example, we demonstrate the use of the while loop for iterating and repeating code blocks.

First, we simulate the movement of a robot towards a target distance. We initialize the distance variable to 0 and set the target_distance to 100 units. We also define a step_size of 10 units.

We use a while loop to repeatedly move the robot by the step_size until the distance reaches or exceeds the target_distance. Inside the loop, we increment the distance by the step_size and print the current distance using cout.

Once the robot reaches the target distance, we print a message indicating that the target distance has been reached.

Next, we demonstrate a countdown using the while loop. We initialize the countdown variable to 5 and use a while loop to repeatedly decrement the countdown value and print it using cout. The loop continues until the countdown reaches 0.

After the countdown finishes, we print a message indicating that the countdown is finished and the robot is launching.

Run the code.

6-robot-while-loop

You should see the robot’s movement progress and the countdown sequence printed in the terminal.

This example demonstrates how the while loop can be used to iterate and repeat code blocks in C++ for robotic projects. The while loop continues to execute the code block as long as the specified condition is true. It’s important to ensure that the condition eventually becomes false to avoid an infinite loop.

Using break and continue statements

Let’s look at a concise example of using the break and continue statements in C++ for controlling the flow of loops in robotic projects.

Let’s create a new C++ file and name it robot_break_continue_concise.cpp.

Type the following code into the editor:

#include <iostream>

using namespace std;

int main() {
    int distances[] = {10, 20, 5, 30, 15};
    int max_distance = 25;

    for (int i = 0; i < 5; i++) {
        if (distances[i] > max_distance) {
            cout << "Distance exceeds maximum limit. Stopping robot." << endl;
            break;
        }
        if (distances[i] < 10) {
            cout << "Distance too short. Skipping iteration." << endl;
            continue;
        }
        cout << "Moving robot " << distances[i] << " units." << endl;
    }

    return 0;
}

In this example, we demonstrate the use of break and continue statements in a loop that controls a robot’s movement based on distances.

We define an array of distances that represents the distances the robot needs to move in each iteration. 

We also define a max_distance variable to set the maximum allowable distance.

We use a for loop to iterate over the distances. Inside the loop, we first check if the current distance exceeds the max_distance. If it does, we print a message indicating that the maximum distance limit is exceeded and use the break statement to stop the robot and exit the loop.

If the distance is within the maximum limit, we then check if the distance is less than 10 units. If it is, we consider the distance too short and use the continue statement to skip the current iteration and move to the next one.

If the distance is within the acceptable range, we print a message indicating that the robot is moving the specified distance.

Run the code.

7-robot-break-continue

You should see the messages related to the robot’s movement and the effects of the break and continue statements printed in the terminal.

This example demonstrates how the break and continue statements can be used to control the flow of a loop based on specific conditions in a robotics scenario. 

The break statement is used to stop the robot’s movement if the distance exceeds the maximum limit, while the continue statement is used to skip iterations where the distance is too short.

These statements allow you to handle different situations and make decisions within the loop, providing flexibility in controlling the robot’s behavior.

Implementing do-while loop

Let’s explore the use of the do-while loop in C++ for robotics. The do-while loop is similar to the while loop, but it guarantees that the code block is executed at least once before checking the loop condition.

Let’s create a new C++ file and name it robot_do_while_loop.cpp.

Type the following code into the editor:

#include <iostream>

using namespace std;

int main() {
    int count = 0;

    do {
        cout << "Robot iteration: " << count << endl;
        count++;
    } while (count < 3);

    return 0;
}

In this example, we demonstrate the use of the do-while loop to iterate a fixed number of times.

We declare a variable count and initialize it to 0. We start the do-while loop, which begins by executing the code block inside the loop. Inside the loop, we print the current iteration number using cout and increment the count variable.

After executing the code block, the loop checks the condition count < 3. If the condition is true, the loop continues to the next iteration. If the condition is false, the loop terminates.

Run the code.

8-robot-do-while-loop

You should see the robot iterations printed in the terminal.

This example demonstrates the basic usage of the do-while loop in C++ for robotics. The do-while loop is useful when you want to ensure that the code block is executed at least once, regardless of the initial condition.

In robotic projects, the do-while loop can be used in scenarios where you want to perform an action or collect data at least once before checking a condition. For example, you might use a do-while loop to ensure that a sensor is read at least once before checking if the reading meets a certain threshold.

That’s it. Thanks, and I’ll see you in the next tutorial.


Keep building!