diff --git a/README.md b/README.md index 12a9352c..0e149d09 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ Python 3 教程 ============ + +[Python 3 教程](https://www.liaoxuefeng.com/wiki/1016959663602400) diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 00000000..fac3311c --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +learn-python3.itranswarp.com \ No newline at end of file diff --git a/docs/pyscript_plugin.js b/docs/pyscript_plugin.js new file mode 100644 index 00000000..39e7bae7 --- /dev/null +++ b/docs/pyscript_plugin.js @@ -0,0 +1,31 @@ +export default class LearnPython3Plugin { + afterStartup(runtime) { + console.log('[plugin] pyscript startup.'); + window.__pyscript_ready__ = true; + } + + afterPyScriptExec(opt) { + let + tag = opt.pyScriptTag, + outputId = tag.getAttribute('output'), + $btn = $('button[outputId=' + outputId + ']'), + $i = $btn.find('i'); + $i.removeClass('uk-icon-spinner'); + $i.removeClass('uk-icon-spin'); + $btn.removeAttr('disabled'); + let err = $(tag).find('pre.py-error').html(); + if (err) { + let + $out = $('#' + outputId), + s = $out.html(); + s = s + err.replaceAll(' ', ' '); + $out.html(s); + $out.addClass('uk-alert-danger'); + } + } + + onUserError(err) { + console.log('Error >>>'); + console.error(err); + } +} diff --git a/samples/advance/do_iter.py b/samples/advance/do_iter.py index 99ba3702..0ded6af4 100755 --- a/samples/advance/do_iter.py +++ b/samples/advance/do_iter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from collections import Iterable, Iterator +from collections.abc import Iterable, Iterator def g(): yield 1 diff --git a/samples/basic/do_match.py b/samples/basic/do_match.py new file mode 100644 index 00000000..b14fe51f --- /dev/null +++ b/samples/basic/do_match.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# 简单匹配: +print('-- simple match --') + +score = 'A' + +match score: + case 'A': + print('score is A.') + case 'B': + print('score is B.') + case 'C': + print('score is C.') + case _: + print('score is ???.') + +# 复杂匹配: +print('-- complex match --') + +age = 15 + +match age: + case x if x < 10: + print('< 10 years old.') + case 10: + print('10 years old.') + case 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18: + print('11~18 years old.') + case 19: + print('19 years old.') + case _: + print('not sure.') + +# 列表匹配: +print('-- match list --') + +args = ['gcc', 'hello.c', 'world.c'] +# args = ['clean'] +# args = ['gcc'] + +match args: + # 如果仅出现gcc,报错: + case ['gcc']: + print('gcc: missing source file(s).') + # 出现gcc,且至少指定了一个文件: + case ['gcc', file1, *files]: + print('gcc compile: ' + file1 + ', ' + ', '.join(files)) + # 仅出现clean: + case ['clean']: + print('clean') + case _: + print('invalid command.') diff --git a/samples/basic/hello.py b/samples/basic/hello/hello.py similarity index 100% rename from samples/basic/hello.py rename to samples/basic/hello/hello.py diff --git a/samples/commonlib/use_chainmap.py b/samples/commonlib/use_chainmap.py new file mode 100755 index 00000000..406e29e0 --- /dev/null +++ b/samples/commonlib/use_chainmap.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from collections import ChainMap +import os, argparse + +defaults = { + 'color': 'red', + 'user': 'guest' +} + +parser = argparse.ArgumentParser() +parser.add_argument('-u', '--user') +parser.add_argument('-c', '--color') +namespace = parser.parse_args() +command_line_args = { k: v for k, v in vars(namespace).items() if v } + +combined = ChainMap(command_line_args, os.environ, defaults) +print('color=%s' % combined['color']) +print('user=%s' % combined['user']) diff --git a/samples/gui/turtle/rect.py b/samples/gui/turtle/rect.py new file mode 100644 index 00000000..9bd0e801 --- /dev/null +++ b/samples/gui/turtle/rect.py @@ -0,0 +1,26 @@ +# 导入turtle包的所有内容: +from turtle import * + +# 设置笔刷宽度: +width(4) + +# 前进: +forward(200) +# 右转90度: +right(90) + +# 笔刷颜色: +pencolor('red') +forward(100) +right(90) + +pencolor('green') +forward(200) +right(90) + +pencolor('blue') +forward(100) +right(90) + +# 调用done()使得窗口等待被关闭,否则将立刻关闭窗口: +done() diff --git a/samples/gui/turtle/stars.py b/samples/gui/turtle/stars.py new file mode 100644 index 00000000..3a7db272 --- /dev/null +++ b/samples/gui/turtle/stars.py @@ -0,0 +1,16 @@ +from turtle import * + +def drawStar(x, y): + pu() + goto(x, y) + pd() + # set heading: 0 + seth(0) + for i in range(5): + fd(40) + rt(144) + +for x in range(0, 250, 50): + drawStar(x, 0) + +done() diff --git a/samples/gui/turtle/tree.py b/samples/gui/turtle/tree.py new file mode 100644 index 00000000..43670e39 --- /dev/null +++ b/samples/gui/turtle/tree.py @@ -0,0 +1,59 @@ +from turtle import * + +colormode(255) + +lt(90) + +lv = 14 +l = 120 +s = 45 + +width(lv) + +r = 0 +g = 0 +b = 0 +pencolor(r, g, b) + +penup() +bk(l) +pendown() +fd(l) + +def draw_tree(l, level): + global r, g, b + # save the current pen width + w = width() + + # narrow the pen width + width(w * 3.0 / 4.0) + # set color: + r = r + 1 + g = g + 2 + b = b + 3 + pencolor(r % 200, g % 200, b % 200) + + l = 3.0 / 4.0 * l + + lt(s) + fd(l) + + if level < lv: + draw_tree(l, level + 1) + bk(l) + rt(2 * s) + fd(l) + + if level < lv: + draw_tree(l, level + 1) + bk(l) + lt(s) + + # restore the previous pen width + width(w) + +speed("fastest") + +draw_tree(l, 4) + +done() diff --git a/samples/micropython/hellorobot/.vscode/extensions.json b/samples/micropython/hellorobot/.vscode/extensions.json new file mode 100644 index 00000000..f8f1a440 --- /dev/null +++ b/samples/micropython/hellorobot/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/samples/micropython/hellorobot/.vscode/launch.json b/samples/micropython/hellorobot/.vscode/launch.json new file mode 100644 index 00000000..af12883d --- /dev/null +++ b/samples/micropython/hellorobot/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/samples/micropython/hellorobot/.vscode/settings.json b/samples/micropython/hellorobot/.vscode/settings.json new file mode 100644 index 00000000..37c9a5dd --- /dev/null +++ b/samples/micropython/hellorobot/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/samples/micropython/hellorobot/main.py b/samples/micropython/hellorobot/main.py new file mode 100644 index 00000000..d51e43bd --- /dev/null +++ b/samples/micropython/hellorobot/main.py @@ -0,0 +1,14 @@ +#!/usr/bin/env pybricks-micropython + +from pybricks import ev3brick as brick +from pybricks.ev3devices import (Motor, TouchSensor, ColorSensor, InfraredSensor, UltrasonicSensor, GyroSensor) +from pybricks.parameters import (Port, Stop, Direction, Button, Color, SoundFile, ImageFile, Align) +from pybricks.tools import print, wait, StopWatch +from pybricks.robotics import DriveBase + +# Write your program here +brick.sound.beep() +# 输出到控制台: +print('Hello, robot!') +# 输出到EV3屏幕: +brick.display.text('Hello, robot!') diff --git a/samples/micropython/rccar/.vscode/extensions.json b/samples/micropython/rccar/.vscode/extensions.json new file mode 100644 index 00000000..f8f1a440 --- /dev/null +++ b/samples/micropython/rccar/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/samples/micropython/rccar/.vscode/launch.json b/samples/micropython/rccar/.vscode/launch.json new file mode 100644 index 00000000..af12883d --- /dev/null +++ b/samples/micropython/rccar/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/samples/micropython/rccar/.vscode/settings.json b/samples/micropython/rccar/.vscode/settings.json new file mode 100644 index 00000000..37c9a5dd --- /dev/null +++ b/samples/micropython/rccar/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/samples/micropython/rccar/devices.py b/samples/micropython/rccar/devices.py new file mode 100644 index 00000000..0c6c133c --- /dev/null +++ b/samples/micropython/rccar/devices.py @@ -0,0 +1,47 @@ +# list input devices + +class InputDevice(): + def __init__(self): + self.name = '' + self.handler = '' + + def __str__(self): + return '' % (self.name, self.handler) + + def setName(self, name): + if len(name) >= 2 and name.startswith('"') and name.endswith('"'): + name = name[1:len(name)-1] + self.name = name + + def setHandler(self, handlers): + for handler in handlers.split(' '): + if handler.startswith('event'): + self.handler = handler + +def listDevices(): + devices = [] + with open('/proc/bus/input/devices', 'r') as f: + device = None + while True: + s = f.readline() + if s == '': + break + s = s.strip() + if s == '': + devices.append(device) + device = None + else: + if device is None: + device = InputDevice() + if s.startswith('N: Name='): + device.setName(s[8:]) + elif s.startswith('H: Handlers='): + device.setHandler(s[12:]) + return devices + +def detectJoystick(joystickNames): + for device in listDevices(): + for joystickName in joystickNames: + if joystickName in device.name: + return '/dev/input/%s' % device.handler + return None diff --git a/samples/micropython/rccar/main.py b/samples/micropython/rccar/main.py new file mode 100644 index 00000000..cf18c927 --- /dev/null +++ b/samples/micropython/rccar/main.py @@ -0,0 +1,100 @@ +#!/usr/bin/env pybricks-micropython + +import struct, threading + +from pybricks import ev3brick as brick +from pybricks.ev3devices import (Motor, TouchSensor, ColorSensor, InfraredSensor, UltrasonicSensor, GyroSensor) +from pybricks.parameters import (Port, Stop, Direction, Button, Color, SoundFile, ImageFile, Align) +from pybricks.tools import print, wait, StopWatch +from pybricks.robotics import DriveBase +from devices import detectJoystick + +class Robot(): + def __init__(self): + self.motor = Motor(Port.B) + self.ultrasonic = UltrasonicSensor(Port.S4) + self.active = True + self.speed = 0 + self.colors = [None, Color.GREEN, Color.YELLOW, Color.RED] + + def setSpeed(self, acc): + if acc < 0: + self.speed = max(-3, self.speed - 1) + elif acc > 0: + self.speed = min(3, self.speed + 1) + else: + self.speed = 0 + if self.speed != 0: + self.motor.run(self.speed * 90) + else: + self.motor.stop() + brick.light(self.colors[abs(self.speed)]) + + def inactive(self): + self.active = False + self.setSpeed(0) + brick.sound.beep() + +def autoStopLoop(robot): + while robot.active: + if robot.speed > 0 and robot.ultrasonic.distance() < 200: + robot.setSpeed(0) + wait(100) + +def joystickLoop(robot, eventFile): + FORMAT = 'llHHI' + EVENT_SIZE = struct.calcsize(FORMAT) + with open(eventFile, 'rb') as infile: + while True: + event = infile.read(EVENT_SIZE) + _, _, t, c, v = struct.unpack(FORMAT, event) + # button A, B: + if t == 1 and v == 1: + if c == 305: + # press A: + robot.setSpeed(1) + elif c == 304: + # press B: + robot.setSpeed(-1) + elif c == 307: + # press X: + return robot.inactive() + elif t == 3: + if c == 1: + # Left stick & vertical: + speed = 0 + if v < 32768: + # up: + speed = 1 + elif v > 32768: + # down: + speed = -1 + robot.setSpeed(speed) + +def buttonLoop(robot): + while True: + if not any(brick.buttons()): + wait(10) + else: + if Button.LEFT in brick.buttons(): + robot.setSpeed(-1) + elif Button.RIGHT in brick.buttons(): + robot.setSpeed(1) + elif Button.CENTER in brick.buttons(): + robot.setSpeed(0) + elif Button.UP in brick.buttons(): + return robot.inactive() + wait(500) + +def main(): + brick.sound.beep() + joystickEvent = detectJoystick(['Controller']) + robot = Robot() + t = threading.Thread(target=autoStopLoop, args=(robot,)) + t.start() + if joystickEvent: + joystickLoop(robot, joystickEvent) + else: + buttonLoop(robot) + +main() diff --git a/samples/micropython/smallcar/.vscode/extensions.json b/samples/micropython/smallcar/.vscode/extensions.json new file mode 100644 index 00000000..f8f1a440 --- /dev/null +++ b/samples/micropython/smallcar/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/samples/micropython/smallcar/.vscode/launch.json b/samples/micropython/smallcar/.vscode/launch.json new file mode 100644 index 00000000..af12883d --- /dev/null +++ b/samples/micropython/smallcar/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/samples/micropython/smallcar/.vscode/settings.json b/samples/micropython/smallcar/.vscode/settings.json new file mode 100644 index 00000000..a9e3a557 --- /dev/null +++ b/samples/micropython/smallcar/.vscode/settings.json @@ -0,0 +1,7 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false, + "python.formatting.provider": "autopep8" +} diff --git a/samples/micropython/smallcar/main.py b/samples/micropython/smallcar/main.py new file mode 100644 index 00000000..9ddd7aec --- /dev/null +++ b/samples/micropython/smallcar/main.py @@ -0,0 +1,51 @@ +#!/usr/bin/env pybricks-micropython + +from pybricks import ev3brick as brick +from pybricks.ev3devices import (Motor, TouchSensor, ColorSensor, InfraredSensor, UltrasonicSensor, GyroSensor) +from pybricks.parameters import (Port, Stop, Direction, Button, Color, SoundFile, ImageFile, Align) +from pybricks.tools import print, wait, StopWatch +from pybricks.robotics import DriveBase + +# Write your program here + +motor = Motor(Port.B) +ultrasonic = UltrasonicSensor(Port.S4) + +brick.sound.beep() +brick.light(None) + +speed = 0 +colors = [None, Color.GREEN, Color.YELLOW, Color.RED] + +def setSpeed(acc): + global speed + if acc < 0: + speed = max(0, speed - 1) + elif acc > 0: + speed = min(3, speed + 1) + else: + speed = 0 + if speed > 0: + motor.run(speed * 90) + else: + motor.stop() + brick.light(colors[speed]) + +while True: + if not any(brick.buttons()): + wait(10) + else: + if Button.LEFT in brick.buttons(): + setSpeed(-1) + elif Button.RIGHT in brick.buttons(): + setSpeed(1) + elif Button.CENTER in brick.buttons(): + setSpeed(0) + elif Button.UP in brick.buttons(): + setSpeed(0) + break + wait(500) + if ultrasonic.distance() < 200: + setSpeed(0) + +brick.sound.beep() diff --git a/samples/micropython/tank/.vscode/extensions.json b/samples/micropython/tank/.vscode/extensions.json new file mode 100644 index 00000000..f8f1a440 --- /dev/null +++ b/samples/micropython/tank/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "lego-education.ev3-micropython" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + "ms-python.python" + ] +} \ No newline at end of file diff --git a/samples/micropython/tank/.vscode/launch.json b/samples/micropython/tank/.vscode/launch.json new file mode 100644 index 00000000..af12883d --- /dev/null +++ b/samples/micropython/tank/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Download and Run", + "type": "ev3devBrowser", + "request": "launch", + "program": "/home/robot/${workspaceRootFolderName}/main.py" + } + ] +} diff --git a/samples/micropython/tank/.vscode/settings.json b/samples/micropython/tank/.vscode/settings.json new file mode 100644 index 00000000..37c9a5dd --- /dev/null +++ b/samples/micropython/tank/.vscode/settings.json @@ -0,0 +1,6 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.eol": "\n", + "debug.openDebug": "neverOpen", + "python.linting.enabled": false +} diff --git a/samples/micropython/tank/cannon.wav b/samples/micropython/tank/cannon.wav new file mode 100644 index 00000000..ee0d0102 Binary files /dev/null and b/samples/micropython/tank/cannon.wav differ diff --git a/samples/micropython/tank/devices.py b/samples/micropython/tank/devices.py new file mode 100644 index 00000000..0c6c133c --- /dev/null +++ b/samples/micropython/tank/devices.py @@ -0,0 +1,47 @@ +# list input devices + +class InputDevice(): + def __init__(self): + self.name = '' + self.handler = '' + + def __str__(self): + return '' % (self.name, self.handler) + + def setName(self, name): + if len(name) >= 2 and name.startswith('"') and name.endswith('"'): + name = name[1:len(name)-1] + self.name = name + + def setHandler(self, handlers): + for handler in handlers.split(' '): + if handler.startswith('event'): + self.handler = handler + +def listDevices(): + devices = [] + with open('/proc/bus/input/devices', 'r') as f: + device = None + while True: + s = f.readline() + if s == '': + break + s = s.strip() + if s == '': + devices.append(device) + device = None + else: + if device is None: + device = InputDevice() + if s.startswith('N: Name='): + device.setName(s[8:]) + elif s.startswith('H: Handlers='): + device.setHandler(s[12:]) + return devices + +def detectJoystick(joystickNames): + for device in listDevices(): + for joystickName in joystickNames: + if joystickName in device.name: + return '/dev/input/%s' % device.handler + return None diff --git a/samples/micropython/tank/joystick.py b/samples/micropython/tank/joystick.py new file mode 100644 index 00000000..0379051c --- /dev/null +++ b/samples/micropython/tank/joystick.py @@ -0,0 +1,61 @@ +# joystick control: + +import struct + +# define button code: + +BUTTON_A = 305 +BUTTON_B = 304 +BUTTON_X = 307 +BUTTON_Y = 306 +BUTTON_PLUS = 313 +BUTTON_MINUS = 312 +BUTTON_START = 317 +BUTTON_HOME = 316 + +class JoyStick(): + def __init__(self, eventFile): + self.eventFile = eventFile + self.buttonHandler = None + self.joyLeftHandler = None + self.joyRightHandler = None + + def setButtonHandler(self, buttonHandler): + self.buttonHandler = buttonHandler + + def setJoyLeftHandler(self, joyLeftHandler): + self.joyLeftHandler = joyLeftHandler + + def setJoyRightHandler(self, joyRightHandler): + self.joyRightHandler = joyRightHandler + + def startLoop(self): + FORMAT = 'llHHI' + EVENT_SIZE = struct.calcsize(FORMAT) + with open(self.eventFile, 'rb') as infile: + lx, ly, rx, ry = 0, 0, 0, 0 + while True: + event = infile.read(EVENT_SIZE) + _, _, t, c, v = struct.unpack(FORMAT, event) + if t == 1 and v == 1: + # button pressed: + if self.buttonHandler: + if not self.buttonHandler(c): + return + if t == 3: + if c == 0 and self.joyLeftHandler: + # left stick & horizontal: + lx = v - 32768 + self.joyLeftHandler(lx, ly) + elif c == 1 and self.joyLeftHandler: + # left stick & vertical: + ly = v - 32768 + self.joyLeftHandler(lx, ly) + elif c == 3 and self.joyRightHandler: + # right stick & horizontal: + rx = v - 32768 + self.joyRightHandler(rx, ry) + elif c == 4 and self.joyRightHandler: + # right stick & vertical: + ry = v - 32768 + self.joyRightHandler(rx, ry) diff --git a/samples/micropython/tank/main.py b/samples/micropython/tank/main.py new file mode 100644 index 00000000..efb082da --- /dev/null +++ b/samples/micropython/tank/main.py @@ -0,0 +1,103 @@ +#!/usr/bin/env pybricks-micropython + +import struct, threading + +from pybricks import ev3brick as brick +from pybricks.ev3devices import (Motor, TouchSensor, ColorSensor, InfraredSensor, UltrasonicSensor, GyroSensor) +from pybricks.parameters import (Port, Stop, Direction, Button, Color, SoundFile, ImageFile, Align) +from pybricks.tools import print, wait, StopWatch +from pybricks.robotics import DriveBase + +from devices import detectJoystick +from joystick import JoyStick, BUTTON_A, BUTTON_X + +SPEED = 100 +STEERING = 90 + +STATUS_STOPPED = 0 +STATUS_FORWARD = 1 +STATUS_BACKWARD = 2 +STATUS_STEERING = 3 + +COLORS = (None, Color.GREEN, Color.RED, Color.YELLOW) + +class Driver(): + def __init__(self, leftMotor, rightMotor, diameter, axle): + self.driver = DriveBase(leftMotor, rightMotor, diameter, axle) + self.x = 0 + self.y = 0 + self.speed = 0 + self.steering = 0 + + def drive(self, speed, steering): + self.speed = speed + self.steering = steering + if self.speed == 0: + self.driver.stop() + else: + self.driver.drive(self.speed, self.steering) + +class Robot(): + def __init__(self, leftMotor, rightMotor, topMotor, diameter, axle, maxSpeed=300, maxSteering=180, port=Port.S4): + self.driver = Driver(leftMotor, rightMotor, diameter, axle) + self.cannon = topMotor + self.ultrasonic = UltrasonicSensor(port) + self.speedStep = 32767 // maxSpeed + self.steeringStep = 32767 // maxSteering + self.active = True + + def drive(self, x, y): + # map y (-32768 ~ +32767) to speed (+maxSpeed ~ -maxSpeed): + speed = -y // self.speedStep + # map x (-32768 ~ +32767) to steering (-maxSteering ~ +maxSteering): + steering = x // self.steeringStep + self.driver.drive(speed, steering) + + def target(self, x): + self.cannon.run(-x // 327) + + def fire(self): + brick.sound.file('cannon.wav') + + def inactive(self): + self.active = False + self.drive(0, 0) + brick.sound.beep() + +def autoStopLoop(robot): + while robot.active: + if robot.ultrasonic.distance() < 200: + robot.drive(0, 0) + wait(100) + +def main(): + brick.sound.beep() + joystickEvent = detectJoystick(['Controller']) + if joystickEvent: + robot = Robot(Motor(Port.D), Motor(Port.A), Motor(Port.B), 55, 200) + t = threading.Thread(target=autoStopLoop, args=(robot,)) + t.start() + + def onButtonPressed(code): + if code == BUTTON_X: + robot.inactive() + return False + if code == BUTTON_A: + robot.fire() + return True + + def onLeftJoyChanged(x, y): + robot.drive(x, y) + + def onRightJoyChanged(x, y): + robot.target(x) + + joystick = JoyStick(joystickEvent) + joystick.setButtonHandler(onButtonPressed) + joystick.setJoyLeftHandler(onLeftJoyChanged) + joystick.setJoyRightHandler(onRightJoyChanged) + joystick.startLoop() + else: + brick.sound.beep() + +main() diff --git a/samples/multitask/task_worker.py b/samples/multitask/task_worker.py index a5d0097e..8155a2b6 100755 --- a/samples/multitask/task_worker.py +++ b/samples/multitask/task_worker.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -import time, sys, queue +import time, sys from multiprocessing.managers import BaseManager # 创建类似的QueueManager: diff --git a/teach/README.md b/teach/README.md deleted file mode 100644 index d5cb2ae8..00000000 --- a/teach/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# 安装Python学习助手 - -首先确认Python 3.4已安装。 - -# 下载learning.py - -下载地址: - -[https://raw.githubusercontent.com/michaelliao/learn-python3/master/teach/learning.py](https://raw.githubusercontent.com/michaelliao/learn-python3/master/teach/learning.py) - -(右键 - 另存为) - -放到某个目录,例如`C:\Work`下。 - -# 运行命令: - -切换到`learning.py`所在目录,运行: - -``` -C:\Work> python learning.py -``` - -如果看到`Ready for Python code on port 39093...`表示运行成功,不要关闭命令行窗口,最小化放到后台运行即可。 - -![run-learning.py.png](https://raw.githubusercontent.com/michaelliao/learn-python3/master/teach/run-learning.py.png) diff --git a/teach/learning.py b/teach/learning.py deleted file mode 100755 index 4335c9e3..00000000 --- a/teach/learning.py +++ /dev/null @@ -1,250 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -r''' -learning.py - -A Python 3 tutorial from https://www.liaoxuefeng.com - -Usage: - -python3 learning.py -''' - -# check ####################################################################### - -import sys -from datetime import datetime - -CERT_EXPIRES = '2018-07-01' - -def check_version(): - v = sys.version_info - if v.major == 3 and v.minor >= 5: - return - print('Your current python is %d.%d. Please use Python 3.6.' % (v.major, v.minor)) - exit(1) - -def check_cert(): - today = datetime.now().strftime('%Y-%m-%d') - if today >= CERT_EXPIRES: - print('This learning.py is expired. Please download a newer version.') - exit(1) - -check_version() -check_cert() - -# start server ################################################################ - -import os, io, json, subprocess, tempfile, ssl -from urllib import parse -from http.server import HTTPServer, BaseHTTPRequestHandler, SimpleHTTPRequestHandler - -EXEC = sys.executable -PORT = 39093 -TEMP = tempfile.mkdtemp(suffix='_py', prefix='learn_python_') - -HTML_INDEX = r''' - - Learning Python - -
- -

-
- - -''' - -class LearningHTTPRequestHandler(BaseHTTPRequestHandler): - - def do_GET(self): - self.close_connection = True - if self.path != '/': - return self.send_error(404) - self._sendHttpHeader('text/html') - self._sendHttpBody(HTML_INDEX) - - def do_POST(self): - self.close_connection = True - if self.path != '/run': - return self.send_error(400) - print('Prepare code...') - body = self.rfile.read(int(self.headers['Content-length'])) - qs = parse.parse_qs(body.decode('utf-8')) - if not 'code' in qs: - return self.send_error(400) - code = qs['code'][0] - r = dict() - try: - fpath = write_py(get_name(), code) - print('Execute: %s %s' % (EXEC, fpath)) - r['output'] = decode(subprocess.check_output([EXEC, fpath], stderr=subprocess.STDOUT, timeout=5)) - except subprocess.CalledProcessError as e: - r = dict(error='Exception', output=decode(e.output)) - except subprocess.TimeoutExpired as e: - r = dict(error='Timeout', output='执行超时') - except subprocess.CalledProcessError as e: - r = dict(error='Error', output='执行错误') - print('Execute done.') - self._sendHttpHeader() - self._sendHttpBody(r) - - def _sendHttpHeader(self, contentType='application/json'): - origin = self.headers['Origin'] or 'https://www.liaoxuefeng.com' - self.send_response(200) - self.send_header('Content-Type', contentType) - self.send_header('Access-Control-Allow-Origin', origin) - self.send_header('Access-Control-Allow-Methods', 'GET,POST') - self.send_header('Access-Control-Max-Age', '86400') - self.end_headers() - - def _sendHttpBody(self, data): - body = b'' - if isinstance(data, bytes): - body = data - elif isinstance(data, str): - body = data.encode('utf-8', errors='ignore') - else: - body = json.dumps(data).encode('utf-8', errors='ignore') - self.wfile.write(body) - -def main(): - certfile = write_cert() - httpd = HTTPServer(('127.0.0.1', PORT), LearningHTTPRequestHandler) - httpd.socket = ssl.wrap_socket(httpd.socket, certfile=certfile, server_side=True) - print('Ready for Python code on port %d...' % PORT) - print('Press Ctrl + C to exit...') - httpd.serve_forever() - -# functions ################################################################### - -INDEX = 0 - -def get_name(): - global INDEX - INDEX = INDEX + 1 - return 'test_%d' % INDEX - -def write_py(name, code): - fpath = os.path.join(TEMP, '%s.py' % name) - with open(fpath, 'w', encoding='utf-8') as f: - f.write(code) - print('Code wrote to: %s' % fpath) - return fpath - -def decode(s): - try: - return s.decode('utf-8') - except UnicodeDecodeError: - return s.decode('gbk') - -# certificate ################################################################# - -def write_cert(): - fpath = os.path.join(TEMP, 'local.liaoxuefeng.com.pem') - with open(fpath, 'w', encoding='utf-8') as f: - f.write(CERT_DATA) - return fpath - -CERT_DATA = r''' ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA5b3zv77bzN8JShoXkVjXFG9NK342wnfgye+NmuSoRfCMPrwL -GToJZiwxokXGyVY8obmQA69WUgonpuotp0AhDK8bOvykKuX+7MyE36sh9TUVOiIw -6D3ODG2E1K5IIEytfGhuPmeJe3OapnL/lJytlLhonu63VEf+jpYh6I/gXD4hZu1N -tx4rOeJLl3qSFgRgX4oBZtO0d4aHop/XW5XcdaeuJxIW5qw7PxXqlch4h9TUs0Og -udko380DrO9pmTuVXr2rtk6Jy96wDAVwsAiSX85FF59Q3QmjDzM+fx8a/vyWkxOw -9dT0DzfZBJ9g/tPk13ir14U1vPpDMO1lIXjKZQIDAQABAoIBAEp+FwT7W8XII/j1 -EOM+DS9BD6KkoBjaSfbwR9gLgEx9PNwymN6rJNUOS2G0gkpSPgKqannnZnPfew/y -Kq9qacz1Ej1EIe8O+GPLxOHJWY9qkOFyqK0FLUR2VnWntRdUBYSrT+PIKpnu2BxU -eW60hswMJ1AxUxxu46lUINaJoFQH7ANHzpCxXFiWDiVK8VCCFS3MaJfqz945zLdg -orHMty+gCcaWRX9wanZ5k9RmX2qzqLAAhlnKIfmItpel8HTppOk1taVDopUgPGd+ -8IG7IANbRlykkeBvlA5soSk7RNM2+crHcdCz5ehoSjMHsY3e99EPoPjKQmb3Ak0p -zgtjPpkCgYEA8p+eULq0OM2anLQeOqQe2QNxkTuriOI2qyobOnCYAJRFlxCLJ8K8 -OIf+srIJUYzJsGmPSqo8iizM5V9bmBRihYnPwePUJS0af8G2vdeJARoAFBo4LZNi -YBN3Gi6hKo8hDgOPQ6D2a25NXYua4z5HlOb8PU6JhX1/6O6yv4ScZh8CgYEA8miG -QxHbx3a7Zfy3/QCQrEwmbp9k49ex/DZvh50N5MqG9h6lb6+ct+qUT7HkvcXUrBxL -6HP7aLVUTTvo9z10sBh1Kt1UQP/57JbKQNMCYKUbMxZH59XdFPzVwkbyDE7Z29tf -8QEMnk9CM6HbvbQDSvOZ04IsfSEstMEPKqVmFvsCgYEAsOSborRdTcTp4zKXj521 -N/gAxyjAKe70eNscOwF4cYOpMTjInFaosHbGxjZ0ANcq/coYxRFVTlDXmqxptXm3 -UzFlHjIjrG80EM2FlOgeZYU1ZXKwXtpEMVQ/1AEHVGZCbVs/CsnCoBUtpvRwGxp/ -ShsW8QPf1EnqBkRyYpwnA3UCgYA5nrLbWnFddlGRKoMpdmrtKaSxAt5ecjTyeJYG -LETTL3jpI9u7MokUBoR+dRCkM1QcHRXGCVunRgLl4Om9azRDb2zaZYXTdYUYwbcN -tZqJEnXmrNMmvmUwyfCdn3OFjXCnm/uwM8mmD7zyvPSYoSNvO3xDFFwy2iHgTUun -nW0o5QKBgQCF/mCu/z1+CsddcHu1RYjnG08uVk0ErjTLB5Qy0YI2NWVE2zdV9fi9 -MWn7S+oEcmjaMdXdF0W/MDyB8TLUSdsXGHPl/vRizK3vhDQGxQ+y3ru8GEVq8BjX -YePMDifbgHDXrCeBeb7TypefD/ScxdVJdI9sPSno20AehzDkXcAssQ== ------END RSA PRIVATE KEY----- - ------BEGIN CERTIFICATE----- -MIIFzTCCBLWgAwIBAgIQB594sjWBo6qup5zlKa2F7zANBgkqhkiG9w0BAQsFADCB -lzELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs -IEluYy4xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxHTAbBgNVBAsT -FERvbWFpbiBWYWxpZGF0ZWQgU1NMMSEwHwYDVQQDExhUcnVzdEFzaWEgRFYgU1NM -IENBIC0gRzUwHhcNMTcwNzA1MDAwMDAwWhcNMTgwNzA1MjM1OTU5WjAgMR4wHAYD -VQQDDBVsb2NhbC5saWFveHVlZmVuZy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDlvfO/vtvM3wlKGheRWNcUb00rfjbCd+DJ742a5KhF8Iw+vAsZ -OglmLDGiRcbJVjyhuZADr1ZSCiem6i2nQCEMrxs6/KQq5f7szITfqyH1NRU6IjDo -Pc4MbYTUrkggTK18aG4+Z4l7c5qmcv+UnK2UuGie7rdUR/6OliHoj+BcPiFm7U23 -His54kuXepIWBGBfigFm07R3hoein9dbldx1p64nEhbmrDs/FeqVyHiH1NSzQ6C5 -2SjfzQOs72mZO5Vevau2TonL3rAMBXCwCJJfzkUXn1DdCaMPMz5/Hxr+/JaTE7D1 -1PQPN9kEn2D+0+TXeKvXhTW8+kMw7WUheMplAgMBAAGjggKJMIIChTAgBgNVHREE -GTAXghVsb2NhbC5saWFveHVlZmVuZy5jb20wCQYDVR0TBAIwADBhBgNVHSAEWjBY -MFYGBmeBDAECATBMMCMGCCsGAQUFBwIBFhdodHRwczovL2Quc3ltY2IuY29tL2Nw -czAlBggrBgEFBQcCAjAZDBdodHRwczovL2Quc3ltY2IuY29tL3JwYTAfBgNVHSME -GDAWgBRtWMd/GufhPy6mjJc1Qrv00zisPzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0l -BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGbBggrBgEFBQcBAQSBjjCBizA8Bggr -BgEFBQcwAYYwaHR0cDovL3RydXN0YXNpYTItb2NzcC5kaWdpdGFsY2VydHZhbGlk -YXRpb24uY29tMEsGCCsGAQUFBzAChj9odHRwOi8vdHJ1c3Rhc2lhMi1haWEuZGln -aXRhbGNlcnR2YWxpZGF0aW9uLmNvbS90cnVzdGFzaWFnNS5jcnQwggEDBgorBgEE -AdZ5AgQCBIH0BIHxAO8AdQDd6x0reg1PpiCLga2BaHB+Lo6dAdVciI09EcTNtuy+ -zAAAAV0QuhtTAAAEAwBGMEQCIERpJLcXX4eFEW02eZMh6EYFW236foQrCsakOgQQ -NW96AiBCE6/7vrUxWKf964i4D9z2NA0TCuXm9giVgQaFju0XXQB2AKS5CZC0GFgU -h7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABXRC6G5MAAAQDAEcwRQIhAK4GeiTU -OQcjGFvLAugOMIEKCEuiJsEu0t+f1ql5Edn2AiAUqqLMw87IkjMnJsbEUGsHkng0 -KL6MLDC3BaHVcH6HsjANBgkqhkiG9w0BAQsFAAOCAQEAYDU2DSBh/63brAW/VWlQ -PQIZzWhji6209MG5hg/RN3Zo9uoz2GodNWwOSkvcFVUz9oBExLfcfhZAsBz26dgs -abWstAje63oduhXU9MR1LDFfG6GLit0Pou0yiS0hfg3jpxpYCIo97QAe8bkuMdRQ -7V09yKKo44M+iXbkIUivnM1ckYJHU9xQ3y8/q/DQajUmVIEPRzmyz6B3tP4WA11T -X5T89OK6osvLcYSJXvxOeR3J8Ohxdwi+PRX4BCgXgTseOj+biwJuCo9z7uwvCoXG -fdilj1tXNa5eDtSRplqbFB+kPGkP/NZ5b1+huarDqE/aeNpmREqONhxi49KB1/9u -1w== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIFZTCCBE2gAwIBAgIQOhAOfxCeGsWcxf/2QNXkQjANBgkqhkiG9w0BAQsFADCB -yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL -ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp -U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW -ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5IC0gRzUwHhcNMTYwODExMDAwMDAwWhcNMjYwODEwMjM1OTU5WjCBlzEL -MAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIElu -Yy4xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxHTAbBgNVBAsTFERv -bWFpbiBWYWxpZGF0ZWQgU1NMMSEwHwYDVQQDExhUcnVzdEFzaWEgRFYgU1NMIENB -IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC39aSJZG/97x3a -6Qmuc9+MubagegRAVUmFYHTYTs8IKB2pM7wXN7W8mekdZaEgUjDFxvRBK/DhTb7U -8ONLsKKdT86aOhzbz2noCTn9wPWnGwkg+/4YKg/dPQQdV9tMsSu0cwqInWHxSAkm -AI1hYFC9D7Sf7Hp/5cRcD+dK454YMRzNOGLQnCVI8JEqrz6o9SOvQNTqTcfqt6DC -0UlXG+MPD1eNPjlzf1Vwaab+VSTgySoC+Ikbq2VsdykeOiGXW/OIiASH7+2LcR05 -PmQ7GEOlM8yzoVojFpM8sHz+WxI05ZOPri5+vX3HhHHjWr5432G0dVmgohnZvlVZ -oy8XrlbpAgMBAAGjggF2MIIBcjASBgNVHRMBAf8ECDAGAQH/AgEAMC8GA1UdHwQo -MCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNvbS9wY2EzLWc1LmNybDAOBgNVHQ8B -Af8EBAMCAQYwLgYIKwYBBQUHAQEEIjAgMB4GCCsGAQUFBzABhhJodHRwOi8vcy5z -eW1jZC5jb20wYQYDVR0gBFowWDBWBgZngQwBAgEwTDAjBggrBgEFBQcCARYXaHR0 -cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGRoXaHR0cHM6Ly9kLnN5 -bWNiLmNvbS9ycGEwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCkGA1Ud -EQQiMCCkHjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0yLTYwMTAdBgNVHQ4EFgQU -bVjHfxrn4T8upoyXNUK79NM4rD8wHwYDVR0jBBgwFoAUf9Nlp8Ld7LvwMAnzQzn6 -Aq8zMTMwDQYJKoZIhvcNAQELBQADggEBABUphhBbeG7scE3EveIN0dOjXPgwgQi8 -I2ZAKYm6DawoGz1lEJVdvFmkyMbP973X80b7mKmn0nNbe1kjA4M0O0hHaMM1ZaEv -7e9vHEAoGyysMO6HzPWYMkyNxcCV7Nos2Uv4RvLDpQHh7P4Kt6fUU13ipcynrtQD -1lFUM0yoTzwwFsPu3Pk+94hL58ErqwqJQwxoHMgLIQeMVHeNKcWFy1bddSbIbCWU -Zs6cMxhrra062ZCpDCbxyEaFNGAtYQMqNz55Z/14XgSUONZ/cJTns6QKhpcgTOwB -fnNzRnk+aWreP7osKhXlz4zs+llP7goBDKFOMMtoEXx3YjJCKgpqmBU= ------END CERTIFICATE----- -''' - -# start main at last ########################################################## - -if __name__ == '__main__': - main() diff --git a/teach/run-learning.py.png b/teach/run-learning.py.png deleted file mode 100644 index d9491a95..00000000 Binary files a/teach/run-learning.py.png and /dev/null differ