最新消息:

乐高 EV3 高级编程 – 第八课:控制传感器

乐高 少儿编程 2414浏览 0评论

EV3: Lesson 8 – Control Sensors

EV3: 第 8 课 – 控制传感器

 

8.1 Control Sensor by Object Oriented Programs

8.1 使用面向对象程序控制传感器

 

The program should explain itself, read carefully about the comments.

程序已经很清楚的解释自己了,小心的阅读注释。

Before you run the programs, attach 2 large motors to port A and B, attach a touch sensor to port 1, and attach a Ultrasonic sensor to port 2.

运行程序之前,在端口 A 及 B 安装两个 大马达,在端口 1 安装一个【按键传感器】,在端口 2 安装一个 【超声波传感器】。

Create and copy the following codes to the corresponding programs:

新建并拷贝下面的程序:

 

from ev3dev.ev3 import *
from time import sleep, time
from importlib import *
import g
import traceback

class SENSORPARM:
    intNoOfSensor = 0

    # The type of sensor: 
    # "T" = Touch sensor
    # "C" = Color sensor
    # "U" = Ultrasonic sensor
    # "I" = Infrared sensor
    # "G" = Gyro sensor
    gastrSType = []

    # The port of sensor: Port "1" - "4"
    gastrSPort = []

    # The Mode of sensor:
    # Color Sensor: "COL-COLOR" for Color, "COL-REFLECT" for Reflection, "COL-AMBIENT" for Ambient
    # Touch Sensor: "TOUCH"
    # Ultrasonic sensor: "US-DIST-CM" for cm
    # Infrared sensor: "IR-PROX"
    # Gyro sensor: "GYRO-ANG"
    gastrSMode = []


class MOTORPARM:
    intNoOfMotor = 0
    
    # The type of motor: 
    # "L" = Large motor, 
    # "M" = Medium motor
    gastrMType = []

    # The port of motor: Port "A" - "D"
    gastrMPort = []

    # The movement direction of motor: either 1 or -1
    gaintMDir = []

    # The fastest speed of motor: Large Motor: 0 - 900, Medium Motor: 0 - 1500
    gaintMDefSpeed = []

    # L means robot uses this motor to turn left
    # R means robot uses this motor to turn right
    # N special motor
    gastrLRN = []

    # Radius for wheel
    gafloRadius = []

