友情提示:380元/半年,儿童学编程,就上码丁实验室。
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")
http://www.zephan.top/ev3pythonlessons/lesson7/lesson7_01.py
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
http://www.zephan.top/ev3pythonlessons/lesson7/robot.py
上面这个是 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)
http://www.zephan.top/ev3pythonlessons/lesson7/g.py
上面这个是 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
http://www.zephan.top/ev3pythonlessons/lesson7/fun.py
上面这个是 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()
http://www.zephan.top/ev3pythonlessons/lesson7/lesson7_02.py
上面这个是 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