最新消息:

乐高 EV3 高级编程 – 第七课:控制马达

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

EV3: Lesson 7 – Control Motors

EV3:第 7 课 – 控制马达

 

7.1 Simple Motor Controls

7.1 简单控制马达第方法

 

Below is a simple program to demonstrate how to control a motor in EV3.

下面是一个简单的控制马达程序。

#!/usr/bin/env python3
from time import sleep, time
from ev3dev.ev3 import *

mA = LargeMotor("outA")
mB = MediumMotor("outB")

mA.run_forever(speed_sp=900)
mB.run_forever(speed_sp=-1500)
sleep(3)
mA.stop(stop_action="hold")
mB.stop(stop_action="hold")
sleep(1)
mA.run_to_rel_pos(position_sp=360, speed_sp=900, stop_action="hold")
mB.run_to_rel_pos(position_sp=-720, speed_sp=1500, stop_action="hold")

zephan.top/ev3pythonles

 

Before running this program, you should first connect a large motor to port A and a medium motor to port B.

The run_forever function keeps the motor running forever at the speed specified.

The run_to_rel_pos function turns the motor at given angle relative to the current angle.

在运行这个程序之前,你必须先连接一个大马达到端口A,并且连接一个中马达到端口B。

run_forever 这个函数,让该马达永远以设定的速度一直运行。

run_to_rel_pos 这个函数,让该马达以当前的角度为基础,转某一个设定的角度。

However, we are not going to control motors in this way, similar to previous lessons, we are going to write object oreinted programs to control motors.

但是,我们不会用这种方式控制马达,和之前的课程一样,我们将会用面向对象的方式,控制马达。

 

Create and copy following codes into corresponding programs:

新建并拷贝下面的程序:

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

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 = []
    
    def __init__(self, mtp):
        global module
        module = __import__(g.module)

        # 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()


    
    
            
    # 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

上面这个是 robot.py

 

import robot

def funInitRobot():
    global rb, module, mtp
    module = 'fun'
    mtp = robot.MOTORPARM()
    mtp.intNoOfMotor = 2
    # 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)

zephan.top/ev3pythonles

上面这个是 g.py

 

from time import sleep, time
import g

def StartProgram():
    strMenuTitle = 'Main Menu'
    listMenu = ['Move F 30cm','Move B 40cm','Quit']
    listFunction = ['funF30','funB40', 'funQuit']
    g.rb.ShowMenu(strMenuTitle, listMenu, listFunction)

def funF30():
    g.rb.MoveRobot(g.mtp, "DA", 1, 1, 30)

def funB40():
    g.rb.MoveRobot(g.mtp, "DA", -1, -1, 40)

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()
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

上面这个是 lesson7_02.py

 

Upload the above 4 programs and run lesson7_02.py in the EV3 brick, you’ll see the motors run as expected.

上传上面这 4 个程序,并且在 EV3 里运行 lesson7_02.py,你会发现马达将会如期运动。

 

(译者自己加的内容:

作者忘记说:这次需要在端口 A 和 B 连接两个大马达!另外,比方说,如果马达 A 没有按照你想要的方向运动,你只需要在 g.py 里的这一句:

mtp.gaintMDir.insert(0, 1)

换成

mtp.gaintMDir.insert(0, -1)

作者这个方法还是比较聪明的,因为每个人安装马达的方向都不一样,用这个 1 或者 -1 就可以简单的调整马达运行方向。

下面这一句,也是比较聪明,设置了轮子的半径为 3.0cm (或者是你的轮子半径),就可以简单的控制轮子的运行距离。

mtp.gafloRadius.insert(0, 3.0)

译者自己加的内容完毕)

 

 

To turn right at maximum speed, simply use:

如果你想让机器人永远用最大马力右转,只需要用以下这句:

 

g.rb.MoveRobot(g.mtp, “F”, 1, -1, 0)

 

To turn left at half speed, simply use:

如果你想让机器人永远用一半马力左转,只需要用以下这句:

g.rb.MoveRobot(g.mtp, “F”, -0.5, 0.5, 0)

You should read the above programs line by line carefully, the programs explain themselves.

你需要一句一句的阅读上面的程序。

 

 

In our next lesson, we’ll talk about how to control sensors.

在下一课,我们将会学习如何控制传感器。

始发于知乎专栏:ken

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