How to Work with Python Databases & Other Advanced Features

In this tutorial, we are going to learn how to use Python databases and other advanced features.

Prerequisites

Connecting to a Database

Managing database connections is important for logging sensor data, storing robot configurations, or even tracking operational data in real-time robotics applications.

Create a new file called database_connection.py inside the following folder: ~/Documents/python_tutorial.

We’ll use sqlite3, which is a built-in Python library that allows you to interact with SQLite databases. This makes it a good choice for demonstration purposes and smaller projects.

import sqlite3

def create_connection(db_file):
    """ Create a database connection to the SQLite database specified by db_file """
    conn = None
    try:
        conn = sqlite3.connect(db_file)
        print("SQLite database version:", sqlite3.sqlite_version)
    except sqlite3.Error as e:
        print(e)
    finally:
        if conn:
            conn.close()

if __name__ == "__main__":
    create_connection("example.db")

This script attempts to connect to an SQLite database specified by the filename. If example.db doesn’t exist, SQLite will create it automatically when we try to connect. The connection is closed immediately after being opened to ensure there are no loose ends.

Let’s run this script to test our database connection.

1-database-connections

You should see the SQLite database version printed, indicating that the connection was successfully established. If there’s an error, it will be printed instead.

Working with Recursive Functions

Let’s dive into recursive functions—a technique that can help you solve problems that involve nested structures or repetitive tasks.

We’ll demonstrate recursion with a robotics-related example: navigating a robot hierarchy. 

Let’s say we have a robot structure where each robot can have multiple sub-robots. Our task is to calculate the total number of all robots and sub-robots within this hierarchy.
Create a file named recursive_robotics.py inside the following folder: ~/Documents/python_tutorial.

class Robot:
    def __init__(self, name):
        self.name = name
        self.sub_robots = []

    def add_sub_robot(self, sub_robot):
        self.sub_robots.append(sub_robot)

def count_robots(robot):
    """ Return the total count of robots in the hierarchy using recursion """
    total = 1  # Start with the current robot
    for sub_robot in robot.sub_robots:
        total += count_robots(sub_robot)  # Recursive call for each sub-robot
    return total

Here, we define a Robot class with a method to add sub-robots. The count_robots function starts counting with the current robot, then recursively counts each sub-robot in the sub_robots list.

Let’s create a robot hierarchy to test our recursive function:

root_robot = Robot("Root")
child_robot1 = Robot("Child1")
child_robot2 = Robot("Child2")
sub_child_robot1 = Robot("SubChild1")

root_robot.add_sub_robot(child_robot1)
root_robot.add_sub_robot(child_robot2)
child_robot1.add_sub_robot(sub_child_robot1)

print("Total number of robots:", count_robots(root_robot))

Run the script.

2-recursive-robotics

You will see the total count of robots in the hierarchy, which includes the root robot, its children, and sub-children.

Working with Modules

Let’s explore how to work with modules in Python—a fundamental concept that allows you to organize your code better, making it more readable, maintainable, and reusable. For robotics engineers, using modules can help structure control systems, sensor integration, and interaction logic into separate components.

Create a new file called robot_modules.py inside the following folder: ~/Documents/python_tutorial.

Save it.

Now let’s create a module that we’ll use as a utility for our robotic operations. This module will include functions to calculate the area of different shapes which could, for example, be useful in path planning or space management in robotics applications.

Create another file in the same directory named geometry.py and type in the following code:

def rectangle_area(length, width):
    return length * width

def circle_area(radius):
    from math import pi
    return pi * radius ** 2

Now, in your robot_modules.py file, let’s write this code:

import geometry

def main():
    rect_area = geometry.rectangle_area(5, 3)
    circ_area = geometry.circle_area(7)
    print(f"Area of the rectangle: {rect_area}")
    print(f"Area of the circle: {circ_area}")

if __name__ == "__main__":
    main()

Here, we have imported the geometry module, which contains our area calculation functions. We can now use these functions in our main program to calculate the area of a rectangle and a circle.

Let’s run our script to see modules in action. 

3-robot-modules

You will see the areas of the rectangle and circle printed out, showcasing how our main program can use functions defined in another module.

Creating a GUI

Let’s learn how to create a graphical user interface, or GUI, using Python. This skill is helpful when you need to create an interface for interacting with robots, such as controlling movements or monitoring sensor data.

Create a new file called robot_gui.py inside the following folder: ~/Documents/python_tutorial.

We’ll use tkinter, the standard GUI library for Python, to create a basic interface. It’s included with Python, so you don’t need to install anything extra.

import tkinter as tk
from tkinter import simpledialog

def main():
    root = tk.Tk()
    root.title("Robot Control Panel")

    def handle_command():
        response = simpledialog.askstring("Input", "Enter a command for the robot:")
        print(f"Command received: {response}")

    command_button = tk.Button(root, text="Send Command", command=handle_command)
    command_button.pack(pady=20)

    exit_button = tk.Button(root, text="Exit", command=root.destroy)
    exit_button.pack(pady=20)

    root.mainloop()

