Passing

Aim at a team mate's tag, judge the power from its distance.

7.6Hands and feetRobot club20 min

Do this lesson in the simulator

A pass is a kick with an aim and a range. A kick always travels about 45 cm, so a pass means getting to about that distance from your team mate, turning until they are dead ahead, and kicking. Their tag gives you both numbers: the bearing and the distance.

Find the receiver

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

def bearing_of(cx):
    return (cx - 160) * 120 / 320

# camera: the tag detector
set_cv("apriltag")
for tag in apriltags():
    print(f"robot {tag[0]}: {tag[3]} cm away, bearing {round(bearing_of(tag[1]), 1)}")

Run this in the simulator

Robot 101 is up and to the right, with a blue LED. Not straight ahead, so a kick now would miss.

Aim

Turn until the tag is centred, with the settle-and-check from lesson 4.2, holding the ball all the while:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

def bearing_of(cx):
    return (cx - 160) * 120 / 320

# close the jaws (it waits while they move)
gripper("close")
# camera: the tag detector
set_cv("apriltag")
# do this 100 times (tick counts from 0)
for tick in range(100):
    tags = [t for t in apriltags() if t[0] == 101]
    if not tags:
        # spin clockwise on the spot at 30
        turn_right(30)
    else:
        error = bearing_of(tags[0][1])
        if abs(error) < 1.5:
            # all motors off
            stop()
            # pause 0.3 s (the robot keeps doing what it was told)
            wait(0.3)
            if abs(bearing_of(apriltags()[0][1])) < 1.5:
                # leave the loop
                break
        else:
            # forward, sideways, rotation: -100 to 100 each, until the next command
            drive(0, 0, max(-30, min(30, error * 3)))
    # pause 0.05 s (the robot keeps doing what it was told)
    wait(0.05)
# all motors off
stop()
print("aimed at heading", round(heading()), "holding:", holding())

Run this in the simulator

Range

The tag gives the distance. A kick goes about 45 cm, and the ball starts about 8 cm in front of your centre, so the ball stops about 53 cm from you: that is where the receiver has to be. Farther and the pass drops short, nearer and it rolls past. So carry the ball to the right distance first, then aim, then kick:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

def bearing_of(cx):
    return (cx - 160) * 120 / 320

def aim_at(tag_id):
    # turn until the tag is centred, with the settle-and-check from lesson 4.2
    # do this 100 times (tick counts from 0)
    for tick in range(100):
        tags = [t for t in apriltags() if t[0] == tag_id]
        if not tags:
            # spin clockwise on the spot at 30
            turn_right(30)
        else:
            error = bearing_of(tags[0][1])
            if abs(error) < 1.5:
                # all motors off
                stop()
                # pause 0.3 s (the robot keeps doing what it was told)
                wait(0.3)
                if abs(bearing_of(apriltags()[0][1])) < 1.5:
                    return
            else:
                # forward, sideways, rotation: -100 to 100 each, until the next command
                drive(0, 0, max(-30, min(30, error * 3)))
        # pause 0.05 s (the robot keeps doing what it was told)
        wait(0.05)
    # all motors off
    stop()

# close the jaws (it waits while they move)
gripper("close")
# camera: the tag detector
set_cv("apriltag")
aim_at(101)
dist = [t for t in apriltags() if t[0] == 101][0][3]
print(f"receiver {dist} cm away")
if dist > 56:
    # too far for a kick: carry the ball closer
    forward(40, distance=dist - 53)
elif dist < 50:
    # too close: back off
    backward(40, distance=53 - dist)
# moving changes the bearing a little: aim again
aim_at(101)
# kick: one turn of the kicker winds the spring and lets it go
kick()
# pause 4 s (the robot keeps doing what it was told)
wait(4)

Run this in the simulator

Receiving

The other half of a pass is the receiver: face the passer, wait, and close the jaws when the ball arrives in front of you. distance() dropping to a few centimetres is the moment. In the netball game the receiver is another program, and it has to be ready before the kick.

Task: pass to your partner

Grip the ball, get to kicking range of robot 101, aim, and kick so the ball stops within the square around it.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# close the jaws (it waits while they move)
gripper("close")
# kick: one turn of the kicker winds the spring and lets it go
kick()
# pause 5 s (the robot keeps doing what it was told)
wait(5)

Challenges

  1. Pass to a partner who is moving: aim a little ahead of them.
  2. Make the pass bounce off the right wall on its way (aim at the wall, and think about the range).
  3. Write pass_to(tag_id) that does the whole thing, and time it.