Module 5/5 · Weeks 13–15 · 30 h

Block programming and Git for teamwork

DRT 114 Computer Programming

About 90 minDraft, awaiting reviewLast updated 26 September 2026

Lesson

By the end of this module you will be able to

  1. Translate a Hula drone block program into Python with the same structure
  2. Write a drone simulation class and use it to compute polygon and star routes
  3. Explain concurrency with threads, signalling, and protecting shared variables
  4. Use Git to record history, branch and merge following GitHub flow
  5. Write commit messages following Conventional Commits and keep secrets out of repositories

Prerequisites: DRT 114 modules 1–2

Why this matters

Many students start programming drones with block programs, such as HighGreat’s Hula app, dragging blocks like “take off”, “fly forward” and “turn” together. Block programs make program structure very visible, but as work grows you need a language that can be tested, reused and shared by a team: Python with Git.

The good news is that the ideas are almost identical. One block is one line of code, a Repeat block is for, an if block is if. What you gain are testing tools, simulation, and a traceable history of changes.

From blocks to Python

Hula blockPythonNote
when ▶ clickedMain part of the programStart point
Take off / Landingdrone.take_off() / drone.land()Always take off first and land last
Fly to Front with 60 cmdrone.fly_forward(60)
Turn to Clockwise with 90 degreedrone.turn_clockwise(90)
Repeat 4 timesfor _ in range(4):
repeat until [condition]while not condition:
Set / change [variable]count = 0 / count += 1
broadcast / when I receivethreading.EventConcurrency

The class below models a drone on a flat plane. It does not command a real drone, but it checks a program’s logic before flight. Hula’s speed is a percentage command, not m/s, so the class does not model flight time.

import math


class SimDrone:
    """A flat-plane drone model for checking block programs before flight."""

    def __init__(self):
        self.x_cm = 0.0
        self.y_cm = 0.0
        self.heading_deg = 0.0
        self.flying = False
        self.distance_cm = 0.0
        self.turned_deg = 0.0

    def take_off(self):
        self.flying = True

    def land(self):
        self.flying = False

    def _require_flying(self):
        if not self.flying:
            raise RuntimeError("take off first")

    def fly_forward(self, cm):
        self._require_flying()
        self.x_cm += cm * math.sin(math.radians(self.heading_deg))
        self.y_cm += cm * math.cos(math.radians(self.heading_deg))
        self.distance_cm += cm

    def turn_clockwise(self, deg):
        self._require_flying()
        self.heading_deg = (self.heading_deg + deg) % 360
        self.turned_deg += deg

    def back_at_start(self):
        return math.isclose(self.x_cm, 0, abs_tol=1e-6) and math.isclose(self.y_cm, 0, abs_tol=1e-6)


drone = SimDrone()
try:
    drone.fly_forward(100)
except RuntimeError as err:
    print("error:", err)
error: take off first

The _require_flying() method enforces Hula’s “take off first” rule in code. Forget the Take off block and the simulation reports it immediately, instead of the problem surfacing in flight.

Polygons and stars

Example 1 A square and a five-pointed star (Hula examples 2 and 3)

Flying equal straight legs and turning the same way each time, the turn for a figure with vertices stepping vertices at a time is . A square is with 90° turns; a five-pointed star is with 144° turns.

def fly_polygon(n, k, side_cm):
    drone = SimDrone()
    drone.take_off()
    for _ in range(n):
        drone.fly_forward(side_cm)
        drone.turn_clockwise(360 * k / n)
    drone.land()
    return drone


for n, k, side in [(4, 1, 60), (5, 2, 50)]:
    d = fly_polygon(n, k, side)
    print(f"{{{n}/{k}}}: turn {360 * k / n:.0f} deg, flown {d.distance_cm:.0f} cm, "
          f"turned {d.turned_deg:.0f} deg, back at start: {d.back_at_start()}")
{4/1}: turn 90 deg, flown 240 cm, turned 360 deg, back at start: True
{5/2}: turn 144 deg, flown 250 cm, turned 720 deg, back at start: True

The star turns 720° in total, not 360°, because the path crosses itself.

Example 2 When a star closes sooner than expected

With , meant as a six-pointed star, the drone returns to the start after only legs, tracing a triangle and then repeating it.

def legs_until_back(n, k, side_cm=100):
    drone = SimDrone()
    drone.take_off()
    for leg in range(1, n + 1):
        drone.fly_forward(side_cm)
        drone.turn_clockwise(360 * k / n)
        if drone.back_at_start():
            return leg
    return None


for n, k in [(5, 2), (6, 2), (7, 3)]:
    print(f"{{{n}/{k}}}: back after {legs_until_back(n, k)} legs, n / gcd = {n // math.gcd(n, k)}")
{5/2}: back after 5 legs, n / gcd = 5
{6/2}: back after 3 legs, n / gcd = 3
{7/3}: back after 7 legs, n / gcd = 7

The simulation confirms the formula. That is the value of simulating before flight: conceptual mistakes show up without spending time or risking equipment.

Concurrency

Hula’s level-5 example uses two scripts running at once: one flies a survey, the other searches for QR targets, communicating through a broadcast block and a shared variable. In Python this becomes two threads: threading.Event replaces the broadcast, and threading.Lock stops both threads changing the shared variable at the same moment and corrupting it.

import threading