if __name__ == "__main__":
    main()

In this script, we create a basic window with a button. When clicked, this button prompts the user to enter a command, which could hypothetically be sent to a robot. The mainloop() method keeps the window open and waits for user interaction.

Now, run the script.

4-tkinter-gui
5-enter-a-command

A window titled “Robot Control Panel” should appear with a button labeled “Send Command”. Clicking the button will open a dialog box asking for a command input.

Click Exit when you are finished.

And there you have it—a basic GUI for controlling a robot using Python and tkinter.

This concludes the Python for Robotics course. Thank you for following along.

Keep building!

How to Use Python Multithreading and Regular Expressions

In this tutorial, we are going to learn how to use threads in Python  to perform multiple tasks simultaneously.

Prerequisites

Understanding Threads

Create a file called threading_example.py inside the following folder: ~/Documents/python_tutorial.

Now write the following code:

import threading
import time

def robot_task(name, duration):
    print(f"{name} starting task.")
    time.sleep(duration)
    print(f"{name} has completed its task.")

# Creating threads
thread1 = threading.Thread(target=robot_task, args=("Robot 1", 2))
thread2 = threading.Thread(target=robot_task, args=("Robot 2", 3))

Here, we define a simple function robot_task that simulates a task by sleeping for a specified duration. Then, we create two threads, each assigned to execute this function.

Let’s complete the threading example by starting the threads and waiting for them to finish:

thread1.start()
thread2.start()

# Wait for both threads to complete
thread1.join()
thread2.join()

print("Both robots have completed their tasks.")

Now, run the script.

1-threading-example

You should see output indicating that both robots are starting and completing their tasks, potentially overlapping in time, showing how threads allow simultaneous task execution.

Working with Regular Expressions

Let’s check out an indispensable tool for processing text data effectively—regular expressions, often abbreviated as regex.

Understanding how to use regular expressions will help you handle complex string manipulation tasks, which can be particularly useful in robotics for parsing logs, sensor data, or commands.

Create a new file named regex_examples.py inside the following folder: ~/Documents/python_tutorial.

First, we need to import the re module, which is Python’s library for handling regular expressions:

import re

Let’s define a function to demonstrate a basic regex operation—finding dates within a string. Imagine we’re processing a log file and we want to extract date entries formatted as dd-mm-yyyy.

def find_dates(text):
    pattern = r'\b\d{2}-\d{2}-\d{4}\b'
    dates = re.findall(pattern, text)
    return dates

This function uses the re.findall() method, which searches through the text and returns all non-overlapping matches of the pattern described. Here, our pattern \b\d{2}-\d{2}-\d{4}\b looks for sequences that match the date format.

Let’s add a test case to use our function:

log_entry = "Error reported on 23-10-2023 at node 3. Previous error was on 01-10-2023."
found_dates = find_dates(log_entry)
print("Dates found:", found_dates)

Now, run the script.

2-regex-examples

You should see the output displaying the dates extracted from the string. This illustrates how regular expressions can simplify the task of searching and extracting data from text.

And that’s it for regular expressions. 

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

Keep building!

How to Use Advanced Object-Oriented Python

In this tutorial, we are going to learn advanced concepts for object-oriented programming using Python.

Prerequisites

Writing Getters and Setters

Let’s learn about getters and setters – they’re like security guards for your robot’s information! Think of them as special functions that help you safely check and change your robot’s settings. 

Just like you wouldn’t want anyone to accidentally set your robot’s speed to a dangerous level, getters and setters help protect your robot’s information and make sure it’s changed in the right way.

First, create a file called robot_settings.py inside the following folder: ~/Documents/python_tutorial.

Define a class named Robot that will help us manage the speed and battery level, which are common attributes in robotics:

class Robot:
    def __init__(self, speed=0, battery=100):
        self._speed = speed
        self._battery = battery

    def get_speed(self):
        return self._speed

    def set_speed(self, value):
        if value < 0:
            raise ValueError("Speed cannot be negative")
        self._speed = value

    def get_battery(self):
        return self._battery

    def set_battery(self, value):
        if not (0 <= value <= 100):
            raise ValueError("Battery must be between 0 and 100")
        self._battery = value

This code snippet introduces get and set methods for speed and battery level. The setters include validations to ensure the values are within acceptable ranges, which is essential for maintaining the safety and functionality of your robot.

Next, run a simple test to see these getters and setters in action. 

Add the following test code at the end of your script:

robot = Robot()
print("Initial Speed:", robot.get_speed())
robot.set_speed(5)
print("Updated Speed:", robot.get_speed())

try:
    robot.set_battery(150)
