Протокол с гарантией доставки для tr24a

При создании навигационной системы робота для участия в Eurobot 2011 мы решили использовать радио модули tr24. Но при работе с ними выяснилась одна проблема: иногда они теряют передаваемые пакеты. В нашей системе планировалось по радиоканалу передавать управляющие команду, поэтому потеря данных была просто недопустима. В связи с этим мне пришлось разработать протокол общения радио модулей tr24, гарантирующий доставку пакета.

Сначала в вкратце опишу, что собой представляла система. Имелось три периферийных маяка, которые должны были по радиоканалу принимать команды и выполнять некоторый набор действий. Имелся локатор на роботе противника, который должен был по радиоканалу обмениваться данными с локатором на нашем роботе. Оба локатора должны были по очереди слать команды маякам и друг другу. Аппаратно все пять устройств были выполнены идентично. Про схему подключения радио модулей tr24 в этих устройствах можете посмотреть здесь. Подробнее про навигационную систему робота - здесь.

Я решил, что все пять устройств будут работать на одной частоте.

Из всего вышесказанного я пришёл к такой логике работы протокола: взаимодействие между устройствами нужно оформить в виде отношений Master/Slave, каждому устройству нужно присвоить свой уникальный ID, чтобы при приёмке пакета всеми устройствами они могли определять, от кого и кому предназначен пакет. Slave принимает пакет от Master, выполняет команду, содержащуюся в пакете, и шлёт ответ, возможно, с результатами работы. Master, послав команду, ждёт ответа некоторое время, если ответ не пришёл, шлёт её ещё раз. Для наглядности приведу UML диаграмму взаимодействий для Master и Slave.

Все пакеты содержат бит, в котором храниться их порядковый номер(0 или 1). Вначале Master шлёт пакет с номером 0,а Slave ждёт пакет с номером 0. Когда Master получает от Slave подтверждение о выполнение команды, он изменяет номер посылаемого пакета. А когда Slave получает пакет от Master и номер пакета совпадает с ожидаемым номером, он выполняет команду и шлёт ответ. Если Slave получает пакет с неожидаемым номером, он, ничего не выполняя, шлёт ответ.

Приведу формат пакета по байтам.

1. Старт байт

2. Служебный байт, содержащий номер пакеты, тип пакета.

3. Байт, содержащий ID устройства, пославшего пакет.

4. Байт, содержащий ID устройства, которому предназначен пакет.

Байты с информацией.

n. Стоп байт.

Чтобы более детально проработать протокол, я оформил его в виде протокольных конечных автоматов. Один автомат для Master и один для Slave. Приведу UML диаграмму состояний, для них(слева Master, справа Slave).

Проект реализовывался под Atmega32 на C++ для компилятора WinAVR.

Я написал четыре класса: класс для Master VSenderStateMachine, класс для Slave VRecieverStateMachine, класс VAirPacket, инкапсулирующий формат пакета, и класс-адаптер VTR24Adapter для радио модуля tr24. Класс VTR24Adapter реализован как одноэлементное множество(Singleton). Классы VSenderStateMachine, VRecieverStateMachine и VAirPacket являются шаблонными. Перечислю их шаблонные параметры:

dataLength – длина данных в пакете в байтах, не более 59.

Timer – класс таймера, считающий время. Класс должен иметь static метод uint64_t time(), возвращающий текущее время.

ProcessPacket – класс функтор, который будет обрабатывать сообщения. Класс должен реализовывать:

void operator()(const VAirPacket& recievedPacket, VAirPacket& ackPacket) const

recievedPacket – принятый пакет

ackPacket – пакет, который будет отправлен в ответ

Приведу пример использования классов:

Код для Master:

#include "v_system_timer.h"
#include "tr24/v_sender_state_machine.h"
 
int main()
{
    VSenderStateMachine<VSystemTimer, 7> senderMachine;
    VSystemTimer::timer.start();
    uint8_t command[7];
    memset(command, 0, 7);
    command[0] = 44;
    senderMachine.doIteration(command);
    VSystemTimer::timer.stop();
    return 0;
}

Код для Slave:

 
#include "tr24/v_reciever_state_machine.h"
 
class ProcessPacket
{
public:
    inline void operator()(const VAirPacket<7>& recievedPacket, VAirPacket<7>& ackPacket) const
    {
        //Process incoming message
    }
};
 
int main()
{
    VRecieverStateMachine<ProcessPacket, 7> recieverMachine;
    ProcessPacket packetProcessor;
    m_masterRecieverMachine.doIteration(packetProcessor);
    return 0;
}

Код протестирован. Работает отлично, но, к сожалению, дальность не более трёх метров.

Скачать протокол с гарантией доставки для tr24a.

7 Comments

  1. boris:

    Думаю ваши проблемы с дальностью основаны на:
    1. Распространение радиоволн.
    2. Электромагнитная совместимость.

  2. boris:

    У вас модуль TR24A закрыт текстолитом с фольгой, антена смотрит в верх, вам нужно переместить модуль, или подключить антену. Как вариант взять TR24P.

  3. Мы пробовали вообще снимать крышку и подпаивать внешнюю антенну - не помогло. Не знаете код для tr24p после tr24a менять придется?

  4. boris:

    Попробуйте поднять модуль на шлейфе, чтобы он стал вертикально. Посмотрите как стоит модуль у a9d http://www.youtube.com/watch?v=HYnQRP0CEZY По поводу TR24P 99.9% что переписывать ничего ненужно, чипы у модулей одинаковы.

  5. andreykyz:

    А если взять, что-нибудь по мощнее например YS-1100U http://www.kosmodrom.com.ua/data/YS-1100U.pdf

  6. Delphi:

    Мощнее взять - не проблема, но у нас ограничение по габаритам, в статье про систему навигации можно увидеть, сколько места отведено под радиомодуль. Мы перешли на RFM12B и сделали, что планировали на них. Скоро ждите новую статью.

  7. Delphi:

    YS-1100U - классная штука. Думаю, надежный модуль, поставлю такой в следующую свою разработку.

Leave a Reply

You must be logged in to post a comment.