Skip to content

add Birthday Candle Blower #65

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e9a5276
add README for Kiki the Dog (SPIKE Prime)
Mar 15, 2021
d73e11b
add Kiki program
AntoniLuongPham Mar 15, 2021
80ac4f8
fix Kiki README
Mar 15, 2021
8a18f81
Merge branch 'master' of https://github.com/pybricks/pybricks-projects
Mar 17, 2021
731d412
Merge branch 'master' of https://github.com/pybricks/pybricks-projects
Apr 28, 2021
41c6367
Merge branch 'master' of https://github.com/pybricks/pybricks-projects
May 14, 2021
35150f1
Merge branch 'master' of https://github.com/pybricks/pybricks-projects
Jun 3, 2021
c1f58af
Merge branch 'master' of https://github.com/pybricks/pybricks-projects
Jul 29, 2021
5f8ac13
add SPIKE Prime Other Models index.md
Jul 29, 2021
b605465
add SPIKE Prime Birthday Candle Blower index.md
Jul 29, 2021
24cabf8
Add Birthday Candle Blower program
Jul 30, 2021
d26f61b
refactor Birthday Candle Blower program
Jul 30, 2021
41e65fb
add Birthday Candle Blower photo
Jul 30, 2021
c381f5a
update Birthday Candle Blower index.md
Jul 30, 2021
74928db
update Birthday Candle Blower index.md
Jul 30, 2021
86f20fe
update Birthday Candle Blower index.md
Jul 30, 2021
3500e89
update Birthday Candle Blower index.md
Jul 30, 2021
7639a7c
update VSCode settings
Jul 30, 2021
42765f9
move Birthday-Candle-Blower to remix
Aug 6, 2021
f380d02
update VSCode settings
Aug 6, 2021
60801f9
update Birthday Candle Blower index.md
Aug 6, 2021
ac6aed6
update VSCode settings
Aug 6, 2021
539ecaa
refactor Birthday-Candle-Blower program
Aug 11, 2021
adfafdc
fix hub.display.image argument in Birthday Candle Blower
Aug 13, 2021
12617f7
add Prospector.YAML config file
Sep 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .prospector.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pylint:
disable:
- assignment-from-no-return
- too-many-arguments
32 changes: 31 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,43 @@
{
"editor.rulers": [70],

"files.exclude": {
"**/.git": true,
"**/.mypy_cache": true,
"**/*.pyc": {"when": "$(basename).py"},
"**/__pycache__": true,
"**/.ropeproject": true,
},

"python.analysis.diagnosticSeverityOverrides": {
"reportMissingImports": "none",
},

"python.linting.enabled": true,

"python.linting.pylintEnabled": true,
"python.linting.pylintArgs": [
"--disable", "assignment-from-no-return",
"--disable", "import-error",
"--disable", "missing-class-docstring",
"--disable", "missing-function-docstring",
"--disable", "missing-module-docstring",
"--disable", "no-name-in-module",
"--disable", "too-few-public-methods",
"--disable", "too-many-arguments",
],

"python.linting.flake8Enabled": true,

"python.linting.mypyEnabled": true,

"python.linting.pydocstyleEnabled": false,

"python.linting.pycodestyleEnabled": true,

"python.linting.prospectorEnabled": true,

"python.linting.pylamaEnabled": true,
"python.linting.banditEnabled": true

"python.linting.banditEnabled": true,
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 51 additions & 0 deletions remix/birthday-candle-blower/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
title: "Birthday Bot: Candle Blower"
maintainer:
user: "TheVinhLuong102"
name: "The Lương-Phạm Family"
image:
local: "birthday-candle-blower.jpg"
video:
youtube: "PAk9mxus1Nk"
description:
"A cute robot who wheels around, sings Happy Birthday and blow candles by its powerful fan! Member of the Lương-Phạm family's Birthday Bots squad, alongside Birthday Cake Cutter and Birthday Gift Presenter."
building_instructions:
local: TODO
code: "#program"
---


Control the Birthday Candle Blower by the Powered-Up Remote as follows:

- Driving: (refer to the `RemoteControlledDriveBase` code below)
- 2 Top/Plus buttons together: drive forward
- 2 Bottom/Minus buttons together: drive backward
- Top-Left/Left-Plus and Bottom-Right/Right-Minus together: turn left on the spot
- Top-Right/Right-Plus and Bottom-Left/Left-Minus together: turn right on the spot
- Top-Left/Left-Plus: turn left forward
- Top-Right/Right-Plus: turn right forward
- Bottom-Left/Left-Minus: turn left backward
- Bottom-Right/Right-Minus: turn right backward

- Singing Happy Birthday: green Center button

- Spinning the Fan:
- Clockwise (from robot's point of view): red Right button
- Counterclockwise: left Red button


## Technical Design Notes

For the fan to spin fast enough to blow candles, we need a very large gear attached to the fan motor and a very small gear attached to the fan's axis.

The fan blades' facing and spinning directions also matter. In the pictured design, the fan only generates strong forward wind when:
- the bottoms of the blade pieces face forward; AND
- the fan spins clockwise from the robot's point of view.


## Program

{% include copy-code.html %}
```python
{% include_relative main.py %}
```
134 changes: 134 additions & 0 deletions remix/birthday-candle-blower/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor, Remote
from pybricks.robotics import DriveBase
from pybricks.geometry import Axis
from pybricks.parameters import Button, Direction as Dir, Icon, Port


HAPPY_BIRTHDAY_SONG = [
'G3/8', 'G3/8', 'A3/4', 'G3/4', 'C4/4', 'B3/2',
'G3/8', 'G3/8', 'A3/4', 'G3/4', 'D4/4', 'C4/2',
'G3/8', 'G3/8', 'G4/4', 'E4/4',
'C4/8', 'C4/8', 'B3/4', 'A3/4',
'F4/8', 'F4/8', 'E4/4', 'C4/4', 'D4/4', 'C4/2'
]


class RemoteControlledDriveBase:
def __init__(self,
wheel_diameter: float, # milimeters
axle_track: float, # milimeters
left_motor_port: Port = Port.A,
left_motor_pos_dir: Dir = Dir.COUNTERCLOCKWISE,
right_motor_port: Port = Port.B,
right_motor_pos_dir: Dir = Dir.CLOCKWISE):
self.drive_base = \
DriveBase(left_motor=Motor(left_motor_port,
left_motor_pos_dir),
right_motor=Motor(right_motor_port,
right_motor_pos_dir),
wheel_diameter=wheel_diameter,
axle_track=axle_track)

self.remote = Remote()
print('Remote Connected!')

def drive_by_remote(self,
speed: float = 1000, # mm/s
turn_rate: float = 90 # rotational deg/s
):
remote_button_pressed = self.remote.buttons.pressed()

# forward
if remote_button_pressed == (Button.LEFT_PLUS,
Button.RIGHT_PLUS):
self.drive_base.drive(speed=speed, turn_rate=0)

# backward
elif remote_button_pressed == (Button.LEFT_MINUS,
Button.RIGHT_MINUS):
self.drive_base.drive(speed=-speed, turn_rate=0)

# turn left on the spot
elif remote_button_pressed == (Button.RIGHT_MINUS,
Button.LEFT_PLUS):
self.drive_base.drive(speed=0, turn_rate=-turn_rate)

# turn right on the spot
elif remote_button_pressed == (Button.LEFT_MINUS,
Button.RIGHT_PLUS):
self.drive_base.drive(speed=0, turn_rate=turn_rate)

# turn left forward
elif remote_button_pressed == (Button.LEFT_PLUS,):
self.drive_base.drive(speed=speed, turn_rate=-turn_rate)

# turn right forward
elif remote_button_pressed == (Button.RIGHT_PLUS,):
self.drive_base.drive(speed=speed, turn_rate=turn_rate)

# turn left backward
elif remote_button_pressed == (Button.LEFT_MINUS,):
self.drive_base.drive(speed=-speed, turn_rate=turn_rate)

# turn right backward
elif remote_button_pressed == (Button.RIGHT_MINUS,):
self.drive_base.drive(speed=-speed, turn_rate=-turn_rate)

# otherwise stop
else:
self.drive_base.stop()


class BirthdayCandleBlower(RemoteControlledDriveBase):
WHEEL_DIAMETER = 44 # milimeters
AXLE_TRACK = 100 # milimeters

def __init__(self,
fan_motor_port: Port = Port.A,
left_motor_port: Port = Port.D,
right_motor_port: Port = Port.C):
super().__init__(wheel_diameter=self.WHEEL_DIAMETER,
axle_track=self.AXLE_TRACK,
left_motor_port=left_motor_port,
left_motor_pos_dir=Dir.COUNTERCLOCKWISE,
right_motor_port=right_motor_port,
right_motor_pos_dir=Dir.CLOCKWISE)

self.hub = PrimeHub(top_side=Axis.X, front_side=Axis.Z)

self.fan_motor = Motor(fan_motor_port, Dir.CLOCKWISE)

def smile(self):
self.hub.display.image(Icon.HAPPY)

def sing_happy_birthday_by_remote_center_button(self):
if self.remote.buttons.pressed() == (Button.CENTER,):
self.hub.speaker.play_notes(
notes=HAPPY_BIRTHDAY_SONG,
tempo=120)

def spin_fan_by_remote_red_buttons(self):
remote_button_pressed = self.remote.buttons.pressed()

if remote_button_pressed == (Button.LEFT,):
self.fan_motor.run(speed=-1000)

elif remote_button_pressed == (Button.RIGHT,):
self.fan_motor.run(speed=1000)

else:
self.fan_motor.stop()


# initialize Birthday Candle Blower
candle_blower = BirthdayCandleBlower()

# make it smile
candle_blower.smile()

# remote-control it to drive around, sing and blow candles
while True:
candle_blower.drive_by_remote()
candle_blower.sing_happy_birthday_by_remote_center_button()
candle_blower.spin_fan_by_remote_red_buttons()
6 changes: 6 additions & 0 deletions remix/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: "Remix"
image:
local: "birthday-candle-blower/birthday-candle-blower.jpg"
layout: remix
---