Python 3 for Robotics – Foundations

Course Description

Welcome, future roboticist! This 16-week course is your launchpad into the exciting world of robotics using Python 3, one of the most powerful and beginner-friendly programming languages on the planet. We'll start from the absolute basics of Python and steadily build your skills until you're controlling hardware, reading sensors, and making intelligent decisions with code. This course is designed for anyone with a spark of curiosity—no prior programming or electronics experience required. We'll move from blinking an LED to building a functional obstacle-avoiding robot. Get ready to turn your ideas into physical reality!

Primary Learning Objectives

Upon successful completion of this course, you will be able to:

  • Master the fundamentals of Python 3 programming, including variables, control flow, functions, and data structures.
  • Apply Object-Oriented Programming (OOP) principles to create clean, modular, and scalable robotics software.
  • Interface with hardware like LEDs, buttons, sensors, and motors using a Raspberry Pi or similar microcontroller.
  • Read and interpret sensor data to allow your robot to perceive its environment.
  • Implement basic robotics algorithms for movement, control, and simple navigation.
  • Understand the fundamentals of computer vision and how to use it in robotics applications.
  • Build and program a complete robotics project from scratch.

Prerequisites & Materials

Software (Free):

  • Python 3: We'll be using the latest version of Python 3.
  • Visual Studio Code (VS Code): A recommended, free code editor with excellent Python support.
  • Git & GitHub Account: For version control (a good habit to learn!).
  • A Single-Board Computer: A Raspberry Pi 4 (or newer) is highly recommended. An Arduino can also be used, especially for Week 11.
  • A Robotics Starter Kit: Many kits are available online. Look for one that includes:
    • A breadboard and jumper wires
    • LEDs and resistors
    • Push buttons
    • An ultrasonic distance sensor (like the HC-SR04)
    • A servo motor and a DC motor with a motor driver (like the L298N)
    • A simple robot chassis with wheels
    • A portable power source for the Raspberry Pi/motors.

Course Structure

The course is divided into 14 weekly lessons, followed by a 2-week final project. Each week builds upon the last, taking you on a structured journey from software principles to hardware application.


Part 1: Python Fundamentals (Weeks 1-4)

Lesson 1: Introduction to Python and Your Robotics Lab Setup

  • Learning Objectives:

    1. Understand why Python is a premier language for robotics.
    2. Set up your complete development environment (Python and VS Code).
    3. Write and run your first Python script: the classic "Hello, World!".
  • Key Vocabulary:

    • Python: A high-level, interpreted programming language known for its readability and extensive libraries.
    • Interpreter: A program that directly executes instructions written in a programming language, one line at a time.
    • IDE (Integrated Development Environment): A software application that provides comprehensive facilities to computer programmers for software development (e.g., VS Code).
    • Syntax: The set of rules that defines the combinations of symbols that are considered to be correctly structured statements or expressions in a language.
  • Lesson Content:
    Hello there! Welcome to your first week. So, why Python for robotics? Imagine you need to give instructions to a robot. You could use a very complex, low-level language (like talking in binary code), or you could use a language that's closer to how humans speak. Python is like the latter. It's readable, powerful (thanks to a massive community building tools for it), and fast to develop with, which means you can prototype your robot ideas quickly!

    Our first mission is to set up your digital workshop.

    1. Install Python 3: Head over to the official Python website (python.org), download the latest version for your operating system, and run the installer. Crucially, make sure to check the box that says "Add Python to PATH" during installation. This makes it easier to run Python from your command line.
    2. Install VS Code: Go to the Visual Studio Code website (code.visualstudio.com) and install it. Once installed, open it and go to the Extensions tab (the little blocks icon on the left). Search for and install the official "Python" extension by Microsoft. This will give you awesome features like code completion and debugging.

    Now, let's make the computer talk! In VS Code, create a new file and save it as hello.py. The .py extension tells the computer this is a Python file. In that file, type the following:

    # This is my first Python program!
    # The print() function displays text on the screen.
    print("Hello, Robot World!")
    

    To run this, you can open a terminal (or command prompt) in VS Code (View -> Terminal), and type python hello.py and press Enter. You should see Hello, Robot World! printed out. Congratulations, you are now officially a Python programmer! 🎉

  • Practical Hands-on Example:
    Modify your hello.py script. Create a "dialogue" for a robot. Use multiple print() statements to make the robot introduce itself and state its mission. For example:

    print("--- Booting sequence initiated ---")
    print("Hello! My name is PR-01.")
    print("My mission is to learn and explore.")
    print("--- System ready ---")
    

Lesson 2: Variables, Data Types, and Basic Math

  • Learning Objectives:

    1. Understand and use variables to store information.
    2. Differentiate between core data types: integers, floats, strings, and booleans.
    3. Perform mathematical operations in Python to manipulate data.
  • Key Vocabulary:

    • Variable: A symbolic name that is a reference or pointer to an object. Once an object is assigned to a variable, you can refer to the object by that name. Think of it as a labeled box where you store information.
    • Data Type: A classification that specifies which type of value a variable has and what type of mathematical, relational, or logical operations can be applied to it without causing an error.
    • Integer (int): A whole number (e.g., 10, -5, 0).
    • Float (float): A number with a decimal point (e.g., 3.14, -0.001).
    • String (str): A sequence of characters, enclosed in quotes (e.g., "Hello", 'robot').
    • Boolean (bool): A data type with two possible values: True or False.
  • Lesson Content:
    For a robot to be useful, it needs to remember things. It needs to store its current speed, the distance to a wall, or its name. In programming, we use variables for this. A variable is just a name you give to a piece of data.

    Let's look at the main types of data you'll be storing:

    • Integers (int): For counting things, like the number of wheels on your robot.
      number_of_wheels = 4
    • Floats (float): For measurements that need precision, like battery voltage or the exact distance to an object.
      battery_voltage = 11.8
    • Strings (str): For any text data, like the robot's name or a status message.
      robot_name = "Bumblebee"
    • Booleans (bool): For states that are either on or off, true or false. Is the gripper holding an object? Is an obstacle detected?
      obstacle_detected = False

    You can perform math with these variables, which is crucial for robotics!

    # Let's calculate the speed of a robot
    distance_cm = 100  # an integer
    time_seconds = 5.5 # a float
    
    # Speed = Distance / Time
    speed_cm_per_second = distance_cm / time_seconds
    
    # We can print the result, and also check its type
    print("Calculating robot speed...")
    print(f"The robot's speed is: {speed_cm_per_second} cm/s") # The 'f' before the string is called an f-string, a modern way to format strings!
    print(f"The data type of the speed variable is: {type(speed_cm_per_second)}")
    

    In robotics, you'll constantly be doing calculations—converting sensor readings, calculating angles for an arm, or determining motor power. Mastering these basics is a key first step.

  • Practical Hands-on Example:
    Write a Python script named battery_calc.py.

    1. Create a variable max_voltage and set it to 12.6.
    2. Create a variable current_voltage and set it to 11.2.
    3. Calculate the remaining battery percentage using the formula: percentage = (current_voltage / max_voltage) * 100.
    4. Print a user-friendly message like: "Battery level: 88.88% remaining.". Try to format the output to only show two decimal places. (Hint: You can use round(your_variable, 2)).