mission_started = threading.Event()
lock = threading.Lock()
targets_marked = 0
QR_FOUND_AT_SCAN = {2, 5, 6}


def search_thread():
    global targets_marked
    mission_started.wait()
    scan = 0
    while targets_marked < 3:
        scan += 1
        if scan in QR_FOUND_AT_SCAN:
            with lock:
                targets_marked += 1
        threading.Event().wait(0.002)


searcher = threading.Thread(target=search_thread)
searcher.start()
mission_started.set()
while targets_marked < 3:
    threading.Event().wait(0.002)
searcher.join()
print("targets marked:", targets_marked)
targets marked: 3

searcher.join() waits for the search thread to finish before landing, like Hula’s stop all scripts block, which prevents a script from being left running. Concurrent code is easy to get wrong; if you do not need it, write a single sequence first.

Git: recording history

Git records snapshots of code (commits) with explanatory messages, lets you go back, and lets many people work on the same code. The Pro Git book is free at git-scm.com.

The four areas of Git: working tree, staging area, local repository and remote on GitHub; git add moves changes from the working tree to staging, git commit to the local repository, git push to the remote, and git pull brings changes back to the working tree
Figure 1 The four areas of Git
git config --global init.defaultBranch main   # Git still names the default branch master
git init
git add mission_tools.py test_mission_tools.py
git commit -m "feat: add battery_status and distance_m"
git log --oneline

A .gitignore file tells Git which files not to track. Add it in the very first commit.

.venv/
__pycache__/
*.tlog
.env

Never commit secrets

Passwords, API keys and .env files must never be committed. Git history keeps every version; deleting later does not remove it from history or from forks others have already copied. GitHub advises that if a secret leaks, revoke or rotate it first, then clean the history. OWASP recommends keeping secrets in a secrets manager or environment variables, never embedded in code.

GitHub flow and commit messages

A blue main line with a pink branch named feature/battery-check splitting off, three commits on the branch, then a pull request and review, then a merge back into main
Figure 2 GitHub flow: branch, work, pull request, merge

GitHub flow is simple: branch from main → change and commit → open a pull request → a teammate reviews → merge and delete the branch.

git switch -c feature/battery-check
# edit the code and make the tests pass
git add mission_tools.py test_mission_tools.py
git commit -m "fix: treat 15% as LOW, not OK"
git push -u origin feature/battery-check

Conventional Commits 1.0.0 uses the form type(scope): description, such as feat: for a new capability, fix: for a bug fix, and docs:, test: or refactor: for other work. A good message says what changed, not “fixed stuff” or “update”.

Module lab

Lab: a team mini-project

Use the Hula block reference and the five-level examples in the drone knowledge hub.

  1. Choose one Hula example from levels 2–4, translate it to Python with SimDrone, and write tests confirming the route closes or turns fully as intended.
  2. Create a group repository on GitHub, add .gitignore in the first commit, and bring in your files from modules 2 to 4.
  3. Each member works on their own branch, opens a pull request, and reviews at least one teammate’s work.
  4. If a Hula drone is available, fly the original block program in a safe area under the instructor’s supervision and compare it with the simulation.

Common mistakes

Watch out

  • Forgetting Take off or Landing in a block program
  • Treating the app’s speed percentage as m/s without calibration
  • Letting two threads change one variable without a Lock
  • Committing the .venv folder or secrets
  • Working directly on main, so teammates’ work collides
  • Writing “update” as a commit message, which says nothing

Summary

  • Hula blocks translate directly to Python: Repeat is for, repeat until is while, broadcast is threading.Event
  • A drone simulation class checks logic before flight; a figure turns and closes after legs
  • Threads sharing a variable need a Lock, and must be waited for with join()
  • Git has four areas, and GitHub flow is branch → commit → pull request → review → merge
  • Write commit messages following Conventional Commits, and never commit secrets

Check your understanding

  1. Which Python statement matches the block Repeat 5 times?
  2. For a regular hexagon with 100 cm sides, how many degrees is each turn, and how far is the total flight?
  3. After how many legs does return to its start?
  4. Which Git command moves changes from the working tree to the staging area?
  5. You accidentally committed an API key to GitHub. What must you do first?
Answers
  1. for _ in range(5):
  2. per turn, and cm in total
  3. legs
  4. git add
  5. Revoke or rotate the key immediately, because deleting it from history later cannot guarantee nobody has copied it

Key formulas

Turn angle of polygons and stars {n/k}
Legs before returning to start

Key references

  1. Shenzhen HighGreat Innovation Technology Development Co. HULA all-in-1 drone and Hula app user manual. link
  2. Python Software Foundation. The Python tutorial (Python 3.14 documentation). link
  3. Chacon, S., & Straub, B. (2014). Pro Git (2nd ed.). Apress. link
  4. GitHub. GitHub flow. GitHub Docs. link
  5. Conventional Commits. Conventional Commits 1.0.0. link
  6. GitHub. Removing sensitive data from a repository. GitHub Docs. link
  7. OWASP Foundation. Secrets management cheat sheet. OWASP Cheat Sheet Series. link

Further reading

Study the assigned knowledge units in advance, review media and take the module quiz

In class / field

Lab or field practice from worksheets with a safety checklist

Learning evidence: Checked worksheets and quiz results

Module quiz

This is a formative self-check, not a graded exam

Knowledge domain: Programming and digital technology