class ROBOT:
    lcd = Screen()
    btn = Button()
    gM = []
    gS = []
    
    def __init__(self, mtp, ssp):
        global module
        module = __import__(g.module)



        # Define sensors
        try:
            if (ssp.intNoOfSensor > 0):
                i = 1
                while i <= ssp.intNoOfSensor:
                    if (ssp.gastrSType[i - 1] == "T"):
                        # Define Touch Sensor
                        self.gS.insert(i - 1, TouchSensor("in" + ssp.gastrSPort[i - 1]))
                    elif (ssp.gastrSType[i - 1] == "C"):
                        # Define Color Sensor
                        self.gS.insert(i - 1, ColorSensor("in" + ssp.gastrSPort[i - 1]))
                    elif (ssp.gastrSType[i - 1] == "U"):
                        # Define Ultrasonic Sensor
                        self.gS.insert(i - 1, UltrasonicSensor("in" + ssp.gastrSPort[i - 1]))
                    elif (ssp.gastrSType[i - 1] == "I"):
                        # Define Infrared Sensor
                        self.gS.insert(i - 1, InfraredSensor("in" + ssp.gastrSPort[i - 1]))
                    elif (ssp.gastrSType[i - 1] == "G"):
                        # Define Gyro Sensor
                        self.gS.insert(i - 1, GyroSensor("in" + ssp.gastrSPort[i - 1]))
                       
                    intStartTime = time()
                    bolDefineSensor = False
                    while not bolDefineSensor:
                        intEndTime = time()
                        try:
                            assert self.gS[i - 1].connected, "Connect a sensor to port " + ssp.gastrSPort[i - 1]
                            bolDefineSensor = True
                            if (intEndTime - intStartTime > 1):
                                self.DefineSErr(ssp.gastrSPort[i - 1])
                        except:
                            bolDefineSensor = False
                    sleep(0.5)
                    intStartTime = time()
                    bolDefineSensor = False
                    while not bolDefineSensor:
                        intEndTime = time()
                        try:
                            self.gS[i - 1].mode = ssp.gastrSMode[i - 1]
                            bolDefineSensor = True
                            if (intEndTime - intStartTime > 1):
                                self.DefineSErr(ssp.gastrSPort[i - 1])
                        except:
                            bolDefineSensor = False
                    sleep(0.1)

                    # Next Sensor
                    i = i + 1
                    sleep(0.1)
        except:
            # If there is any error, show a log file with prefex e_m + "A/B/C/D" to show which
            # port's motor is not connected
            self.DefineSErr(ssp.gastrSPort[i - 1])



        # Define motors
        try:
            if (mtp.intNoOfMotor > 0):
                i = 1
                while i <= mtp.intNoOfMotor:
                    if (mtp.gastrMType[i - 1] == "L"):
                        self.gM.insert(i - 1, LargeMotor('out' + mtp.gastrMPort[i - 1]))
                    else:
                        self.gM.insert(i - 1, MediumMotor('out' + mtp.gastrMPort[i - 1]))
                    i = i + 1
                    sleep(0.1)
                i = 1
                while i <= mtp.intNoOfMotor:
                    self.MoveMotor(mtp, i, "F", 1, 100, 0)
                    sleep(0.01)
                    self.StopMotor(i)
                    i = i + 1
        except:
            # If there is any error, show a log file with prefex e_m + "A/B/C/D" to show which
            # port's motor is not connected
            logtime = str(time())
            f=open("e_m" + mtp.gastrMPort[i - 1] + logtime + ".txt",'a')
            traceback.print_exc(file=f)  
            f.flush()  
            f.close()
            sys.exit()



    def DefineSErr(strPort):
        logtime = str(time())
        f=open("e_s" + strPort + logtime + ".txt",'a')
        traceback.print_exc(file=f)  
        f.flush()  
        f.close()
        sys.exit()
    
         
        
    # LCD & Buttons Related Methods
    # The following method display a Menu on the lcd screen and wait for user selection
    # ShowMenu() Begin
    def ShowMenu(self, strMenuTitle, listMenu, listFunction):
        global module
        intSelect = 1
        intNoOfLine = len(listMenu)

        bolSelect = False
        bolPressed = False

        # Continue to loop until the user make a selection
        while not bolSelect:
            self.lcd.clear()

            intX = 5
            intY = 5
        
            # Display title
            self.lcd.draw.text((intX, intY), strMenuTitle)

            # Display a line after the title, to separate the title and the content
            self.lcd.draw.line((0, intY + 12, 177, intY + 12), fill = None, width = 0)

            intY = intY + 5
             
            # Display all lines
            i = 1
            while i <= intNoOfLine:
                intY = intY + 15
                if i == intSelect:
                    # If the cursor is on this line, reverse the color of this line
                    self.lcd.draw.rectangle((0, intY, 177, intY + 10), fill = 'black')
                    self.lcd.draw.text((intX, intY), listMenu[i - 1], fill = 'white')
                else:
                    # If the cursor is not on this line, display the text on this line 
                    self.lcd.draw.text((intX, intY), listMenu[i - 1])
                i = i + 1

            # Show the screen
            self.lcd.update()

            if bolPressed:
                sleep(0.5)
                bolPressed = False

            # if bolWait == True, continue waiting for key press event
            bolWait = True
            while bolWait:
                if self.btn.up:
                    # if Up is pressed
                    bolPressed = True
                    bolWait = False
                    # Cursor go up 1 line
                    intSelect = intSelect - 1
                    if intSelect == 0:
                        # if Cursor at line 0, set Cursor to last line
                        intSelect = intNoOfLine
                elif self.btn.down:
                    # if Down is pressed
                    bolPressed = True
                    bolWait = False
                    # Cursor go down 1 line
                    intSelect = intSelect + 1
                    if intSelect > intNoOfLine:
                        intSelect = 1
                elif self.btn.left:
                    # if Left is pressed, do nothing
                    pass
                elif self.btn.right:
                    # if Right is pressed, do nothing
                    pass
                elif self.btn.enter:
                    # if Enter is pressed, exit loop
                    bolWait = False
                    bolSelect = True
                else:
                    # Sleep for 0.05 seconds to detect another key press
                    sleep(0.05)

        # Important to sleep here, otherwise the btn.enter will be catched by another menu
        sleep(0.5)

        # From here User has made its selection, do the function according to user selection
        func = getattr(module, listFunction[intSelect-1])
        func()
    # ShowMenu() End


    # Show a Single String at intX, intY
    # bolClear = True means Clear the screen before display string
    def DisplaySingleString(self, intX, intY, strMessage, bolClear):
        if (bolClear):
            self.lcd.clear()

        self.lcd.draw.text((intX, intY), strMessage)

        # Show the screen
        self.lcd.update()
    # DisplayLCD() End

    # Display Whole String at 0,0 until screen full, clear screen first!
    def DisplayWholeString(self, strMessage):
        intCharPerLine = 29
        self.lcd.clear()
        bolFinish = False
        strLeft = strMessage
        intX = 0
        intY = 0
        while (not bolFinish):
            if (len(strLeft) <= intCharPerLine):
                bolFinish = True
                strCurLine = strLeft
            else:
                strCurLine = strLeft[:intCharPerLine]
                strLeft = strLeft[-(len(strLeft)-intCharPerLine):]
            self.lcd.draw.text((intX,intY), strCurLine)
            intY += 12
            if (intY >= 116):
                bolFinish = True
        self.lcd.update()



    # Motor Related Methods

    # Move a single motor
    def MoveMotor(self, mtp, intMotorNo, strType, intDir, intSpeed, intValue):
        if (strType == "F"):
            # Move a Motor Forever
            self.gM[intMotorNo - 1].run_forever(speed_sp=intSpeed * intDir * mtp.gaintMDir[intMotorNo - 1])
        elif (strType == "A"):
            # Move a Motor a certain Degree intValue
            self.gM[intMotorNo - 1].run_to_rel_pos(position_sp=intValue * mtp.gaintMDir[intMotorNo - 1] * intDir, speed_sp=intSpeed, stop_action="hold")
        elif (strType == "DA"):
            # Move wheel ? Distance cm calculated by movement of motor Angle
            self.gM[intMotorNo - 1].run_to_rel_pos(position_sp=intValue * mtp.gaintMDir[intMotorNo - 1] * intDir * 360 / (2 * 3.141592654 * mtp.gafloRadius[intMotorNo - 1]) , speed_sp=intSpeed, stop_action="hold")
    # MoveMotor End

    # Stop a single motor
    def StopMotor(self, intMotorNo):
        self.gM[intMotorNo - 1].stop(stop_action="hold")
    # StopMotor End


    # Move Robot
    # floSpeedFL -1.0 to 1.0
    def MoveRobot(self, mtp, strType, floSpeedFL, floSpeedFR, intValue):
        floMaxSF = 0
        if (abs(floSpeedFL) > abs(floSpeedFR)):
            floMaxSF = abs(floSpeedFL)
        else:
            floMaxSF = abs(floSpeedFR)
        intMaxSpeed = 0
        floMaxRadius = 0

        intDir = 0
        if (strType == "F"):
            # Move Robot Forever
            for i in range(1,mtp.intNoOfMotor + 1):
                if (mtp.gastrLRN[i - 1] == "L"):
                    if (floSpeedFL > 0):
                        self.MoveMotor(mtp, i, strType, 1, mtp.gaintMDefSpeed[i - 1] * floSpeedFL, 0)
                    else:
                        self.MoveMotor(mtp, i, strType, -1, mtp.gaintMDefSpeed[i - 1] * floSpeedFL * -1 , 0)
                if (mtp.gastrLRN[i - 1] == "R"):
                    if (floSpeedFR > 0):
                        self.MoveMotor(mtp, i, strType, 1, mtp.gaintMDefSpeed[i - 1] * floSpeedFR, 0)
                    else:
                        self.MoveMotor(mtp, i, strType, -1, mtp.gaintMDefSpeed[i - 1] * floSpeedFR * -1, 0)
        elif (strType == "A" or strType == "DA"):
            # "A" - Move Robot a Certain Degree, 
            # "DA" - Move Certain Distance in cm calculated by Degree and Radius "DA"
            for i in range(1,mtp.intNoOfMotor + 1):
                if (mtp.gaintMDefSpeed[i - 1] > intMaxSpeed):
                    intMaxSpeed = mtp.gaintMDefSpeed[i - 1]
                if (mtp.gafloRadius[i - 1] > floMaxRadius):
                    floMaxRadius = mtp.gafloRadius[i - 1]
                if (mtp.gastrLRN[i - 1] == "L"):
                    if (floSpeedFL > 0):
                        self.MoveMotor(mtp, i, strType, 1, mtp.gaintMDefSpeed[i - 1] * floSpeedFL, intValue)
                    else:
                        self.MoveMotor(mtp, i, strType, -1, mtp.gaintMDefSpeed[i - 1] * floSpeedFL * -1, intValue)
                if (mtp.gastrLRN[i - 1] == "R"):
                    if (floSpeedFR > 0):
                        self.MoveMotor(mtp, i, strType, 1, mtp.gaintMDefSpeed[i - 1] * floSpeedFR, intValue)
                    else:
                        self.MoveMotor(mtp, i, strType, -1, mtp.gaintMDefSpeed[i - 1] * floSpeedFR * -1, intValue)
            intMaxSpeed = intMaxSpeed * floMaxSF
            intSleepSecond = 0
            if (strType == "A"):
                intSleepSecond = intValue/720*900/intMaxSpeed
            elif (strType == "DA"):
                intSleepSecond = intValue/720*900/intMaxSpeed*360/2/3.141592654/floMaxRadius
            sleep(intSleepSecond)                
    # Move robot End


    # Stop Robot
    def StopRobot(self):
        for i in range(1,mtp.intNoOfMotor + 1):
             if (mtp.gastrLRN[i - 1] == "L" or mtp.gastrLRN[i - 1] == "R"):
                self.gM[i - 1].stop(stop_action="hold")
    # StopRobot End