Lesson 3: Control Flow: Conditionals and Loops

  • Learning Objectives:

    1. Make decisions in code using if, elif, and else statements.
    2. Repeat actions using for and while loops.
    3. Combine conditionals and loops to create simple logic.
  • Key Vocabulary:

    • Control Flow: The order in which individual statements, instructions, or function calls of an imperative program are executed or evaluated.
    • Conditional Statement (if/elif/else): A feature of a programming language which performs different computations or actions depending on whether a programmer-specified boolean condition evaluates to true or false.
    • Loop: A sequence of instructions that is continually repeated until a certain condition is reached.
    • for loop: A loop that iterates over a sequence (like a list) or a range of numbers.
    • while loop: A loop that repeats as long as a certain condition is true.
  • Lesson Content:
    A robot that just runs commands in a straight line isn't very smart. An intelligent robot needs to make decisions and repeat actions. This is where control flow comes in.

    Making Decisions with if Statements
    Think about an obstacle-avoiding robot. The core logic is: IF an obstacle is close, THEN stop. Otherwise, keep moving. We write this in Python using if, elif (else if), and else.

    distance_to_wall_cm = 25
    
    if distance_to_wall_cm < 20:
        print("Obstacle detected! Stopping motors.")
    elif distance_to_wall_cm < 50:
        print("Caution, object nearby. Slowing down.")
    else:
        print("Path is clear. Full speed ahead!")
    

    This code checks a condition. If the first if is true, its block runs and the rest are skipped. If not, it checks the elif. If none are true, the else block runs.

    Repeating Actions with Loops
    What if you want a robot arm to pick up 5 blocks? You wouldn't write pick_up_block() five times. You'd use a loop!

    The for loop is great for when you know how many times you want to repeat something.

    # The range(5) function generates numbers from 0 to 4.
    for i in range(5):
        print(f"Picking up block number {i + 1}...")
    print("All blocks collected!")
    

    The while loop is perfect for when you want to repeat an action until a condition changes. For example, a robot moving forward until it detects an obstacle.

    # A simple simulation
    battery_charge = 100
    while battery_charge > 20:
        print(f"Robot is active. Battery at {battery_charge}%.")
        battery_charge = battery_charge - 10 # Drains 10% each cycle
    
    print("Battery low! Returning to charging station.")
    

    This loop will continue running as long as battery_charge is greater than 20. This is the foundation for creating responsive, persistent robot behaviors.

  • Practical Hands-on Example:
    Write a script sensor_check.py that simulates a temperature sensor in a robot.

    1. Create a variable core_temp and set it to a value like 85.
    2. Use an if-elif-else structure to check the temperature:
      • If core_temp > 80, print a "WARNING: Core temperature critical! Initiating cooling system." message.
      • If core_temp > 60, print "Core temperature is high. Increasing fan speed."
      • Otherwise, print "Core temperature is normal."
    3. Add a for loop that counts down from 5 to 1, printing "Cooling system active in… [number]" inside the first if block, to simulate a countdown.

Lesson 4: Functions and Modules: Building Reusable Code

  • Learning Objectives:

    1. Define and call custom functions to organize code.
    2. Understand the difference between parameters and return values.
    3. Import and use modules to access pre-written code, like the math and time modules.
  • Key Vocabulary:

    • Function: A block of organized, reusable code that is used to perform a single, related action.
    • Parameter: A variable listed inside the parentheses in the function definition. It's the input to the function.
    • Return Value: The data that a function gives back after it has finished its job.
    • Module: A file containing Python definitions and statements. Modules are used to break down large programs into smaller, manageable files.
    • Import: The process of bringing the code from one module into another.
  • Lesson Content:
    As our robot programs get more complex, we don't want to write the same code over and over. If we need to calculate the distance from a sensor reading multiple times, we should write that logic once and reuse it. We do this with functions.

    A function is like a mini-program within your program. You give it a name, tell it what data it needs (parameters), and it does a job. It can also give you back a result (a return value).

    # This function defines how to convert a sensor reading to centimeters
    def convert_ultrasonic_reading_to_cm(reading):
        # Let's pretend the conversion factor is 0.343
        distance = reading * 0.343
        return distance # This sends the calculated value back
    
    # Now we can use (or "call") our function
    sensor_value_1 = 50
    distance_1 = convert_ultrasonic_reading_to_cm(sensor_value_1)
    print(f"Sensor reading {sensor_value_1} corresponds to {distance_1} cm.")
    
    sensor_value_2 = 120
    distance_2 = convert_ultrasonic_reading_to_cm(sensor_value_2)
    print(f"Sensor reading {sensor_value_2} corresponds to {distance_2} cm.")
    

    See how we avoided writing the calculation * 0.343 twice? This makes our code cleaner and easier to fix. If the conversion factor changes, we only need to update it in one place!

    But what if the function we need has already been written by someone else? That's where modules come in. Python has a huge standard library of modules. For example, the math module gives us advanced math functions, and the time module lets us pause our program.

    import math  # Gives us access to the math module
    import time  # Gives us access to the time module
    
    # Using the math module to find a square root
    number = 64
    sqrt_number = math.sqrt(number)
    print(f"The square root of {number} is {sqrt_number}.")
    
    # Using the time module to pause the program
    print("Moving forward...")
    time.sleep(2) # Pauses the program for 2 seconds
    print("...and stopped.")
    

    Modules are the building blocks of large applications. In robotics, we will import modules to control hardware, perform complex calculations, and much more.

  • Practical Hands-on Example:
    Create a script motor_control.py.

    1. Write a function called calculate_motor_speed that takes two parameters: desired_speed_percent and max_rpm (revolutions per minute).
    2. Inside the function, calculate the target RPM by converting the percentage. The formula is target_rpm = max_rpm * (desired_speed_percent / 100).
    3. The function should return the target_rpm.
    4. Call your function with a speed of 75% and a max_rpm of 150.
    5. Print the result in a clear message: "To achieve 75% speed, set motor RPM to [result].".

