Эта заметка была написана в продолжение прошлой записи, посвященной производительности NXT блока. Поскольку в той заметке рассматривался аспект производительности самого блока, то, конечно, хотелось получить также данные, показывающие как производительность зависит от типа датчика, ответственного в тот или иной момент за основную работу робота. |
Итак, сначала надо определиться с методикой определения частоты опроса датчика.
Предлагается такой алгоритм:
- Инициализируем датчик
- Запоминаем текущее значение таймера (или сбрасываем таймер в ноль)
- Делаем N итераций цикла, который делает только одно действие - опрашивает датчик
- После завершения цикла запоминаем новое значение таймера, а точнее на сколько он изменился с шага 2.
Количество итераций будет браться заведомо большое, поскольку на время на одну итерацию может оказаться соизмеримым с временем работы функций засекающих (измеряющих) время, что не позволит определить действительную производительность.
Также нужно выбрать "подопытные" датчики. Имеет смысл посмотреть на три разных: на световой, как представителя аналоговых сенсоров, на датчик расстояния, представителя цифровых устройств, и на енкодеры - датчики встроенные в двигатели и подсчитывающие то, на сколько поворачивается ось двигателя.
Чтобы было, с чем сравнивать, тестирование датчиков производиться в трех средах: NXT-G, NXC и Python.
Что же получилось?
NXT-G
Получились вот такие три программы для замера частоты опроса трех датчиков:
Они выдали вот такие результаты:
датчик | кол-во итераций | время в мс. | итераций в секунду |
---|---|---|---|
световой | 10000 | 5329 | 1876 |
расстояния | 10000 | 7938 | 1259 |
енкодеры | 10000 | 4383 | 2281 |
Все результаты, кроме датчика расстояния, вполне ожидаемые. А вот датчик расстояния повел себя довольно странно. Дело в том, что этот датчик имеет вполне вычисляемую скорость работы, которая ограничена скоростью звука. В прошлый раз (это уже было описано здесь) замеры для среды NXT-G показали, что с ее помощью подготавливается такой байткод, который не может опрашивать датчик быстрее чем 17 раз в секунду. В этот раз измерения показывают, что ничто не мешает опрашивать датчик даже каждую миллисекунду. Отличия от прошлого раза - версия NXT-G и версия FW. Если кто-то еще проведет такой же тест и подтвердит высокую скорость работы, то это будет указывать, что новая версия NXT-G привносит определенные изменения в процесс работы с данным датчиком, что, несомненно, следует учитывать в программах.
NXC
Все три программы строились по одному и тому же шаблону:
task main() {
SetSensorLight(IN_4);
Wait(500);
int tmp;
long strt = CurrentTick();
for(int i=0;i <10000;i++) {
tmp = SensorValue(IN_4);
}
NumOut(12,LCD_LINE4, CurrentTick()-strt);
until(ButtonPressed(BTNCENTER, false) > 0);
}
Естественно, в случае других датчиков инициализация и получение значений выполнялись по другому.Результаты получились следующие:
датчик | кол-во итераций | время в мс. | итераций в секунду |
---|---|---|---|
световой | 10000 | 1123 | 8904 |
расстояния | 1000 | 22013 | 45 |
енкодеры | 10000 | 1108 | 9025 |
Как видно, язык NXC генерирует вполне ожидаемый код - он эффективнее, чем код полученный в среде NXT-G, и логичнее работает с ультразвуковым сенсором.
Единственное, что может заметить пытливый взгляд это расхождение с результатами, декларируемым тестом PerformanceChk2, рассматриваемом в прошлой заметке.
Действительно, автор теста заявлял предельную производительность блока, как 5200 простейших операций в секунду. В результатах теста выше, видно что сенсоры опрашиваются с гораздо большей частотой.
Чтобы разобраться с этим феноменом, давайте сами скомпилируем PerformanceChk2.nxc и запустим его на блоке. Вот, что получается:
int+- | 12406 |
long+- | 14388 |
int * | 11061 |
long * | 12330 |
int / | 11848 |
long / | 13140 |
int << | 3454 |
long << | 3551 |
empty | 7894 |
tick/tacho | 22388 |
arrays | 10960 |
i++ | 25380 |
asm inc | 25380 |
Т.е. получается, что на новом FW производительность блока в целом значительно возросла больше, чем в два раза.
Python
Опять же, все три программы будут во многом идентичны - будут отличаться инициализацией и способом получения данных:
import nxt.locator from nxt.sensor import * from time import clock,sleep ITERATIONS = 1000 b = nxt.locator.find_one_brick() sens = Ultrasonic(b, PORT_4) sleep(0.5) print "US testing..." StartTime = clock() i = 0 while i < ITERATIONS: tmp = sens.get_distance() i = i+1 total = clock()-StartTime print "Time of execution: ",totalРезультаты:
датчик | кол-во итераций | время в мс. | итераций в секунду |
---|---|---|---|
световой | 10000 | 10063 | 993 |
расстояния | 1000 | 9883 | 101 |
енкодеры | 10000 | 10049 | 995 |
Здесь сенсор расстояния работает опять же медленнее, чем остальные. Но гораздо быстрее, чем в NXC. Стоит заглянуть во внутреннюю реализацию класса, чтобы посмотреть не выполняет ли он асинхронные запросы к датчику, используя время от времени закешированное значение. Показания других сенсоров показывают интересную особенность общения программы на Python c NXT блоком - очень похоже на то, что Python не опрашивает блок чаще чем каждую миллисекунду. Т.е. быстрее этого опрашивать датчики никак не получиться. А ваше какое мнение?
Сразу возникает несколько вопросов по методу тестирования:
ОтветитьУдалить- сколько разрядов имеет таймер? Не происходит ли его переполнения во время теста?
- хотелось бы увидеть код NXC именно для теста UltraSonic'а - если не ошибаюсь, то на NXC можно задать различные варианты работы: LowSpeed с I2C-устройствами, работа с RAW или с показаниями датчика и т.д.
- при тестах используется всегда один таймер или разные? В NXT-G и RoboLab можно выбрать один из трех таймеров (что наводит на мысль, что их всего в Mindstorms NXT 3 штуки). Так вот, одинаковые ли они, или разные? У них может быть разная разрядность, некоторые из них может быть нельзя использовать одновременно с ШИМ-ом (который используется для управления двигателями).
Разрядность таймеров - скорее всего 32, так как в справке к NXT-G указан диапазон значений, генерируемый блоком 0...4294967296, то есть 2 в 32 степени. Вопрос с переполнением отпадает, так как даже при частоте 32 МГц для переполнения таймера потребуется более 134 секунд.
Удалить1. для US датчика я использую получение калиброванных (scaled) значений через SensorUS(). Программу посмотреть здесь: http://pastebin.com/dEK250TJ
Удалить2. Скриншотах NXT-G программ видно, что таймеры одни и те же.