zephan.top/ev3pythonles

上面这个是 roboy.py

 

import robot

def funInitRobot():
    global rb, module, mtp, ssp

    module = 'fun'

    mtp = robot.MOTORPARM()
    mtp.intNoOfMotor = 2

    ssp = robot.SENSORPARM()
    ssp.intNoOfSensor = 2

    # Sensor 1
    ssp.gastrSType.insert(0, "T")
    ssp.gastrSPort.insert(0, "1")
    ssp.gastrSMode.insert(0, "TOUCH")

    # Sensor 2
    ssp.gastrSType.insert(1, "U")
    ssp.gastrSPort.insert(1, "2")
    ssp.gastrSMode.insert(1, "US-DIST-CM")

    # Motor 1
    mtp.gastrMType.insert(0, "L")
    mtp.gastrMPort.insert(0, "A")
    mtp.gaintMDir.insert(0, 1)
    mtp.gaintMDefSpeed.insert(0, 900)
    mtp.gastrLRN.insert(0, "L")
    mtp.gafloRadius.insert(0, 3.0)

    # Motor 2
    mtp.gastrMType.insert(1, "L")
    mtp.gastrMPort.insert(1, "B")
    mtp.gaintMDir.insert(1, 1)
    mtp.gaintMDefSpeed.insert(1, 900)
    mtp.gastrLRN.insert(1, "R")
    mtp.gafloRadius.insert(1, 3.0)

    rb = robot.ROBOT(mtp, ssp)