Part 2: Intermediate Python and Data Structures (Weeks 5-7)

Lesson 5: Data Structures: Lists, Tuples, and Dictionaries

  • Learning Objectives:

    1. Store and manipulate sequences of data using lists.
    2. Understand the difference between mutable lists and immutable tuples.
    3. Store key-value pairs of data using dictionaries.
  • Key Vocabulary:

    • Data Structure: A particular way of organizing and storing data in a computer so that it can be accessed and modified efficiently.
    • List: A collection which is ordered and changeable (mutable). Allows duplicate members. Written with square brackets [].
    • Tuple: A collection which is ordered and unchangeable (immutable). Allows duplicate members. Written with round brackets ().
    • Dictionary: A collection which is unordered, changeable and indexed. No duplicate keys. Written with curly brackets {} and consists of key-value pairs.
  • Lesson Content:
    So far, we've stored single pieces of data in variables. But what if we need to store a path for our robot—a sequence of movements? Or a list of sensor readings? We need more powerful containers: data structures.

    Lists: Your Go-To Collection
    A list is an ordered, changeable collection of items. It's your most common tool for storing sequences.

    # A list of waypoints for a robot to visit (in meters)
    waypoints_x = [1.0, 2.5, 3.0, 2.5]
    waypoints_y = [0.5, 1.0, 2.5, 3.0]
    
    # You can access items by their index (starting from 0)
    first_x = waypoints_x[0] 
    print(f"First X waypoint is: {first_x}")
    
    # You can add items
    waypoints_x.append(1.0)
    print(f"New waypoints: {waypoints_x}")
    
    # You can loop through a list
    print("--- Waypoint Log ---")
    for x in waypoints_x:
        print(f"Navigating to X coordinate: {x}")
    

    Tuples: Lists That Can't Be Changed
    A tuple is just like a list, but it's immutable—once you create it, you can't change it. Why is this useful? For data that should never change, like the fixed RGB values for a color or a robot's hardware configuration.

    # (Red, Green, Blue) color definition
    RED_COLOR = (255, 0, 0)
    # RED_COLOR[0] = 100 # This would cause an error!
    print(f"Red is defined as: {RED_COLOR}")
    

    Dictionaries: Labeled Information
    What if you want to store information about your robot, but with labels? A list ["RoverX", 5.5, 4, True] is confusing. What do those values mean? A dictionary solves this by storing data in key-value pairs.

    robot_config = {
        "name": "RoverX",
        "weight_kg": 5.5,
        "num_wheels": 4,
        "is_active": True
    }
    
    # Access data using the key
    print(f"Robot name: {robot_config['name']}")
    
    # Add a new key-value pair
    robot_config['battery_type'] = "LiPo"
    print(f"Robot configuration: {robot_config}")
    

    Dictionaries are perfect for managing settings, sensor data from multiple sources, or the state of your robot.

  • Practical Hands-on Example:
    Create a script sensor_fusion.py.

    1. Create a list called temp_readings and add five floating-point temperature readings to it (e.g., [22.5, 23.1, 22.8, 22.5, 23.0]).
    2. Write a for loop to calculate the average temperature from the list. Print the average.
    3. Create a dictionary called robot_sensors that maps sensor names (strings) to their status (booleans). For example: {"ultrasonic": True, "camera": True, "lidar": False}.
    4. Write an if statement that checks if the "camera" is True and prints a confirmation message if it is.

Lesson 6: Object-Oriented Programming (OOP) for Robotics

  • Learning Objectives:

    1. Understand the concepts of classes and objects.
    2. Create a simple class to represent a robot component (like a motor).
    3. Use methods and attributes to define the behavior and state of an object.
  • Key Vocabulary:

    • Object-Oriented Programming (OOP): A programming paradigm based on the concept of "objects", which can contain data in the form of fields (often known as attributes or properties), and code, in the form of procedures (often known as methods).
    • Class: A blueprint for creating objects. It defines a set of attributes and methods that the created objects will have.
    • Object (or Instance): A specific realization of a class. If Car is a class, a specific red convertible is an object (or instance) of that class.
    • Attribute: A variable that belongs to an object (e.g., motor.speed).
    • Method: A function that belongs to an object (e.g., motor.start()).
    • __init__ (Constructor): A special method that Python calls automatically when you create a new object from a class, used to initialize its attributes.
  • Lesson Content:
    This is a big step! So far, we've used variables and functions that are separate from each other. Object-Oriented Programming (OOP) lets us bundle data (attributes) and the functions that operate on that data (methods) together into a neat package called an object.

    The blueprint for an object is a class. Let's design a class for a robot's motor. What does a motor have? A speed, a direction, and maybe a pin number it's connected to. These are its attributes. What can a motor do? It can start, stop, and change speed. These are its methods.

    class Motor:
        # The __init__ method is the constructor. It runs when we create a new Motor object.
        # 'self' refers to the specific instance of the object being created.
        def __init__(self, pin_number):
            self.pin = pin_number
            self.speed = 0  # Motors start with a speed of 0
            self.is_running = False
            print(f"Motor configured on pin {self.pin}.")
    
        # This is a method. It's a function inside a class.
        def start(self, speed_percent):
            if not self.is_running:
                self.speed = speed_percent
                self.is_running = True
                print(f"Motor on pin {self.pin} started at {self.speed}% speed.")
            else:
                print(f"Motor on pin {self.pin} is already running.")
    
        def stop(self):
            if self.is_running:
                self.speed = 0
                self.is_running = False
                print(f"Motor on pin {self.pin} stopped.")
    
    # Now, let's create two objects (instances) from our Motor class blueprint
    left_motor = Motor(pin_number=17)
    right_motor = Motor(pin_number=18)
    
    # We can now control them independently using their methods
    left_motor.start(speed_percent=80)
    right_motor.start(speed_percent=80)
    
    time.sleep(2) # Assume this is imported
    
    left_motor.stop()
    right_motor.stop()
    

    Why is this so powerful for robotics? Because a robot is a collection of objects! You can have a Robot object that is composed of two Motor objects, a Sensor object, and a Gripper object. This approach keeps your code incredibly organized, reusable, and easy to understand.

  • Practical Hands-on Example:
    Create a script robot_arm.py.

    1. Design a Servo class for a servo motor (the kind used in robot arms).
    2. In the __init__ method, it should accept a pin_number and a name (e.g., "shoulder_servo"). It should also have an attribute angle initialized to 90 degrees.
    3. Create a method called move_to_angle(self, target_angle). This method should update the self.angle attribute and print a message like "Servo 'shoulder_servo' moving to 45 degrees.".
    4. Create an object of your Servo class.
    5. Call the move_to_angle method a couple of times to simulate moving the arm.

