вторник, 1 апреля 2008 г.

Проектирование робота. Диаграмма классов

В рамках серии статей «Изготовление аналога марсохода ПрОП-М».

Пора заканчивать проектирование (в общих чертах, поскольку все-таки мы к нему будем возвращаться постоянно). Остался очень важный этап - создание диаграммы классов. Конечно, это будет не полная диаграмма, но от нее мы будем отталкиваться. Диаграмма классов является полной декларативной классовой моделью будущей системы. Реализация проекта скорее всего планируется на C/C++, с точки зрения этих языков диаграмма классов содержит всю информацию, необходимую для создания хедеров проекта: названия классов, связи между ними, декларации методов и свойств каждого из классов. Со смысловым содержанием диаграммы, надеюсь, все теперь понятно. Еще замечу, что эта диаграмма создается с использованием всех созданных до этого диаграмм:

  • Диаграммы прецедентов
  • Диаграммы состояний
  • Диаграммы развертывания

Вкратце пройдусь по процессу проектирования:

Общий принцип - начинаем НЕ снизу!!, а «сверху». А там, наверху, у нас один единственный класс, с одним единственным экземпляром - это сам по себе Robot (буду называть его объект Robot). Само собой, здесь должна быть инициализация и финализация - пусть это будут процедуры Initialize() и Finalize(). Также этот объект (исходя из псевдооднозадачной модели Palm) обязательно должен содержать в себе метод, реализующий главный цикл программы. Так его и назовем: MainLoop(). В этом цикле программа должна опрашивать датчики, управлять моторами, принимать команды управления. Кроме того, одним из важнейших свойств робота будет являться его состояние (свойство State). А любая система, поведение которой основано на принципе перехода между состояниями (механизм конечных автоматов, подробно я описывал их в своей статье «Роботы и искусственный интеллект»), должна содержать метод перехода в следующее состояние, в зависимости от текущего состояния и состояния внешней среды. Назовем этот метод SwitchState().

Для хранения правил перехода между состояниями, сведений о самих состояниях, а также информации о смене состояний (лог) - можно использовать базу данных. Удобно создать интерфейсы к каждой таблице нашей БД в виде отдельной связки класс + коллекция. Таким образом, получаем следующие классы "данных" (исходя из требуемых функций системы):

  1. State + StateCollection - описания состояний (в основном используется только для отображения лога)
  2. ExternalEvent + ExternalEventCollection - описания внешних событий, из-за которых может быть инициирован переход между состояниями.
  3. StateLink + StateLinkCollection - связи между состояниями (правила перехода)
  4. StateChange + StateChangeCollection - лог состояний

Также, очевидно, что все эти классы будут использовать некоторый базовый класс для работы с БД - назовем его DBConnect.

Каждый из перечисленных классов будет содержать свойства, дублирующие поля соответствующей таблицы данных (т.о. класс=строка таблицы). Коллекция будет описывать все строки таблицы. Также, коллекция должна содержать методы для заполнения себя данными из БД, для загрузки этих данных обратно в БД, и для обработки этих данных - например, поиска нужной строки по какому-либо из полей.

Для порядка, все классы для связи с базой данных поместим в отдельный пакет - DB, и проставим связи между классами, вот что получилось у меня:

Кстати, еще одну связку коллекция + класс можно создать для хранения настроек программы, но это необязательно...

В объекте Robot целесообразно разместить экземпляры всех трех описанных коллекций для быстрого доступа к ним.

Как я уже упомянул, объект верхнего уровня Robot взаимодействует в основном с датчиками и двигательной системой. Также необходимо предусмотреть связь с устройством управления (в данном случае под устройством управления я понимаю графический интерфейс Palm-приложения), имеющую право на жизнь ради тонкой быстрой настройки и тестирования.

Таким образом, необходимо создание как минимум трех классов - системы датчиков, двигательной системы, и интерфейсного класса.

Модель взаимодействия с этими классами с точки зрения объекта Robot достаточно примитивна - каждый внешний класс имеет свойство State; Robot вызывает метод Work() каждого из классов, тот по определенным правилам изменяет свое свойство State, и далее Robot использует это свойство как один из факторов, влияющих на изменение его собственного свойства State...

Экземпляры классов объявлены внутри объекта Robot. Нетрудно догадаться, что каждый из описываемых классов использует тот же самый механизм конечных автоматов, и те же самые вспомогательные классы для работы с DB.

Однако, помимо считывания состояний, классами двигательной системы и графического интерфейса можно управлять. Я не буду слишком заострять внимание на графическом интерфейсе, т.к. он по сути дела имеет право на жизнь только в рамках тестирования - а сосредоточусь на двигательной системе.

Согласно требованиям диаграммы прецедентов, двигательная система должна выполнять следующие основные функции (в скобках приведены названия соответствующих методов):

  • Движение на заданное число шагов вперед (GoForward)
  • Движение на заданное число шагов назад (GoBackward)
  • Поворот на заданный угол (Turn)
  • Поворот на заданный угол и движение вперед (TurnAndGoForward)
  • Поворот на заданный угол и движение назад (TurnAndGoBackward)
  • Остановка

Внутри класса двигательной системы есть два объекта класса Motor - и все управление происходит с помощью этих объектов. Они, кстати, тоже имеют собственное состояние (State)... Классы Motor и Sensor оба описывают внешние устройства, поэтому наследуют от абстрактного класса ExternalDevice. Единственным свойством этого класса является ExternalID - идентификатор внешнего устройства, которым управляет конкретный класс. Для реализации связи с последовательным портом имеется еще два класса - высокоуровневый (CommDispatcher) и низкоуровневый (CommDriver).

Итоговая диаграмма:

Пакет RobotMain:

Пакет CommPort:

В общем-то, на этом работа закончена. Осталось лишь упомянуть, что я использовал для разработки диаграммы инструмент Enterprise Architect 7.0 от компании Sparx Systems, и этот неплохой в принципе инструмент (30-тидневная версия доступна бесплатно) позволяет, как, впрочем, и другие среды разработки UML, генерировать заготовку кода согласно представленной диаграммы классов. Получается вот такой симпатичный списочек файлов:

А это, собственно, означает, что скоро, очень скоро, по-тихоньку будет появляться и собственно код!

Продолжение следует...

Комментариев нет:

Отправить комментарий

Внимание! Реклама и прочий спам будут беспощадно удаляться.