zephan.top/ev3pythonles

上面这个是 g.py

 

from time import sleep, time
import g

def StartProgram():
    strMenuTitle = 'Main Menu'
    listMenu = ['Press to Move','Move B 20cm','Quit']
    listFunction = ['funMove','funB20', 'funQuit']
    g.rb.ShowMenu(strMenuTitle, listMenu, listFunction)

def funMove():
    g.rb.DisplayWholeString("Program Starts")

    bolExit = False
    while not bolExit:
        if (g.rb.gS[0].value() == 1):
            g.rb.MoveRobot(g.mtp, "DA", 1, 1, 10)
        if (g.rb.gS[1].value() < 200):
            bolExit = True
        sleep(0.1)


def funB20():
    g.rb.MoveRobot(g.mtp, "DA", -1, -1, 20)

def funQuit():
    pass

zephan.top/ev3pythonles

上面这个是 fun.py

 

#!/usr/bin/env python3
from time import sleep, time
import traceback
import g
import fun

# Initialize the LCD and Buttons
try:
    g.funInitRobot()

    # fun.StartProgram()
    fun.StartProgram()
except:
    # If there is any error, it will be stored in the log file in the same directory
    logtime = str(time())
    f=open("log" + logtime + ".txt",'a')  
    traceback.print_exc(file=f)  
    f.flush()  
    f.close()