Lesson 7: File I/O and Error Handling: Making Your Robot Remember

  • Learning Objectives:

    1. Read data from and write data to text files.
    2. Understand how to handle potential errors gracefully using try...except blocks.
    3. Apply file I/O to save and load a robot's configuration.
  • Key Vocabulary:

    • File I/O (Input/Output): The process of reading from and writing to files on a disk.
    • Exception: An error that occurs during the execution of a program.
    • try...except block: A construct in Python used for exception handling. The code in the try block is executed, and if an exception occurs, the code in the except block is run.
  • Lesson Content:
    What happens if your robot's battery dies? Does it forget everything it learned? Not if we save its state to a file! File I/O is how we make our programs persistent.

    Writing to a File
    Let's save our robot's configuration to a file. The with open(...) as f: syntax is the best practice, as it automatically handles closing the file for you.

    import json # JSON is a great format for storing dictionaries
    
    robot_config = {
        "name": "RoverX",
        "last_mission": "Explore the living room",
        "missions_completed": 12,
        "max_speed": 0.5 # m/s
    }
    
    # 'w' means write mode. This will create the file if it doesn't exist, or overwrite it if it does.
    with open('config.json', 'w') as f:
        json.dump(robot_config, f, indent=4) # json.dump writes a dictionary to a file in a nice format
    
    print("Configuration saved!")
    

    Reading from a File
    Now, let's have our robot read this configuration when it boots up.

    import json
    
    # 'r' means read mode
    with open('config.json', 'r') as f:
        loaded_config = json.load(f) # json.load reads a json file into a dictionary
    
    print("Configuration loaded!")
    print(f"Welcome back, {loaded_config['name']}!")
    

    Handling Errors with try...except
    But what if the config.json file doesn't exist? Our program will crash! That's unacceptable for a robot. We need to anticipate and handle errors using a try...except block.

    import json
    
    try:
        # Try to do something that might fail
        with open('config.json', 'r') as f:
            loaded_config = json.load(f)
            print(f"Configuration loaded for {loaded_config['name']}.")
    except FileNotFoundError:
        # This block only runs if a FileNotFoundError occurs
        print("Config file not found. Using default settings.")
        loaded_config = {"name": "DefaultBot", "max_speed": 0.2}
    except Exception as e:
        # This is a general catch-all for any other errors
        print(f"An unexpected error occurred: {e}")
    
    print("Robot boot sequence complete.")
    

    This makes our robot robust. If something goes wrong, it doesn't just give up; it handles the problem and continues.

  • Practical Hands-on Example:
    Write a data logging script log_sensor.py.

    1. Create a function log_data(sensor_name, value).
    2. Inside the function, use with open('sensor_log.txt', 'a') as f: to open a file. The 'a' stands for append mode, which adds to the end of the file instead of overwriting it.
    3. The function should write a formatted string to the file, like "[TIMESTAMP] - Sensor: [sensor_name], Value: [value]\n". (You can import the datetime module to get a real timestamp!).
    4. Use a try...except block around your main code.
    5. Call your function a few times to log data for a "temperature" sensor and a "distance" sensor. Run the script. Check the contents of sensor_log.txt.

Part 3: Python for Hardware Interaction (Weeks 8-11)

Lesson 8: Introduction to GPIO and Interfacing with the Real World

  • Learning Objectives:

    1. Understand what GPIO pins are and how they work.
    2. Use the RPi.GPIO Python library to control an LED (turn it on, off, and make it blink).
    3. Read input from a physical button.
  • Key Vocabulary:

    • GPIO (General Purpose Input/Output): Pins on a physical computing board (like a Raspberry Pi) whose behavior can be controlled by the user at run time.
    • RPi.GPIO: A Python library that allows you to easily control the GPIO pins on a Raspberry Pi.
    • Output Pin: A GPIO pin configured to send a voltage out (e.g., to power an LED).
    • Input Pin: A GPIO pin configured to read an incoming voltage (e.g., to detect a button press).
    • Breadboard: A construction base for prototyping of electronics.
  • Lesson Content:
    Alright, it's time to bridge the gap between software and the physical world! Your Raspberry Pi has a set of pins called GPIO pins. Think of these as light switches that your Python code can flip on and off. We can configure a pin as an output to send power out (to turn on an LED) or as an input to read power in (to see if a button is pressed).

    We'll use a library called RPi.GPIO to control these pins. Let's start with the "Hello, World!" of hardware: blinking an LED.

    Physical Setup:
    You'll need a breadboard, an LED, a resistor (around 330 Ohm is good), and jumper wires. Connect a GPIO pin (e.g., pin 17) to the long leg (anode) of the LED, connect the short leg (cathode) to the resistor, and connect the other end of the resistor to a Ground (GND) pin on the Pi.

    The Code:

    import RPi.GPIO as GPIO
    import time
    
    # Set up our pin numbering system
    GPIO.setmode(GPIO.BCM) # Use the BCM pin numbering
    GPIO.setwarnings(False)
    
    LED_PIN = 17 # The pin number we connected our LED to
    
    # Set up our pin as an output
    GPIO.setup(LED_PIN, GPIO.OUT)
    
    print("Blinking LED... Press CTRL+C to stop.")
    
    try:
        while True: # Loop forever
            print("LED ON")
            GPIO.output(LED_PIN, GPIO.HIGH) # Send 3.3V to the pin
            time.sleep(1) # Wait 1 second
    
            print("LED OFF")
            GPIO.output(LED_PIN, GPIO.LOW) # Send 0V to the pin
            time.sleep(1) # Wait 1 second
    
    except KeyboardInterrupt:
        print("Program stopped.")
    finally:
        GPIO.cleanup() # This resets the GPIO pins to their default state
    

    This code sets up pin 17 as an output, then enters an infinite loop, turning the pin HIGH (on) and LOW (off) with a 1-second pause in between. The try...finally block ensures that even if we stop the program, GPIO.cleanup() is called.

    Reading a button is the reverse. We set up a pin as an INPUT and use GPIO.input(PIN_NUMBER) to see if it's HIGH or LOW.

  • Practical Hands-on Example:
    Create a "traffic light" simulator.

    1. Connect three LEDs (red, yellow, green) to three different GPIO pins.
    2. Write a Python script that loops through a traffic light sequence:
      • Green ON for 3 seconds.
      • Yellow ON for 1 second.
      • Red ON for 3 seconds.
    3. (Bonus Challenge): Add a button. When the button is pressed, the light sequence should start.

