Традиционно изучение программирования Lego-роботов начинается с простых экспериментов с движением - именно эта функция в роботах используется чаще всего. |
Чтобы узнать, какие функции модуля nxt-python нужно использовать, чтобы заставить робота двигаться, можно использовать два способа. В одном случае, можно воспользоваться свойством открытости - языки с открытым исходным кодом тем и хороши, что позволяют зайти в любой модуль, любую функцию и посмотреть для чего она нужна и что она делает. Другой способ, воспользоваться встроенной в Python функцией подсказки - например, через терминал, предоставляющий доступ к командной строке в Linux:
$ python Python 2.7.2 (default, Oct 27 2011, 01:36:46) [GCC 4.6.1 20111003 (Red Hat 4.6.1-10)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import nxt.motor >>> help(nxt.motor)Итак, что можно почерпнуть из этих источников?
Например, можно увидеть - прежде, чем осуществлять передвижение робота, загружаются внутренний модуль
motor
. Фактически, в коде это будет выглядеть, как import nxt.motorили
from nxt.motor import *Данный модуль предоставляет несколько классов для работы с моторами и соответствующими методами.
Так для работы с одним мотором можно воспользоваться классом
Motor
. Тогда прежде, чем отдавать команды мотору, нужно создать экземпляр этого класса и связать его с нужным мотором.engine = Motor(mybrick, PORT_A)Здесь,
engine | Имя переменной, которая будет ссылаться на объект связанный с мотором |
mybrick | Переменная указывающая на объект, отвечающий за NXT блок, к которому присоединен мотор. Как инициализировать NXT блок написано в этой заметке. |
PORT_A | Константа, определяющая к какому порту подключен мотор. |
Тогда для работы с мотором доступны следующие методы:
engine.turn(80, 720)
В данном примере ось мотора повернется на 720 градусов со мощностью 80. Мощность можно задавать отрицательными числами, если необходимо вращать мотор в противоположную сторону -
engine.turn(-100, 1080)
. Также можно указать третий параметр, который позволит не тормозить мотор при достижении нужного количества градусов, а просто отключить от него напряжение: engine.turn(50, 90, False)
- тогда мотор по инерции еще будет продолжать вращаться.engine.run(90)
или engine.run(-60)
Этот метод включит данный мотор с указанной мощностью и передаст управление следующей команде в программе. Чтобы после этого, при наступлении какого-то события, остановить мотор - нужно использовать методы:
engine.idle()
или engine.brake()
. brake
- резкое торможение, а idle
просто отключает подачу питания.engine.get_tacho()
Позволяет узнать текущие показатели енкодера двигателя. Лучше всего работу этого метода и другого, но с ним связанного, -
reset_position
, рассмотреть на примере. После текста программы этого примера будет приведено, то, что программа выводит на экран.#!/usr/bin/env python import nxt.locator from nxt.motor import * from time import sleep def output_tacho(motor): tacho=motor.get_tacho() print "Tacho Count:\t\t", tacho.tacho_count print "Block Tacho Count:\t", tacho.block_tacho_count print "Rotation Count:\t\t", tacho.rotation_count def do_step(motor): motor.run() sleep(.5) motor.brake() b = nxt.locator.find_one_brick() back = Motor(b, PORT_A) # Assuming that the NXT block just turned on # and counters are zero print "Before motor starts" output_tacho(back) do_step(back) print "1st step finished" output_tacho(back) back.reset_position(False) print "Here reset_position called with False" do_step(back) print "2nd step finished" output_tacho(back) back.reset_position(True) print "Here reset_position called with True" do_step(back) print "3rd step finished" output_tacho(back) sleep(.5) back.idle()Программа трижды запускает мотор, и в последние два запуска перед включением моторов сбрасываются показатели енкодера. Какой конкретно из показателей сбрасывается определяется флагом, передаваемым в
reset_position
.Before motor starts Tacho Count: 0 Block Tacho Count: 0 Rotation Count: 0 1st step finished Tacho Count: 342 Block Tacho Count: 342 Rotation Count: 342 Here reset_position called with False 2nd step finished Tacho Count: 746 Block Tacho Count: 746 Rotation Count: 399 Here reset_position called with True 3rd step finished Tacho Count: 1148 Block Tacho Count: 397 Rotation Count: 801Видно, что вызов функции сброса никак не влияет на показатель Tacho Count - он показывает абсолютную позицию мотора после активации NXT блока.
Запуск функции с параметром
False
, скорее всего, нужно делать в начале каждой программы - это позволит отсчитывать относительную позицию двигателя Rotation Count с начала работы программы.Ну и наконец, внутри циклов, других методов или функций имеет смысл выставлять параметр в
True
при использовании reset_position
- при этом относительная позиция программы сохраниться, а относительная позиция внутри данного блока Block Tacho Count может быть использована для навигации.Работа сразу с двумя моторами, синхронизированными друг с другом, несколько сложнее. За нее отвечает класс
SynchronizedMotors
. Дело в том, что как распределяется мощность между моторами задается при инициализации класса:left_engine = Motor(mybrick, PORT_B) right_engine = Motor(mybrick, PORT_C) vehicle = SynchronizedMotors(left_engine, right_engine, 0)Иными словами, сначала нужно проинициализировать каждый мотор, а потом связать их вместе. Последний параметр "0" как раз и задает распределение мощности. В примере выше, "0" означает, что на оба мотора будет подаваться одинаковая скорость.
Если потом в программе возникнет необходимость поменять распределение, то нужно будет объект заново инициализировать:
vehicle = SynchronizedMotors(left_engine, right_engine, -70)Результирующая программа будет выглядеть, например, так:
#!/usr/bin/env python import nxt.locator from nxt.motor import * from time import sleep mybrick = nxt.locator.find_one_brick() left_engine = Motor(mybrick, PORT_B) right_engine = Motor(mybrick, PORT_C) vehicle = SynchronizedMotors(left_engine, right_engine, 0) vehicle.turn(100, 180) sleep(.5) vehicle.turn(-100, 180) vehicle = SynchronizedMotors(left_engine, right_engine, 25) vehicle.turn(100, 90) sleep(.5) vehicle.turn(-100, 90) sleep(.5) vehicle.idle()Как видно, при синхронизированный моторах используются все те же самые методы, что и для одиночного мотора:
turn
- повернуть моторы на определенное количество градусовrun
- включить моторы с определенной базовой мощностью и передать управление следующей командеbrake
- затормозитьidle
- отключить питание
В завершение, хочется обратить внимание на одну важную деталь -
brake
/торможение все время держит моторы под нагрузкой, чтобы обеспечить их неподвижность. Это будет продолжаться даже если программа закончила свое выполнение. Именно поэтому в примерах выше перед концом каждого скрипта выполняется idle
- это не только поможет руками крутить моторы, например, чтобы поставить их в какое-то начальное положение, но и будет экономить разряд батареи - энергия на моторы перестанет подаваться.
Комментариев нет:
Отправить комментарий