zephan.top/ev3pythonles

上面这个是 lesson8_01.py

 

Upload the above 4 programs and run lesson8_01.py in the EV3 brick, press the Touch Button to move the motors, put something in front of the Ultrasonic Sensor to stop the program.

上传上面这 4 个程序,并且在 EV3 里运行 lesson8_01.py。

按【按键传感器】去启动马达。

在【超声波传感器】前面放点东西去结束程序。

From now on, the robot.py IS COMPLETED, you can now use it in different projects without changing the programs inside robot.py.

从现在开始,robot.py 这个程序已经基本完成里,你可以使用它在不同的项目里,而不需要更改里面的内容。

 

Declare variables in g.py so that all programs within the same project can access those variables by using:

对于某一个项目里,所有程序都需要用到的全局变量,你可以在 g.py 里去声明它,并且在其他程序里用以下方式去使用这个变量:

g.variablename

 

Instead of naming the Main Program as lesson8_01.py, in the future, you may name your Main Program as any name you like, for example: “main.py”

在你将来的项目里,你不一定要使用类似 lesson8_01.py 去命名你的主程序,你可以使用任何你喜欢的主程序名称,比方说 main.py。

 

You may also change the name for “fun.py”, codes inside this program should be modified for different projects.

你也可以改变 fun.py 这个程序名称,这个程序的内容,每一个项目应该是不一样的。

 

 

译者后记:

作者关于 ev3dev 的面向对象编程课程,暂时就只有那么多了,帮他翻译了以后,我发现他的内容还是不够丰富,对于程序的解释也不够详细,需要读者自己慢慢的去了解程序,不过对于一个只有 12 岁的作者,能写出这样的课程,还可以了!

作为作者的教练,我会建议他后面再加一些实战篇,图文并茂的解释如何用 ev3dev 编写实用程序,比方说【相扑机器人】之类的。

不过这段时间正在教他如何编写【微信】类的通讯 app,使用了 Cordova 和 Node.js,socket.io 等等技术,对他来说还是有一定难度,新的课程可能要稍等了,希望将来有机会和大家分享。

大家可能会问我的学生是外国人吗?为什么写的课程是英文的呢?不是的,是中国人,因为他英文菜,又要参加国际比赛,必须用英语和外国裁判沟通和解释程序,因此我是强迫他平常多用英语。这里我必须提醒一下学生们,想拿某些机器人比赛的世界冠军,英语水平占了挺大的比重的,尤其是创意赛,所有海报要英语,解释要英语,演讲要英语,问答要英语,要是裁判不明白,分数就自然低了哦!

始发于知乎专栏:ken

您必须 登录 才能发表评论!