Lesson 9: Working with Sensors: Reading the Environment

  • Learning Objectives:

    1. Understand the difference between digital and analog sensors.
    2. Interface with a digital sensor, the HC-SR04 ultrasonic distance sensor.
    3. Write a Python script to measure distance and print it to the console.
  • Key Vocabulary:

    • Sensor: A device that detects or measures a physical property and records, indicates, or otherwise responds to it.
    • Digital Sensor: A sensor that outputs discrete values (usually ON/OFF or a sequence of digital bits).
    • Analog Sensor: A sensor that outputs a continuous range of voltage values. (Note: Raspberry Pi doesn't have built-in analog inputs, requiring an ADC chip, but it's good to know the concept).
    • Ultrasonic Sensor: A sensor that measures distance by sending out a sound wave and listening for the echo.
  • Lesson Content:
    For a robot to act intelligently, it needs to perceive its environment. Sensors are its eyes and ears. Today, we'll work with one of the most common sensors in hobby robotics: the HC-SR04 ultrasonic distance sensor.

    How does it work?

    1. You tell its "Trig" (Trigger) pin to send out a short ultrasonic pulse.
    2. You then listen on its "Echo" pin. The pin will go HIGH, and the length of time it stays HIGH is proportional to how long it took the sound to travel to an object and bounce back.
    3. Knowing the speed of sound, we can calculate the distance from this time duration.

    Physical Setup:
    The HC-SR04 has 4 pins: VCC (to 5V power), Trig (to a GPIO output pin), Echo (to a GPIO input pin), and GND (to Ground).

    The Code:

    import RPi.GPIO as GPIO
    import time
    
    GPIO.setmode(GPIO.BCM)
    
    TRIG_PIN = 23
    ECHO_PIN = 24
    
    GPIO.setup(TRIG_PIN, GPIO.OUT)
    GPIO.setup(ECHO_PIN, GPIO.IN)
    
    def measure_distance():
        # Send a 10 microsecond pulse to trigger the sensor
        GPIO.output(TRIG_PIN, True)
        time.sleep(0.00001)
        GPIO.output(TRIG_PIN, False)
    
        # Wait for the echo to start
        while GPIO.input(ECHO_PIN) == 0:
            pulse_start_time = time.time()
    
        # Wait for the echo to end
        while GPIO.input(ECHO_PIN) == 1:
            pulse_end_time = time.time()
    
        pulse_duration = pulse_end_time - pulse_start_time
    
        # Speed of sound is ~34300 cm/s. The sound travels to the object AND back, so we divide by 2.
        distance = (pulse_duration * 34300) / 2
        return distance
    
    try:
        while True:
            dist = measure_distance()
            print(f"Distance: {dist:.2f} cm") # Format to 2 decimal places
            time.sleep(1)
    
    except KeyboardInterrupt:
        print("Measurement stopped.")
    finally:
        GPIO.cleanup()
    

    This script encapsulates the logic in a measure_distance function. It sends a trigger pulse, times the echo response, and then performs the calculation. Now your robot can "see" objects in front of it!

  • Practical Hands-on Example:
    Create a "parking assistant" script.

    1. Set up your ultrasonic sensor.
    2. Set up a single LED.
    3. Write a script that continuously measures the distance.
    4. Use if/elif/else logic to control the LED:
      • If the distance is greater than 50 cm, the LED is off.
      • If the distance is between 20 cm and 50 cm, the LED blinks slowly (1 second on, 1 second off).
      • If the distance is less than 20 cm, the LED blinks rapidly (0.2 seconds on, 0.2 seconds off).

Lesson 10: Controlling Motors: Making Things Move!

  • Learning Objectives:

    1. Understand the difference between servo motors and DC motors.
    2. Control the position of a servo motor using PWM.
    3. Control the speed and direction of a DC motor using an H-Bridge motor driver (like the L298N).
  • Key Vocabulary:

    • Actuator: A component of a machine that is responsible for moving and controlling a mechanism or system. Motors are actuators.
    • Servo Motor: A motor that allows for precise control of angular position. You can tell it to go to a specific angle (e.g., 90 degrees).
    • DC Motor: A motor that rotates continuously when power is applied. You can control its speed and direction.
    • PWM (Pulse Width Modulation): A technique for getting analog results with digital means. By varying the width of a digital pulse, we can control the speed of a DC motor or the angle of a servo.
    • H-Bridge: An electronic circuit that enables a voltage to be applied across a load in either direction. It's essential for controlling the direction of a DC motor. The L298N is a popular H-Bridge module.
  • Lesson Content:
    Movement is the essence of robotics! Let's explore the two most common types of motors.

    Servo Motors: For Precision
    Servos are for tasks needing precise angles, like a robot arm joint or a camera pan/tilt mechanism. We control them using PWM. The RPi.GPIO library makes this easy. A PWM signal has a frequency (e.g., 50Hz for servos) and a duty cycle (the percentage of time the signal is 'on'). For a typical servo, a 2.5% duty cycle might be 0 degrees, 7.5% might be 90 degrees, and 12.5% might be 180 degrees.

    import RPi.GPIO as GPIO
    import time
    
    GPIO.setmode(GPIO.BCM)
    SERVO_PIN = 18
    GPIO.setup(SERVO_PIN, GPIO.OUT)
    
    # Create a PWM object: 50Hz frequency
    pwm = GPIO.PWM(SERVO_PIN, 50) 
    pwm.start(0) # Start with 0 duty cycle
    
    def set_angle(angle):
        # Convert angle (0-180) to duty cycle (2.5-12.5)
        duty_cycle = (angle / 18) + 2.5
        pwm.ChangeDutyCycle(duty_cycle)
        time.sleep(0.5) # Give the servo time to move
    
    try:
        print("Moving servo...")
        set_angle(0)
        set_angle(90)
        set_angle(180)
        set_angle(90)
    
    finally:
        pwm.stop()
        GPIO.cleanup()
    

    DC Motors: For Locomotion
    DC motors are the workhorses for driving wheels. They just spin! To control their direction, we need an H-Bridge, like the L298N module. To control their speed, we use PWM again. An H-bridge typically needs three pins per motor: one for PWM (speed), and two digital pins to set direction (e.g., IN1=HIGH, IN2=LOW for forward; IN1=LOW, IN2=HIGH for backward).

  • Practical Hands-on Example:
    Build a simple two-wheeled robot base.

    1. Connect two DC motors to an L298N motor driver, and connect the driver to your Raspberry Pi.
    2. Write a Python script with functions for forward(), backward(), turn_left(), and turn_right().
    3. forward() should make both motors spin in the same direction.
    4. turn_left() could make the right motor go forward and the left motor go backward.
    5. In your main script, call these functions in sequence to make your robot drive in a square. For example: forward() for 2 seconds, then turn_right() for 1 second, and repeat four times.

