使用 Linkbot 学习 Python 3/处理不完美
with open("in_test.txt", "rt") as in_file:
with open("out_test.txt", "wt") as out_file:
text = in_file.read()
data = parse(text)
results = encode(data)
out_file.write(results)
print( "All done." )
如果在这段代码中的任何地方发生了某种错误(其中一个文件无法访问,parse()函数因损坏的数据而阻塞等等),“with”语句保证所有文件最终都会被正确关闭。关闭文件只是意味着文件被我们的程序“清理”和“释放”,以便它可以在另一个程序中使用。
因此,您现在有了完美的程序,它运行得非常完美,除了一个细节,它会在无效的用户输入时崩溃。不要害怕,因为 Python 为您提供了一个特殊的控制结构。它叫做 try
,它会尝试做某事。这是一个有问题的程序的示例
print("Type Control C or -1 to exit")
number = 1
while number != -1:
number = int(input("Enter a number: "))
print("You entered:", number)
注意,当您输入 @#&
时,它会输出类似以下的内容
Traceback (most recent call last): File "try_less.py", line 4, in <module> number = int(input("Enter a number: ")) ValueError: invalid literal for int() with base 10: '\\@#&'
如您所见,int()
函数对数字 @#&
不满意(理所当然)。最后一行显示了问题所在;Python 发现了一个 ValueError
。我们的程序如何处理这种情况?我们要做的第一件事是:将可能发生错误的地方放在 try
块中,第二件事是:告诉 Python 我们希望如何处理 ValueError
。以下程序就是这样做的
print("Type Control C or -1 to exit")
number = 1
while number != -1:
try:
number = int(input("Enter a number: "))
print("You entered:", number)
except ValueError:
print("That was not a number.")
现在,当我们运行新程序并提供 @#&
时,它会告诉我们“这不是一个数字”,并继续之前正在做的事情。
当您的程序不断出现您知道如何处理的错误时,请将代码放在 try
块中,并将处理错误的方式放在 except
块中。
我们在前面的示例中已经看到,我们可以编写一个函数,使轮式机器人行驶一定距离。我们还可以使用 setJointSpeed()
函数控制电机转速。setJointSpeed()
函数期望以度/秒为单位的转速,但如果我们可以使用英寸/秒为单位来设置机器人速度,那就更好了。将 英寸/秒转换为 度/秒的数学公式为
其中 是轮子半径。让我们扩展来自 使用 Linkbot 学习 Python 3/定义函数 部分的示例
术语 字符 是“omega”,通常用于表示转速。通常, 的单位是弧度/秒,但在本例中,单位是度/秒。 |
import barobo
import math # So that we can use math.pi
dongle = barobo.Dongle()
dongle.connect()
myLinkbot = dongle.getLinkbot('abcd') # Change abcd to your Linkbot's serial ID
def driveDistance(linkbot, distance):
r = 3.5 / 2 # If you have a wheel that's not 3.5 inches in diameter, change "3.5" to the diameter of your wheel
degrees = (360) / (2 * math.pi * r) * distance
linkbot.move(degrees, 0, -degrees)
def setSpeed(linkbot, speed):
r = 3.5 / 2
omega = (speed/r) * (180/math.pi)
linkbot.setJointSpeed(1, omega)
linkbot.setJointSpeed(3, omega)
setSpeed(myLinkbot, 2.5) # Sets the speed to 2.5 inches/sec
driveDistance(myLinkbot, 10) # Drives the Linkbot 10 inches forward
driveDistance(myLinkbot, -5) # Drives the Linkbot 5 inches backward
这个示例很好。我们定义了一个名为 setSpeed()
的新函数,它设置 Linkbot 轮式车辆的速度,我们使用它将速度设置为 2.5 英寸/秒。
如果程序员尝试将速度设置为 1000 英寸/秒?或者 1000000 英寸/秒?尽管看到 Linkbot 与一级方程式赛车竞争会很酷,但 Linkbot 的电机在物理上无法超过 200 度/秒。如果速度过高,我们应该设置一个用户可以看到并可能处理的错误。这叫做“引发异常”。引发异常的代码如下所示
def setSpeed(linkbot, speed):
r = 3.5 / 2
omega = (speed/r) * (180/math.pi)
if omega > 200:
raise Exception('The speed is too high!')
linkbot.setJointSpeed(1, omega)
linkbot.setJointSpeed(3, omega)
当引发异常时,函数立即返回异常。这些引发的异常可以被 try/except 块捕获。如果异常发生在 try/except 块之外,整个程序将退出并显示异常的错误消息。在 setSpeed()
函数中,这意味着如果执行了 raise
,则两个 setJointSpeed()
语句将被跳过。
当我运行新程序并尝试将速度设置为 1000 英寸/秒时,我得到以下输出
Traceback (most recent call last): File "./linkbot_speed.py", line 20, in <module> setSpeed(myLinkbot, 1000) # Sets the speed to 1000 inches/sec File "./linkbot_speed.py", line 16, in setSpeed raise Exception('The speed is too high!') Exception: The speed is too high!
现在您可以使用 try/catch 块来处理可能的错误。让我们尝试编写一个程序,它尝试再次将速度设置为 10 英寸/秒,但每次遇到异常时,它都会将请求的速度降低 1 英寸/秒,并再次尝试。
import barobo
import math # So that we can use math.pi
dongle = barobo.Dongle()
dongle.connect()
myLinkbot = dongle.getLinkbot('ABCD') # Change ABCD to your Linkbot's serial ID
def driveDistance(linkbot, distance):
r = 3.5 / 2 # If you have a wheel that's not 3.5 inches in diameter, change "3.5" to the diameter of your wheel
degrees = (360) / (2 * math.pi * r) * distance
linkbot.move(degrees, 0, -degrees)
def setSpeed(linkbot, speed):
r = 3.5 / 2
omega = (speed/r) * (180/math.pi)
if omega > 200:
raise Exception('The speed is too high!')
linkbot.setJointSpeed(1, omega)
linkbot.setJointSpeed(3, omega)
requestedSpeed = 10 # 1
while True: # 2
try:
print('Trying to set speed to: ' + str(requestedSpeed) + 'inches/sec')
setSpeed(myLinkbot, requestedSpeed) # 3
print('Success!')
break # 4
except:
print('Failed.')
requestedSpeed -= 1 # 5
# 6
driveDistance(myLinkbot, 10) # Drives the Linkbot 10 inches forward
driveDistance(myLinkbot, -5) # Drives the Linkbot 5 inches backward
输出为
Trying to set speed to: 10inches/sec Failed. Trying to set speed to: 9inches/sec Failed. Trying to set speed to: 8inches/sec Failed. Trying to set speed to: 7inches/sec Failed. Trying to set speed to: 6inches/sec Success!
让我们一起逐步执行这个程序,确保我们完全理解正在发生的事情。
- # 1 : 当我们第一次到达这一行时,我们创建一个名为
requestedSpeed
的新变量,并将其值设置为“10”。 - # 2 : 进入无限循环
- # 3 : 尝试设置速度。
requestedSpeed
当前为 10,过高。setSpeed()
函数抛出异常。由于我们在 try/except 块中,因此在抛出异常后立即转到 except 块。继续执行 # 5 - # 5 : 将
requestedSpeed
减少 1。requestedSpeed
现在为 9。这是我们while
循环的结束,这意味着 Python 将返回到循环的开头。 - # 3 : 我们再次回到 # 3,除了
requestedSpeed
现在为 9。仍然过高,抛出异常。 - # 5 : 我们再次将
requestedSpeed
减至 8。 - # 3 : 仍然过高...
- # 5 : 减少至 7...
- # 3 : 仍然过高...
- # 5 : 减少至 6。
- # 3 : 现在成功了。由于它成功了,所以没有抛出异常。继续执行 # 4
- # 4 : 此
break
语句将我们从循环中弹出。继续执行 # 6 和程序的其余部分。
至少更新电话号码程序(在部分 字典 中),以便在用户在菜单中未输入任何数据时不会崩溃。