Арбитр ресурсов
Описывается реализация переключения походок, которая включает два элемента: арбитр и клиентская подсистема задатчика. Обмен осуществляется при помощи портов и сообщений, описанных ранее в переключении задатчиков. Выбрана максимально асинхронная схема обмена, чтобы не блокировать компонент задатчика.
Варианты реализации клиентской части:
1. Наследник TaskContext, от которого наследуются все компоненты-задатчики. (Статическое связывание).
2. Компонент, куда пользовательский код загружается как плагин.
(Неудобно из-за отсутствия полного доступа к кода задатчика к компоненту, весь интерфейс задатчика окажется в пространстве имен сервиса).
3. Клиентская часть является сервисом. (Динамическое связывание, удобно для тестирования задатчика отдельно, но сложности с взаимодействием).
Далее рассматривается клиентская часть-сервис, остальные реализуются аналогично.
Для взаимодействие используется интегральный тип данных ResourceList:
Клиентская часть: сервис ResourseСlient
Внешний интерфейс (связь с арбитром):
Выходные порты:
resource_request(ResourseRequest) --- запросы ресурсов к арбитру (вариант только с портами)resource_requester_status(ResourseRequesterStatus) --- изменение состояния компонента после перераспределения ресурсов или при деактивации.
Входные порты:
resource_assigment(ResourseAssigment) --- ресурсов по компонентам.
Операции:
Внимание! В соответствие с соглашениями надо удалить из внешнего интерфейса не предназначенные для использования другими компонентами операции. Их метка "Предоставляет" заменена на "Метод" или "Предоставляет (удалить)".
Внутренний интерфейс (связь с кодом задатчика):
- Метод:
uint32 requestResources(strings req [, ints pri1, ints pri2] )--- изменить состав ресурсов, формирует запросResourseRequestи отправляет его арбитру, не для внешнего использования. Возвращает идентификатор запроса (request_idсм. в переключение задатчиков) или ноль, если запрос не может быть выполнен (порт не подключен). - Метод:
bool stopOperational()--- уведомить арбитр о деактивации (посылаетResourseRequesterStatus), не для внешнего использования. - Предоставляет:
bool isOperational()--- возвращает true в состояние "opertional" и "operational pending". - Предоставляет:
bool getState()--- возвращает состояние: "non operational", "pending", "opertional", "operational pending" - Предоставляет:
bool hasResource(string res),bool hasResources(strings res) -
Предоставляет:
strings listResources()--- возвращает список ресурсов, которыми владеет компонент. Не РВ. -
Обработка сообщений арбитра
Метод:
void step()--- функция, которая должна периодически вызываться вupdateHook().ИЛИ
Устанавливает callback
processResourceAssigmentна входной портresource_assigment. -
Средства уведомления пользовательского кода о изменении набора ресурсов:
- Требует (опционально, удалить):
bool resourceChangeHook()--- операция компонента-владельца сервиса, используемая как пользовательский callback, вызываемая при изменении состава ресурсов. Пользовательский код возвращаетtrue, если компонент остается активен. - Требует (опционально, удалить):
void stopOperationalHook()--- операция компонента-владельца сервиса, используемая как пользовательский callbcak, вызываемый при переходе в состояние "non opertional". Плагин сам проверяет наличие этих операций в интерфейсе компонента и присоединяется к ним.
ИЛИ
- Метод:
void setResourceChangeHook(boost::function<bool()> resourceChangeHook) - Метод:
void setStopOperationalHook(boost::function<void()> stopOperationalHook)
- Требует (опционально, удалить):
Семантика исполнения
requestResources формирует запрос ResourseRequest и отправляет его арбитру. Эта функция вызывается кодом пользователя после проверки условий активации, сигнализирует о переходе в состояние ожидания активации (pending) из состояний "активен", "не активен". А состояние "pending" игнорируется.
stopOperational сигнализирует о деактивации. Вызывается пользовательским кодом для перехода в состояние "не активен" (конец движения, отмена действия).
step должна вызываться в начале updateHook() для обработки сообщений ResourseAssigment.
Альтернативный вариант c processResourceAssigment предполагает использование EventPort с Callback функцией для вызова обработчика. Для возможности обработки сообщений компонент должен быть запущен, либо обработка сообщений должна быть явно разрешена через dataOnPortHook не только в режиме "запущен".
step разбирает полученный список ресурсов и вызывает пользовательский hookResourceChange, чтобы определить, согласен ли компонент со списком выделенных ресурсов.
Если hookResourceChange не реализован, то проверяет наличие последних запрошенных ресурсов
и на основе этого меняет состояние задатчика и посылается ResourseRequesterStatus.
Диаграмма состояний клиента приведена ниже:

Детали реализации.
Вероятно, набор ресурсов проще всего хранить и передавать в set<string> или map<string>
Пример реализации задатчика:
bool startHook() {
vector<string> res = { "leg1", "tail" };
req resource_client->requestResources(res);
}
bool hookResourceChange() {
return resource_client->hasResource("leg1") && ...
}
void updateHook() {
resource_client->step();
if (sync_port.read(sync_msg, false)) {
if (resource_client->getState() & OPERATIONAL) {
... ref_joints_port.write(ref_joints);
if (resource_client->hasResource("tail") {
...
}
}
else if (resource_client->getState() == NONOPERATIONAL) {
this->stop(); // stop component when it is nonoperational
}
}
}
stopHook() {
resource_client->stopOperational();
}
Серверная часть: компонент resources_arbiter
Компонент регистрирует все задатчики, осуществляет прием извещений о изменении состава ресурсов/активных компонент, осуществляет перераспределение ресурсов.
Входные порты
resource_request(ResourseRequest) --- запросы ресурсов к арбитру (вариант только с портами).resource_requester_status(ResourseRequesterStatus) --- изменение состояния компонента после перераспределения ресурсов или при деактивации.
Выходные порты
resource_assigment(ResourseAssigment) --- ресурсов по компонентам.controllers_state(ControllerState) --- состояние задатчиков.
Операции:
- Предоставляет
resourceRequest(uint32 resourceRequest(ResourseRequest)) --- запросы ресурсов к арбитру, возвращает номер запроса (вариант c операциями)
Параметры
strings list_orocos--- список компонент-задатчиков OROCOS (опционально, чтобы предварительно выделить память под структуры и проверять корректность запросов).strings resources- список ресурсов (опционально, для выделения памяти и проверки корректности запросов).
Операции
assignAllResorsesTo(string component)--- передать все ресурсы заданному компоненту или никому (noone)
Семантика исполнения
Компонент реализует семантику арбитра ресурсов без приоритетов с возвратом владения.
Основной код --- обработка запросов --- содержится в updateHook. Семантика исполнения подробно расписана в переключении задатчиков. Некорректный запрос приводит к ошибке.
Детали реализации
Для контроля раундов испльзуется механизм request_id, генерируемых на стороне клиентов.
Структура харнения информации о задатчиках map<string,ClientInfo>:
state --- состояние (активен, ожидает активации, неактивен),
last_request --- последний запрос, битовый вектор,
request_id,
seq --- номер последнего запроса (номер глабальный).
Структура харнения информации о ресурсах map<string,ResourceInfo>:
index --- индекс ресурса в битовом векторе,
owner --- имя задатчика-владельца или строка none.
Способ хранения оптимизирован под доступ по имени.
Исключения и ошибки
Предупреждения: 1. Некорректное имя компонента в запросе. 1. Некорректное имя ресурса в запросе.