Lesson 11: Serial Communication: Talking to Microcontrollers

  • Learning Objectives:

    1. Understand the basics of serial communication.
    2. Use the pyserial library to send and receive data between a Raspberry Pi and another device (like an Arduino or your PC).
    3. Design a simple communication protocol.
  • Key Vocabulary:

    • Serial Communication: The process of sending data one bit at a time, sequentially, over a communication channel.
    • UART (Universal Asynchronous Receiver-Transmitter): A hardware device for asynchronous serial communication. The Raspberry Pi has UART pins.
    • pyserial: A Python library that provides access to the serial port.
    • Baud Rate: The rate at which information is transferred in a communication channel. Both devices must be set to the same baud rate (e.g., 9600).
    • Protocol: A set of rules or procedures for transmitting data between two or more devices.
  • Lesson Content:
    Sometimes, the Raspberry Pi isn't the best tool for every single job. A microcontroller like an Arduino is often better at very fast, real-time tasks like controlling complex motor movements (e.g., for a walking robot). In these cases, we use the Raspberry Pi as the "brain" and the Arduino as the "muscle controller." How do they talk to each other? Through serial communication.

    The Pi sends commands (like "move forward at 50% speed") over a single wire (the TX or transmit pin), and the Arduino receives it on its RX (receive) pin. The Arduino can then send sensor data back.

    To do this in Python, we use the excellent pyserial library. First, you'll need to install it: pip install pyserial.

    Here's how the Python code on the Raspberry Pi might look:

    import serial
    import time
    
    try:
        # Open the serial port. The port name might be '/dev/ttyS0', '/dev/ttyAMA0', or '/dev/ttyUSB0' for a USB-to-serial adapter.
        # 9600 is the baud rate.
        ser = serial.Serial('/dev/ttyS0', 9600, timeout=1)
        ser.flush() # Clear the input/output buffer
    
        while True:
            # Send a command to the Arduino. Note the 'b' for bytes and '\n' as an end-of-line marker.
            command = b"MOVE_FORWARD\n"
            ser.write(command)
            print(f"Sent: {command.decode().strip()}") # .decode() converts bytes back to a string
    
            # Wait for a response from the Arduino
            if ser.in_waiting > 0:
                response = ser.readline().decode('utf-8').rstrip()
                print(f"Received: {response}")
    
            time.sleep(2)
    
    except serial.SerialException as e:
        print(f"Error opening serial port: {e}")
    except KeyboardInterrupt:
        print("Program terminated.")
    finally:
        if 'ser' in locals() and ser.is_open:
            ser.close()
            print("Serial port closed.")
    

    This setup creates a powerful architecture where Python handles high-level logic (e.g., navigation, image processing) and sends simple commands to a microcontroller that handles the low-level, real-time hardware control. This is a very common pattern in advanced robotics.

  • Practical Hands-on Example:
    If you have an Arduino, program it to listen for serial commands.

    • Arduino Code (C++): When it receives the string "BLINK", it should blink its onboard LED three times and send back the string "ACK_BLINK" (Acknowledge).
    • Python Code: Write a Python script using pyserial that sends the "BLINK" command. After sending, it should wait and read the response from the Arduino and print it to the console. If you don't have an Arduino, you can use two USB-to-serial adapters connected to your PC to simulate this communication between two different terminal windows.

Part 4: Advanced Robotics Concepts with Python (Weeks 12-14)

Lesson 12: Introduction to Computer Vision with OpenCV

  • Learning Objectives:

    1. Understand the basics of how computers "see" images.
    2. Use the OpenCV library to capture images and video from a camera.
    3. Perform simple image processing tasks like color detection and finding shapes.
  • Key Vocabulary:

    • Computer Vision: An interdisciplinary scientific field that deals with how computers can be made to gain high-level understanding from digital images or videos.
    • OpenCV (Open Source Computer Vision Library): A hugely popular library of programming functions mainly aimed at real-time computer vision.
    • Frame: A single image in a video stream.
    • HSV (Hue, Saturation, Value): A color model that is often more intuitive for color detection than the standard RGB model. Hue represents the color type, Saturation the intensity, and Value the brightness.
    • Masking: The process of creating a binary image (black and white) where white pixels represent a region of interest (e.g., all the blue pixels in an image).
  • Lesson Content:
    Let's give our robot the gift of sight! Computer Vision is a vast field, but we can start with the basics using the OpenCV library. First, you'll need to install it: pip install opencv-python.

    An image, to a computer, is just a grid of numbers (pixels). In a color image, each pixel has three values: Red, Green, and Blue (RGB). Our goal is to write code that can analyze these numbers to find patterns.

    Let's start by just opening the camera and displaying the video feed.

    import cv2
    
    # 0 is usually the default camera. If you have multiple cameras, you might use 1, 2, etc.
    cap = cv2.VideoCapture(0)
    
    if not cap.isOpened():
        print("Error: Cannot open camera")
        exit()
    
    while True:
        # Capture frame-by-frame
        ret, frame = cap.read() # ret is True if a frame was read successfully
    
        if not ret:
            print("Can't receive frame. Exiting...")
            break
    
        # Display the resulting frame
        cv2.imshow('Live Video Feed', frame)
    
        # Wait for the 'q' key to be pressed to exit
        if cv2.waitKey(1) == ord('q'):
            break
    
    # When everything done, release the capture and destroy windows
    cap.release()
    cv2.destroyAllWindows()
    

    This simple script is the foundation for all computer vision tasks. Now, let's do something more useful: find a specific color. Let's say we want our robot to find a blue ball. We'll convert the image to the HSV color space, which makes it easier to define a color range.

    We define a lower and upper range for blue, create a "mask" that keeps only the blue pixels, and then we can find the contours (outlines) of the blue objects.

  • Practical Hands-on Example:
    Create a "ball tracker" script.

    1. Using the code above as a starting point, write a script that identifies a specific color object (e.g., a yellow tennis ball or a red cup).
    2. Define the lower and upper HSV values for your target color. (There are many online tools to help you find these values).
    3. Create a mask using cv2.inRange().
    4. Find the contours in the mask using cv2.findContours().
    5. Find the largest contour, calculate its center point ((x, y) coordinates), and draw a circle on the original frame at that point using cv2.circle().
    6. (Bonus Challenge): Based on the x coordinate of the object's center, print "Turn Left", "Center", or "Turn Right".

