内容简介:移动电机是EV3的核心。机器人需要移动的能力,因此你需要知道它是如何完成的。请参阅文档将一些电机插入你选择的端口,然后以全功率启动它们。这通过以下直接命令完成:过了一段时间,你,你的父母,兄弟姐妹或孩子会对全动力马达的声音感到紧张。如果你是一个爱好和平的人,你应该发送以下直接命令:
移动电机是EV3的核心。机器人需要移动的能力,因此你需要知道它是如何完成的。请参阅文档 EV3 Firmware Developer Kit 中的第 4.9 部分,以获得与电机相对应的操作的第一印象。几乎所有这些都以相同的两个参数开头:
-
LAYER:如果组合多个 EV3 brick 作为单个机器,则声明其中一个是主机,最多3个额外 brick 作为主机从机。然后将操作发送到主机,主机将其发送给主机从机。这就是 LAYER 的含义。Layer 0x|00| 是主机,layers 0x|01|,0x|02| 和 0x|03| 是它的可选从机。在没有从机的标准情况下,我们将设置 LAYER = 0x|00|。我们的直接命令代码可以连接多个 EV3 设备。因此,我认为不需要不同的参数 LAYER 值。
-
NO 或 NOS:电机端口以字母 A,B,C 和 D 标识。在直接命令的层面,你可以通过数字命名它们,A = 0x|01|,B = 0x|02|,C = 0x|04| 和 D = 0x|08|。如果你将这些数字写为二进制表示,则 A = 0b 0000 0001,B = 0b 0000 0010,C = 0b 0000 0100 和 C = 0b 0000 1000,你看,后半个字节可以解释为一系列的四个标志。你可以组合这些标志。如果你处理端口 A 和 C 的电机操作,则设置 NOS = 0x|05| 或 0b 0000 0101。如果参数名称为 NO,则只能处理单个电机端口。NOS是说,你可以处理一个或多个端口。
启动和停止电机
将一些电机插入你选择的端口,然后以全功率启动它们。这通过以下直接命令完成:
----------------------------------------------
\len \cnt \ty\hd \op\la\no\power\op\la\no\
----------------------------------------------
0x|0D:00|2A:00|80|00:00|A4|00|0F|81:64|A6|00|0F|
----------------------------------------------
\13 \42 \no\0,0 \O \0 \a \100 \O \0 \a \
\ \ \ \ \u \ \l \ \u \ \l \
\ \ \ \ \t \ \l \ \t \ \l \
\ \ \ \ \p \ \ \ \p \ \ \
\ \ \ \ \u \ \ \ \u \ \ \
\ \ \ \ \t \ \ \ \t \ \ \
\ \ \ \ \_ \ \ \ \_ \ \ \
\ \ \ \ \P \ \ \ \S \ \ \
\ \ \ \ \o \ \ \ \t \ \ \
\ \ \ \ \w \ \ \ \a \ \ \
\ \ \ \ \e \ \ \ \r \ \ \
\ \ \ \ \r \ \ \ \t \ \ \
----------------------------------------------
过了一段时间,你,你的父母,兄弟姐妹或孩子会对全动力马达的声音感到紧张。如果你是一个爱好和平的人,你应该发送以下直接命令:
----------------------------------
\len \cnt \ty\hd \op\la\no\br\
----------------------------------
0x|09:00|2A:00|00|00:00|A3|00|0F|00|
----------------------------------
\9 \42 \re\0,0 \O \0 \a \no\
\ \ \ \ \u \ \l \ \
\ \ \ \ \t \ \l \ \
\ \ \ \ \p \ \ \ \
\ \ \ \ \u \ \ \ \
\ \ \ \ \t \ \ \ \
\ \ \ \ \_ \ \ \ \
\ \ \ \ \S \ \ \ \
\ \ \ \ \t \ \ \ \
\ \ \ \ \o \ \ \ \
\ \ \ \ \p \ \ \ \
----------------------------------
我们看到了三个新操作:
-
opOutput_Power = 0x|A4|,参数是
- LAYER
- NOS
- POWER:指定输出功率 [-100 – 100 %](负值意味着相反的方向)
-
opOutput_Start = 0x|A6|,参数是
- LAYER
- NOS
-
opOutput_Stop = 0x|A3|,参数是
- LAYER
- NOS
- BRAKE:指定制动级别 [0:浮动,1:制动]。这不是被动制动器,其中电动机固定在其位置上。它是一个主动的,电机试图回到原来的位置,这需要能量!
通过这三个操作,我们可以启动和停止电机。我们还应该讨论另一个,它设定了极性。通常,电动机的运动以前后方向描述,并且使用正数和负数。如果我们的机器结构导致极性相反,则有一个操作,可以改变它:
-
opOutput_Polarity = 0x|A7|,参数是
- LAYER
- NOS
-
POLARITY:指定极性 [-1, 0, 1]
- -1:电机将向后运行
- 0:电机将反方向运行
- -1:电机将向前运行
定义速度而不是功率通常是更好的选择。幸运的是,乐高电机固定的电机,我们可以通过以下操作轻松定义电机运动的恒定速度:
-
opOutput_Speed = 0x|A5|,参数是
- LAYER
- NOS
- SPEED:指定输出速度 [-100 – 100 %](负值意味着相反的方向)
请构造一辆由两个电机驱动的车辆,一个用于左侧,另一个用于右侧。精心设计的例子是:
- http://robotsquare.com/2015/10/06/explor3r-building-instructions
- http://robotsquare.com/wp-content/uploads/2013/10/45544_educator.pdf
- http://www.lego.com/en-gb/mindstorms/build-a-robot/track3r
- http://www.lego.com/en-gb/mindstorms/build-a-robot/robodoz3r
但一个简单的也将满足我们的需求。将右侧电机连接到端口 A,将左侧电机连接到端口 D,并发送以下直接命令:
-------------------------------------------
\len \cnt \ty\hd \op\la\no\sp\op\la\no\
-------------------------------------------
0x|0C:00|2A:00|80|00:00|A5|00|09|3D|A6|00|09|
-------------------------------------------
\12 \42 \no\0,0 \O \0 \A \-3\O \0 \A \
\ \ \ \ \u \ \+ \ \u \ \+ \
\ \ \ \ \t \ \D \ \t \ \D \
\ \ \ \ \p \ \ \ \p \ \ \
\ \ \ \ \u \ \ \ \u \ \ \
\ \ \ \ \t \ \ \ \t \ \ \
\ \ \ \ \_ \ \ \ \_ \ \ \
\ \ \ \ \S \ \ \ \S \ \ \
\ \ \ \ \p \ \ \ \t \ \ \
\ \ \ \ \e \ \ \ \a \ \ \
\ \ \ \ \e \ \ \ \r \ \ \
\ \ \ \ \d \ \ \ \t \ \ \
-------------------------------------------
希望你的车辆以低速直行。使用上面的直接命令(opOutput_Stop)来停止它。
遥控车辆
现在是编写实际应用程序的时候了。使用遥控 EV3 车辆给你的朋友或孩子留下深刻印象。我们从一个简单的遥控器开始,并使用键盘箭头键来改变速度和方向。首先将新操作添加到 EV3 类,然后编写远程控制程序。像往常一样,我已经以 python 3 完成了它:
#!/usr/bin/env python3
import curses
import ev3
def move(speed: int, turn: int)->None:
global myEV3, stdscr
stdscr.addstr(5, 0, 'speed: {}, turn: {} '.format(speed, turn))
if turn > 0:
speed_right = speed
speed_left = round(speed * (1 - turn / 100))
else:
speed_right = round(speed * (1 + turn / 100))
speed_left = speed
ops = b''.join([
ev3.opOutput_Speed,
ev3.LCX(0), # LAYER
ev3.LCX(ev3.PORT_A), # NOS
ev3.LCX(speed_right), # SPEED
ev3.opOutput_Speed,
ev3.LCX(0), # LAYER
ev3.LCX(ev3.PORT_D), # NOS
ev3.LCX(speed_left), # SPEED
ev3.opOutput_Start,
ev3.LCX(0), # LAYER
ev3.LCX(ev3.PORT_A + ev3.PORT_D) # NOS
])
myEV3.send_direct_cmd(ops)
def stop()->None:
global myEV3, stdscr
stdscr.addstr(5, 0, 'vehicle stopped ')
ops = b''.join([
ev3.opOutput_Stop,
ev3.LCX(0), # LAYER
ev3.LCX(ev3.PORT_A + ev3.PORT_D), # NOS
ev3.LCX(0) # BRAKE
])
myEV3.send_direct_cmd(ops)
def react(c):
global speed, turn
if c in [ord('q'), 27, ord('p')]:
stop()
return
elif c == curses.KEY_LEFT:
turn += 5
turn = min(turn, 200)
elif c == curses.KEY_RIGHT:
turn -= 5
turn = max(turn, -200)
elif c == curses.KEY_UP:
speed += 5
speed = min(speed, 100)
elif c == curses.KEY_DOWN:
speed -= 5
speed = max(speed, -100)
move(speed, turn)
def main(window)->None:
global stdscr
stdscr = window
stdscr.clear() # print introduction
stdscr.refresh()
stdscr.addstr(0, 0, 'Use Arrows to navigate your EV3-vehicle')
stdscr.addstr(1, 0, 'Pause your vehicle with key <p>')
stdscr.addstr(2, 0, 'Terminate with key <q>')
while True:
c = stdscr.getch()
if c in [ord('q'), 27]:
react(c)
break
elif c in [ord('p'),
curses.KEY_RIGHT, curses.KEY_LEFT, curses.KEY_UP, curses.KEY_DOWN]:
react(c)
speed = 0
turn = 0
myEV3 = ev3.EV3(protocol=ev3.BLUETOOTH, host='00:16:53:42:2B:99')
stdscr = None
# ops = opOutput_Polarity + b'\x00' + LCX(PORT_A + PORT_D) + LCX(-1)
# myEV3.send_direct_cmd(ops)
curses.wrapper(main)
一些说明:
-
我使用模块
curses来实现键盘事件的事件处理程序。 -
方法
wrapper控制资源键盘和终端。它改变终端的行为,创建一个窗口对象并调用函数main。 -
函数
main将一些文本写入终端,然后等待键事件(方法getch)。 -
如果其中一个相关键命中,则调用函数
react,键<q>或<Ctrl-c>打破循环。 -
变量
speed定义了更快轮子的速度。 -
变量
turn定义方向。值 0 表示直行,正值表示左转,负值表示右转。转弯的绝对值大意味着转弯的半径小。最大值+200 和最小值 -200 意味着在原地盘旋。在下一课中,我们将回到驱动转弯的这个定义。 -
我在第 5 步改变了
speed和turn。这似乎是精确度和反应速度之间的良好折衷。 - 也许,你的车辆结构需要改变两个车轮的极性。这由注释掉的代码完成。
- 右轮连接到端口 A,左侧连接到端口 D。
- 对于低速,由于四舍五入到整数值,转弯半径的精度变得更差。
中断作为一种设计理念
上一课,我们将中断与不耐烦和乖巧的人进行了比较。本课程表明,这种行为恰恰是一种切实可行的设计理念。
遥控程序发送无限的命令,如果不被下一个命令中断,它将永久地移动电机。控制驾驶的人类希望纠正立即生效。这是绝对正确的,新命令会中断旧命令。
该设计概念的另一个积极方面是直接命令的执行时间短。它们不耗时。电机的运动持续很长时间,但是当电机获得新参数时,直接命令已经执行完成。控制立即返回,程序是自由的,以执行下一个任务。资源 EV3 设备未被阻塞,它可用于下一个直接命令。
你已经看到了如何编码远程控制的中断过程。中心部分是一个请求关键事件的循环。如果相关的按键事件发生,则调用一个函数,该函数更改运动的参数并向 EV3 设备发送直接命令。
当我们在 c’’(上一课)中玩三合一时,我们避免了中断。我们有一个固定的所有音调时间表。我们的意见是,每次中断都会扰乱计划,需要加以防范。在绘制三角形时,我们已经讨论了两种时序选择,通过直接命令或本地程序。也可以使用本地程序中的调度并使用中断来播放三元组。这是获得正确时序的替代方法:
#!/usr/bin/env python3
import ev3, time
my_ev3 = ev3.EV3(protocol=ev3.BLUETOOTH, host='00:16:53:42:2B:99')
ops = b''.join([
ev3.opUI_Write,
ev3.LED,
ev3.LED_RED,
ev3.opSound,
ev3.TONE,
ev3.LCX(1),
ev3.LCX(262),
ev3.LCX(0)
])
my_ev3.send_direct_cmd(ops)
time.sleep(0.5)
ops = b''.join([
ev3.opUI_Write,
ev3.LED,
ev3.LED_GREEN,
ev3.opSound,
ev3.TONE,
ev3.LCX(1),
ev3.LCX(330),
ev3.LCX(0)
])
my_ev3.send_direct_cmd(ops)
time.sleep(0.5)
ops = b''.join([
ev3.opUI_Write,
ev3.LED,
ev3.LED_RED,
ev3.opSound,
ev3.TONE,
ev3.LCX(1),
ev3.LCX(392),
ev3.LCX(0)
])
my_ev3.send_direct_cmd(ops)
time.sleep(0.5)
ops = b''.join([
ev3.opUI_Write,
ev3.LED,
ev3.LED_RED_FLASH,
ev3.opSound,
ev3.TONE,
ev3.LCX(1),
ev3.LCX(523),
ev3.LCX(0)
])
my_ev3.send_direct_cmd(ops)
time.sleep(2)
ops = b''.join([
ev3.opUI_Write,
ev3.LED,
ev3.LED_GREEN,
ev3.opSound,
ev3.BREAK
])
my_ev3.send_direct_cmd(ops)
此版本还实现了固定的调度,但时间发生在程序中而不是 EV3 设备上(在直接命令中)。同样,这有一定的优势,它不阻塞 EV3 设备。只要我们一次只执行一个任务,阻塞就无关紧要了。如果我们试图结合独立的声音和点击驱动,且并行执行任务,则本地时序和中断是必须的。
如果我们在上面的程序中设置 sync_mode == SYNC,数据流量会增长,但我们不会听到任何差异。值得反思的是,该程序同步运行,因为没有直接命令是耗时的。sync_mode == ASYNC 或 sync_mode == STD 是为异步执行设计的,但我们也可以使用这些设置编写同步执行代码。异步执行仅在直接命令耗时(时间由直接命令完成)且本地程序不等待直接命令结束时。中断有助于避免耗时的直接命令,并且是同步执行。
继承 EV3
到目前为止,我们直接在我们的程序中编写了操作。这需要封装和抽象。我想特化类,一个用于带两个驱动轮的车辆,一个用于音调和音乐等等。设计应该允许它们平并行使用。我的解决方案是大量的 EV3 类的子类,它们都与同一个 EV3 设备通信。这就是说,它们必须共享资源。为了实现这一点,我修改了 EV3 类的构造函数:
| __init__(self, protocol:str=None, host:str=None, ev3_obj=None) | Establish a connection to a LEGO EV3 device | | Keyword Arguments (either protocol and host or ev3_obj): | protocol: None, 'Bluetooth', 'Usb' or 'Wifi' | host: None or mac-address of the LEGO EV3 (f.i. '00:16:53:42:2B:99') | ev3_obj: None or an existing EV3 object (its connections will be used)
代码是:
class EV3:
def __init__(self, protocol: str=None, host: str=None, ev3_obj=None):
assert ev3_obj or protocol, \
'Either protocol or ev3_obj needs to be given'
if ev3_obj:
assert isinstance(ev3_obj, EV3), \
'ev3_obj needs to be instance of EV3'
self._protocol = ev3_obj._protocol
self._device = ev3_obj._device
self._socket = ev3_obj._socket
elif protocol:
assert protocol in [BLUETOOTH, WIFI, USB], \
'Protocol ' + protocol + 'is not valid'
self._protocol = None
self._device = None
self._socket = None
if protocol == BLUETOOTH:
assert host, 'Protocol ' + protocol + 'needs host-id'
self._connect_bluetooth(host)
elif protocol == WIFI:
self._connect_wifi()
elif protocol == USB:
self._connect_usb()
self._verbosity = 0
self._sync_mode = STD
self._msg_cnt = 41
一些注解:
-
有两种创建类 EV3 的新实例的方式:
-
和以前一样,使用参数
protocol和host调用构造函数以获取新连接。 -
另一种方法是使用现有的 EV3 对象作为参数
ev3_obj调用它,使用其中的连接。
-
和以前一样,使用参数
- 这不仅限于连接。对于将来的扩展,我们可以共享任何资源。
-
每个类都有自己的
_verbosity和_sync_mode。这是 OK 的,但我们使消息计数器_msg_cnt成为一个类属性:class EV3: _msg_cnt = 41
考虑到这一点,我编写了类 TwoWheelVehicle
,这里是它的构造函数:
class TwoWheelVehicle(ev3.EV3):
def __init__(
self,
protocol: str=None,
host: str=None,
ev3_obj: ev3.EV3=None
):
super().__init__(protocol=protocol, host=host, ev3_obj=ev3_obj)
self._polarity = 1
self._port_left = ev3.PORT_D
self._port_right = ev3.PORT_A
我添加了两个方法:
def move(self, speed: int, turn: int)->None:
assert self._sync_mode != ev3.SYNC, "no unlimited operations allowed in sync_mode SYNC"
assert isinstance(speed, int), "speed needs to be an integer value"
assert -100 <= speed and speed <= 100, "speed needs to be in range [-100 - 100]"
assert isinstance(turn, int), "turn needs to be an integer value"
assert -200 <= turn and turn <= 200, "turn needs to be in range [-200 - 200]"
if self._polarity == -1:
speed *= -1
if self._port_left < self._port_right:
turn *= -1
if turn > 0:
speed_right = speed
speed_left = round(speed * (1 - turn / 100))
else:
speed_right = round(speed * (1 + turn / 100))
speed_left = speed
ops = b''.join([
ev3.opOutput_Speed,
ev3.LCX(0), # LAYER
ev3.LCX(PORT_A), # NOS
ev3.LCX(speed_right), # SPEED
ev3.opOutput_Speed,
ev3.LCX(0), # LAYER
ev3.LCX(PORT_D), # NOS
ev3.LCX(speed_left), # SPEED
ev3.opOutput_Start,
ev3.LCX(0), # LAYER
ev3.LCX(PORT_A + PORT_D) # NOS
])
self.send_direct_cmd(ops)
和
def stop(self, brake: bool=False)->None:
assert isinstance(brake, bool), "brake needs to be a boolean value"
if brake:
br = 1
else:
br = 0
ops_stop = b''.join([
ev3.opOutput_Stop,
ev3.LCX(0), # LAYER
ev3.LCX(self._port_left + self._port_right), # NOS
ev3.LCX(br) # BRAKE
])
self.send_direct_cmd(ops)
我们需要三个属性:
@property
def polarity(self):
return self._polarity
@polarity.setter
def polarity(self, value: int):
assert isinstance(value, int), "polarity needs to be of type int"
assert value in [1, -1], "allowed polarity values are: -1 or 1"
self._polarity = value
@property
def port_right(self):
return self._port_right
@port_right.setter
def port_right(self, value: int):
assert isinstance(value, int), "port needs to be of type int"
assert value in [ev3.PORT_A, ev3.PORT_B, ev3.PORT_C, ev3.PORT_D], "value is not an allowed port"
self._port_right = value
@property
def port_left(self):
return self._port_left
@port_left.setter
def port_left(self, value: int):
assert isinstance(value, int), "port needs to be of type int"
assert value in [ev3.PORT_A, ev3.PORT_B, ev3.PORT_C, ev3.PORT_D], "value is not an allowed port"
self._port_left = value
就是这样,我们有了一个新类 TwoWheelVehicle
,它具有这样的 API:
Help on module ev3_vehicle:
NAME
ev3_vehicle - EV3 vehicle
CLASSES
ev3.EV3(builtins.object)
TwoWheelVehicle
class TwoWheelVehicle(ev3.EV3)
| ev3.EV3 vehicle with two drived Wheels
|
| Method resolution order:
| TwoWheelVehicle
| ev3.EV3
| builtins.object
|
| Methods defined here:
|
| __init__(self, protocol:str=None, host:str=None, ev3_obj:ev3.EV3=None)
| Establish a connection to a LEGO EV3 device
|
| Keyword Arguments (either protocol and host or ev3_obj):
| protocol
| BLUETOOTH == 'Bluetooth'
| USB == 'Usb'
| WIFI == 'Wifi'
| host: mac-address of the LEGO EV3 (f.i. '00:16:53:42:2B:99')
| ev3_obj: an existing EV3 object (its connections will be used)
|
| move(self, speed:int, turn:int) -> None
| Start unlimited movement of the vehicle
|
| Arguments:
| speed: speed in percent [-100 - 100]
| > 0: forward
| < 0: backward
| turn: type of turn [-200 - 200]
| -200: circle right on place
| -100: turn right with unmoved right wheel
| 0 : straight
| 100: turn left with unmoved left wheel
| 200: circle left on place
|
| stop(self, brake:bool=False) -> None
| Stop movement of the vehicle
|
| Arguments:
| brake: flag if activating brake
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| polarity
| polarity of motor rotation (values: -1, 1, default: 1)
|
| port_left
| port of left wheel (default: PORT_D)
|
| port_right
| port of right wheel (default: PORT_A)
|
| ----------------------------------------------------------------------
| Methods inherited from ev3.EV3:
|
| __del__(self)
| closes the connection to the LEGO EV3
|
| send_direct_cmd(self, ops:bytes, local_mem:int=0, global_mem:int=0) -> bytes
| Send a direct command to the LEGO EV3
|
| Arguments:
| ops: holds netto data only (operations), the following fields are added:
| length: 2 bytes, little endian
| counter: 2 bytes, little endian
| type: 1 byte, DIRECT_COMMAND_REPLY or DIRECT_COMMAND_NO_REPLY
| header: 2 bytes, holds sizes of local and global memory
|
| Keyword Arguments:
| local_mem: size of the local memory
| global_mem: size of the global memory
|
| Returns:
| sync_mode is STD: reply (if global_mem > 0) or message counter
| sync_mode is ASYNC: message counter
| sync_mode is SYNC: reply of the LEGO EV3
|
| wait_for_reply(self, counter:bytes) -> bytes
| Ask the LEGO EV3 for a reply and wait until it is received
|
| Arguments:
| counter: is the message counter of the corresponding send_direct_cmd
|
| Returns:
| reply to the direct command
|
| ----------------------------------------------------------------------
| Data descriptors inherited from ev3.EV3:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| sync_mode
| sync mode (standard, asynchronous, synchronous)
|
| STD: Use DIRECT_COMMAND_REPLY if global_mem > 0,
| wait for reply if there is one.
| ASYNC: Use DIRECT_COMMAND_REPLY if global_mem > 0,
| never wait for reply (it's the task of the calling program).
| SYNC: Always use DIRECT_COMMAND_REPLY and wait for reply.
|
| The general idea is:
| ASYNC: Interruption or EV3 device queues direct commands,
| control directly comes back.
| SYNC: EV3 device is blocked until direct command is finished,
| control comes back, when direct command is finished.
| STD: NO_REPLY like ASYNC with interruption or EV3 queuing,
| REPLY like SYNC, synchronicity of program and EV3 device.
|
| verbosity
| level of verbosity (prints on stdout).
从现在开始,当我们使用两个驱动车轮移动车辆时,我们将使用 ClassWheelVehicle
。实际上这不仅仅是一个练习,而是一个真实的东西,但下一课,我们将为这个类添加功能。你可能会问,如果努力和利益真的是平衡的话。但是看,我们的程序变短了:
#!/usr/bin/env python3
import curses
import ev3, ev3_vehicle
def react(c):
global speed, turn, my_vehicle
if c in [ord('q'), 27, ord('p')]:
my_vehicle.stop()
return
elif c == curses.KEY_LEFT:
turn += 5
turn = min(turn, 200)
elif c == curses.KEY_RIGHT:
turn -= 5
turn = max(turn, -200)
elif c == curses.KEY_UP:
speed += 5
speed = min(speed, 100)
elif c == curses.KEY_DOWN:
speed -= 5
speed = max(speed, -100)
stdscr.addstr(5, 0, 'speed: {}, turn: {} '.format(speed, turn))
my_vehicle.move(speed, turn)
def main(window)->None:
global stdscr
stdscr = window
stdscr.clear() # print introduction
stdscr.refresh()
stdscr.addstr(0, 0, 'Use Arrows to navigate your EV3-vehicle')
stdscr.addstr(1, 0, 'Pause your vehicle with key <p>')
stdscr.addstr(2, 0, 'Terminate with key <q>')
while True:
c = stdscr.getch()
if c in [ord('q'), 27]:
react(c)
break
elif c in [ord('p'),
curses.KEY_RIGHT, curses.KEY_LEFT, curses.KEY_UP, curses.KEY_DOWN]:
react(c)
speed = 0
turn = 0
my_vehicle = ev3_vehicle.TwoWheelVehicle(protocol=ev3.BLUETOOTH, host='00:16:53:42:2B:99')
stdscr = None
curses.wrapper(main)
如果你下载了 ev3-python3
的模块 ev3_vehicle.py
,你需要以两个额外的参数 radius_wheel
和 tread
调用 TwoWheelVehicle
的构造函数。目前你可以将它们设置为任何正值。
结论
现在我们知道了,如何移动电机,我们获得了两个重要设计概念的经验,即中断和子类化。此外我们编写的东西像个真正的应用程序了,一个车辆的遥控器。
我希望,你的遥控器工作良好,并使你成为一个技术明星。我们即将结束本课程。浏览文档 EV3 Firmware Developer Kit 告诉您,移动电机存在许多额外的操作。其中大多数是为了精确,同步和平滑的运动。这将是我们下一课的主题。我希望能再次见到你。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Paradigms of Artificial Intelligence Programming
Peter Norvig / Morgan Kaufmann / 1991-10-01 / USD 77.95
Paradigms of AI Programming is the first text to teach advanced Common Lisp techniques in the context of building major AI systems. By reconstructing authentic, complex AI programs using state-of-the-......一起来看看 《Paradigms of Artificial Intelligence Programming》 这本书的介绍吧!
HEX HSV 转换工具
HEX HSV 互换工具
HSV CMYK 转换工具
HSV CMYK互换工具