except ValueError as e:
    print(e)

Now, run the code:

1-robot-settings

You should see the outputs corresponding to the robot’s speed updates and any error messages related to battery level adjustments.

Using Inheritance

Let’s talk about inheritance in Python, a topic we briefly covered in the previous tutorial.

Inheritance is like creating a family tree of robots. Imagine you design a basic robot with common features. Then, just like how children inherit traits from their parents, you can create new types of robots that automatically get all the abilities of the basic robot, plus their own special features. This saves you from having to write the same code over and over again.

Create a new file called robot_inheritance.py inside the following folder: ~/Documents/python_tutorial.

Begin by defining a base class called Robot that will contain common attributes and methods that any robot might need:

class Robot:
    def __init__(self, name):
        self.name = name

    def greet(self):
        print(f"Hello, I am {self.name}.")

Now, let’s use inheritance to create a specialized type of robot. We’ll define a class CleaningRobot that inherits from Robot:

class CleaningRobot(Robot):
    def clean(self):
        print("Cleaning in progress...")

Notice how CleaningRobot doesn’t redefine the __init__ method or the greet method but inherits them from the Robot class. It does, however, add a new method, clean, which is specific to cleaning robots.

Now let’s add this test code at the end of your script to create an instance of CleaningRobot and use its methods:

my_robot = CleaningRobot("RoboCleaner")
my_robot.greet()
my_robot.clean()

Now, run the script.

2-robot-inheritance

You should see the greeting from the robot followed by the cleaning message. This demonstrates how the CleaningRobot uses functionality from the Robot base class while adding its own unique behavior.

Practicing Polymorphism

Let’s take a look at another key concept in object-oriented programming: polymorphism. 

Polymorphism literally means “many forms”.

Imagine you have a television remote control with a “power” button that works on different TVs. Just like how different television classes (Samsung, LG, or Sony) all understand the same power command, different robot classes can share common commands too. This is polymorphism in action – we can treat different kinds of objects (like our different robot types) as if they were the same basic type (like a general “robot” class). 

For example, all our robots might understand the command “move forward,” but each robot class implements it differently: a walking robot takes steps, while a wheeled robot rolls forward. Same command name, different behaviors!

Create a new file named polymorphism_example.py inside the following folder: ~/Documents/python_tutorial.

Start by defining a base class called Robot with the following method:

class Robot:
    def __init__(self, name):
        self.name = name

    def perform_task(self):
        print(f"{self.name} performs a generic task.")

Now, let’s define two subclasses that inherit from Robot but perform tasks differently, demonstrating polymorphism:

class CleaningRobot(Robot):
    def perform_task(self):
        print(f"{self.name} is cleaning the area.")

class PaintingRobot(Robot):
    def perform_task(self):
        print(f"{self.name} is painting the wall.")

Each subclass has its own implementation of the perform_task method, tailored to what the specific robot is supposed to do.

Now add this test code at the end of your script to create instances of each robot and call their task method:

robots = [CleaningRobot("Cleany"), PaintingRobot("Painty")]
for robot in robots:
    robot.perform_task()

Now, run the script.

3-polymorphism

You should see each robot performing its specific task, demonstrating how polymorphism allows us to use a common method in different contexts.

Working with Magic Methods

Now let’s explore a concept of Python programming that can significantly enhance your coding, especially when working with classes in robotics: magic methods, also known as dunder methods. 

Magic methods are special methods that start and end with double underscores. They allow us to implement functionality that mimics the behavior of built-in types and elegantly interact with different Python operations.

Create a new file named magic_methods.py inside the following folder: ~/Documents/python_tutorial.

We’ll begin by defining a class called Robot that utilizes some common magic methods:

class Robot:
    def __init__(self, name, battery_life):
        self.name = name
        self.battery_life = battery_life

    def __str__(self):
        return f"{self.name} (Battery life: {self.battery_life} hours)"

    def __len__(self):
        return self.battery_life

    def __add__(self, other):
        if isinstance(other, Robot):
            return Robot(f"{self.name}&{other.name}", self.battery_life + other.battery_life)
        raise ValueError("Can only add another Robot")

In this snippet, we define three magic methods:

__str__: customizes the string representation of our objects, making it more informative.

__len__: allows us to use Python’s len() function to get the battery life of the robot.

__add__: enables us to “add” two robots together to create a new robot with combined names and battery life.

Now add the following test code at the end of your script:

robot1 = Robot("Robo-One", 5)
robot2 = Robot("Robo-Two", 3)
print(robot1)
print("Battery life of", robot1.name, "is", len(robot1), "hours")
combined_robot = robot1 + robot2
print(combined_robot)

Run your code.

4-magic-methods

You should see the string representations of the robots, their individual battery lives, and the details of the combined robot. 

That concludes our overview of magic methods. Thanks, and I’ll see you in the next tutorial.

Keep building!