Lesson 13: Introduction to SLAM and Navigation

  • Learning Objectives:

    1. Understand the conceptual problem of SLAM (Simultaneous Localization and Mapping).
    2. Explore the role of different sensor data (odometry, lidar) in navigation.
    3. Use a high-level Python library to run a simple navigation simulation.
  • Key Vocabulary:

    • SLAM (Simultaneous Localization and Mapping): The computational problem of constructing or updating a map of an unknown environment while simultaneously keeping track of an agent's location within it. It's the "how do I build a map and know where I am on it at the same time?" problem.
    • Localization: The problem of determining the robot's position and orientation in a given map.
    • Mapping: The problem of building a map of the environment.
    • Odometry: The use of data from motion sensors to estimate change in position over time. For a wheeled robot, this is often calculated by counting wheel rotations.
    • LIDAR (Light Detection and Ranging): A sensor that measures distance to a target by illuminating the target with laser light and measuring the reflected light. It provides a 360-degree scan of the environment.
  • Lesson Content:
    How does a robot vacuum cleaner know where it's been and where it needs to go next? The answer is SLAM. This is one of the most fundamental and challenging problems in mobile robotics.

    Imagine you wake up in a dark room you've never been in before. You have a flashlight and a piece of paper. You would shine the light, draw what you see (mapping), and then take a step. As you take a step, you try to guess where you are now relative to your drawing (localization). But your steps aren't perfect (this is like odometry error), and your drawing isn't perfect. SLAM is the process of doing both at once, using new sensor information to correct both your position estimate and your map.

    Sensors are key:

    • Wheel Odometry: Good for short-term position estimates, but drifts over time (like trying to walk a straight line with your eyes closed).
    • IMU (Inertial Measurement Unit): Measures acceleration and rotation. Also drifts over time.
    • LIDAR/Camera: Provides information about the environment ("landmarks"). This is used to correct the drift from odometry. "Oh, I see that same doorway again, I must be back where I was before."

    Implementing SLAM from scratch is incredibly complex and beyond the scope of this course. However, the robotics community has built amazing tools like ROS (Robot Operating System) that have pre-built SLAM packages. For our purposes, we can explore the concepts using a simulator. Many Python-based robotics simulators (like CoppeliaSim with its Python API, or web-based ones) allow you to experiment with these concepts.

    The key takeaway is understanding the process:

    1. Move: Command the robot to move based on a goal.
    2. Sense: Gather data from odometry and a range sensor (like LIDAR).
    3. Update: Feed this data into a SLAM algorithm. The algorithm updates its belief about the robot's position and improves the map.
    4. Plan: Based on the new map and position, plan the next move.
    5. Repeat.
  • Practical Hands-on Example:
    This week is more conceptual. Your task is to research and explore.

    1. Install a simple 2D robotics simulator with a Python API. A good candidate might be pyglet-robot-simulator or exploring the documentation for Webots/CoppeliaSim's Python remote API.
    2. Run one of the basic example simulations, like an obstacle avoidance robot in a pre-built world.
    3. Focus on the Python code that controls the robot. Identify the parts of the code responsible for:
      • Reading sensor data (e.g., laser scanner readings).
      • Setting motor speeds.
    4. Modify the code slightly. For example, change the robot's maximum speed or the distance at which it starts turning to avoid an obstacle. The goal is to get comfortable with the structure of a high-level robotics control script.

Lesson 14: Asynchronous Programming and Concurrency for Responsive Robots

  • Learning Objectives:

    1. Understand why simple, sequential programs are not ideal for complex robots.
    2. Learn the basics of using Python's threading module to run multiple tasks at once.
    3. Design a simple multi-threaded program for a robot.
  • Key Vocabulary:

    • Concurrency: The ability of different parts or units of a program, algorithm, or problem to be executed out-of-order or in partial order, without affecting the final outcome.
    • Sequential Execution: Code that runs one line at a time, in order. The program is blocked until the current task is finished.
    • Thread: A separate flow of execution. A program can have multiple threads running concurrently.
    • threading module: Python's standard library module for creating and managing threads.
    • Asynchronous Programming: A means of parallel programming in which a unit of work runs separately from the main application thread and notifies the calling thread of its completion, failure or progress.
  • Lesson Content:
    Imagine our obstacle-avoiding robot. In a simple, sequential program, it might look like this:

    1. Measure distance.
    2. Decide to move forward.
    3. Move forward for 2 seconds.
    4. Stop.
    5. Go back to step 1.

    What's the problem? While the robot is in the middle of time.sleep(2) in step 3, it's completely blind! A new obstacle could appear, and it wouldn't know until the 2 seconds are up. A responsive robot needs to be able to check its sensors while it's moving.

    This is where concurrency comes in. We can use Python's threading module to create multiple "threads" of execution that run seemingly at the same time. We can have one thread dedicated to reading sensors and updating a global "obstacle detected" variable, while the main thread is responsible for motor control.

    import threading
    import time
    
    # This is a shared variable. We need to be careful when multiple threads access it.
    obstacle_detected = False
    
    # This will be the target for our sensor thread
    def sensor_monitor():
        global obstacle_detected
        while True:
            # In a real robot, this would be code to read the ultrasonic sensor
            print("Sensor thread: Checking for obstacles...")
            # Simulate finding an obstacle sometimes
            import random
            if random.random() < 0.3:
                print("Sensor thread: OBSTACLE DETECTED!")
                obstacle_detected = True
            else:
                obstacle_detected = False
            time.sleep(0.5)
    
    # --- Main Program Logic ---
    print("Starting sensor thread...")
    # Create a new thread. 'daemon=True' means the thread will exit when the main program exits.
    sensor_thread = threading.Thread(target=sensor_monitor, daemon=True)
    sensor_thread.start() # Start the thread's execution
    
    print("Starting main motor control loop...")
    for i in range(10): # Run for 10 steps
        if not obstacle_detected:
            print("Main thread: Path clear, moving forward.")
        else:
            print("Main thread: Obstacle detected, stopping!")
        time.sleep(1)
    
    print("Main thread: Mission complete.")
    

    In this example, the sensor_monitor function runs continuously in the background. The main loop can react instantly to the obstacle_detected flag being changed by the sensor thread. This makes our robot much smarter and more responsive. Asynchronous programming is a key concept for building any non-trivial robot.

  • Practical Hands-on Example:
    Enhance your "parking assistant" script from Week 9 using threading.

    1. Create one thread whose only job is to continuously measure the distance from the ultrasonic sensor and update a global current_distance variable.
    2. Create a second thread whose only job is to look at the current_distance variable and control the blinking of the LED accordingly (off, slow blink, or fast blink).
    3. Your main thread will just start these two threads and then can print status messages to the console.
    4. Notice how the LED's blinking pattern can now change instantly as you move your hand in front of the sensor, because the two tasks are running concurrently.

Final Project (Weeks 15-16): Build a Smart Obstacle-Avoiding Rover

Project Description

This is it! Time to combine everything you've learned. You will build a complete, autonomous, two-wheeled rover that can navigate a space without bumping into things. The robot will move forward continuously until its ultrasonic sensor detects an object in its path. When an object is detected, it will stop, scan its surroundings by panning the sensor with a servo, choose the direction with the most free space, turn, and then continue on its new path.

Required Components:

  • Raspberry Pi
  • Robot chassis with two DC motors and wheels
  • L298N motor driver
  • HC-SR04 ultrasonic distance sensor
  • A small servo motor
  • A custom-made or 3D-printed bracket to mount the ultrasonic sensor onto the servo
  • Portable power source (USB power bank for Pi, separate battery pack for motors)
  • Breadboard and jumper wires

Step-by-Step Instructions

Step 1: Physical Assembly

  1. Build the Chassis: Assemble your robot chassis, attaching the DC motors and wheels.
  2. Mount Electronics: Find a secure place on the chassis to mount the Raspberry Pi, L298N motor driver, and breadboard.
  3. Power Distribution: Connect your motor battery pack to the L298N's power input. Connect the L298N's 5V output to the power rail on your breadboard. This will provide a convenient 5V source for your sensors. Power the Raspberry Pi separately with a good quality USB power bank. Crucially, ensure the ground (GND) of the motor battery pack circuit is connected to a GND pin on the Raspberry Pi. This creates a common ground, which is essential.
  4. Mount the Scanner: Attach the servo motor to the front of your chassis. Mount the HC-SR04 sensor onto the servo motor using your bracket. Your robot should now have a "head" that can turn.

Step 2: Wiring

  1. Motors: Connect the two DC motors to the Motor A and Motor B outputs on the L298N.
  2. Motor Driver Control: Connect the L298N's control pins (e.g., IN1, IN2, ENA for Motor A and IN3, IN4, ENB for Motor B) to six GPIO pins on the Raspberry Pi.
  3. Servo: Connect the servo's signal wire to a GPIO pin, its power wire to 5V, and its ground wire to GND.
  4. Ultrasonic Sensor: Connect the sensor's VCC to 5V, GND to GND, Trig pin to a GPIO pin, and Echo pin to another GPIO pin.

Step 3: Software – Creating the Classes

The best way to organize this project is with OOP. Create a new Python file rover.py.

  1. Motor Class: Create a class to control a single DC motor. It should have methods like forward(speed), backward(speed), and stop(). The speed parameter should control the PWM duty cycle on the motor's ENA/ENB pin.
  2. DriveTrain Class: Create a class that manages the robot's movement. It will contain two Motor objects (left and right). It should have high-level methods like go_forward(speed), go_backward(speed), turn_left(speed), and stop().
  3. DistanceScanner Class: Create a class to manage your servo/sensor combination.
    • The __init__ should set up the servo and ultrasonic sensor GPIO pins.
    • It should have a method like measure_distance() that reads from the sensor.
    • It should have a method called scan_surroundings() which does the following:
      • Moves the servo to three positions (e.g., 45 degrees for left, 90 for center, 135 for right).
      • At each position, it takes a distance measurement.
      • It should return the three measurements in a dictionary, e.g., {"left": 55.2, "center": 20.1, "right": 80.5}.

Step 4: The Main Logic

This is the "brain" of your robot. It will be the main while loop in your script.

  1. Initialization: Create objects for your DriveTrain and DistanceScanner.
  2. The Loop: Start an infinite while True: loop wrapped in a try...finally block to ensure GPIO.cleanup() is called.
  3. Move and Check:
    • Inside the loop, tell the DriveTrain to go_forward() at a moderate speed.
    • Immediately after, get a distance reading from the DistanceScanner in the forward-facing position (90 degrees).
    • Decision Time: Use an if statement. If the forward distance is less than a threshold (e.g., 25 cm):
      a. Call DriveTrain.stop().
      b. Call DistanceScanner.scan_surroundings() to get the left, center, and right distances.
      c. Print the scan results for debugging.
      d. Compare the left and right distances.
      e. If the left distance is greater than the right, call DriveTrain.turn_left() for a short duration (e.g., 0.75 seconds).
      f. Else, call DriveTrain.turn_right() for a short duration.
  4. Small Delay: Add a very small time.sleep(0.05) at the end of the loop to prevent the CPU from running at 100%.

Step 5: Test and Refine

Your first run will probably not be perfect. This is the fun part!

  • Does the robot turn too much or too little? Adjust the duration of the turn.
  • Is it too sensitive to obstacles? Increase the distance threshold.
  • Is it too slow? Increase the motor speed.
  • Place some books or boxes on the floor and watch your creation navigate its world autonomously.

Congratulations! You have successfully designed, built, and programmed a smart robot from the ground up using Python. You are officially a roboticist!

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *