Instituto Tecnológico de Aeronáutica

Divisão de Ciência da Computação

## CE-235

Sistemas Embarcados de Tempo Real

Prof. Dr. Adilson M. Cunha

Exame ### Projeto Final – Protótipo de Veículo Autônomo - PVA

Aluno: Walter Abrahão dos Santos

walter@dss.inpe.br

29 de Novembro-2004

I . Introdução

1.1 Motivação

Visando proporcionar uma experiência hands-on em Sistemas Embarcados de Tempo Real busca-se projetar e prototipar um veículo autônomo - PVA (Protótipo de Veículo Autônomo) - capaz de realizar missões pré-programadas dentro de um ambiente pré-definido. O sistema de hardware do PVA já estava disponível faltando apenas o software de Tempo Real a ser embarcado. Sistemas AGV (Autonomous Guided Vehicle) semelhantes estão disponíveis na web vide [AGV04], por exemplo, para detalhes.

Com este objetivo em mente, motiva-se atingir os seguintes pontos:

- Utilização de uma ferramenta I-CASE-E (Integrated CASE Environment),
- Familiarização com modelagem UML para RT, e
- Familiarização com a abstração de tratamento de sistemas RT feita pelo Rose RT.

A principal necessidade apresentada é a familiarização com a utilização de um I-CASE-E como Rose RT que é um ambiente de desenvolvimento de software adaptado para os requisitos de software de Tempo Real.

O Rose RT lida com todos os estágios de um projeto de sistemas, a saber, desde a modelagem UML de sistemas embarcados de Tempo Real até a geração de código, compilação e debug da aplicação final.

1.2 Contexto

O PVA irá receber uma missão via interface wireless ao MCM (Módulo Central de Monitoramento) através de um protocolo pré-definido. Missões podem ser carregadas e enfileiradas numa fila de missões para serem tratadas posteriormente.

O PVA possui como atuadores dois motores (direito e esquerdo) para se locomover e dispõe de um sensor de proximidade para acusar obstáculos, um sensor de Way-point para detectar pontos chaves na missão (carga, descarga) e de dois sensores de rota (direito e esquerdo) para auxílio à navegação e correção de rota.

Ao receber uma missão, o PVA se dirige ao ponto de carga onde um dispositivo carregador realiza a carga de um objeto que deverá ser entregue a um ponto único de descarga.

Regularmente, o PVA envia status para o MCM informando dados referentes a seu estado interno, obstáculos e missão. Na presença de um obstáculo, o PVA notifica o MCM e aguarda sinalização do mesmo para a remoção do obstáculo e retomada da missão.

1.3 Objetivação do Protótipo de Sistemas de Software

O objetivo primordial do PVA é diminuir custos de deslocamento de cargas de um ponto de carga para um ponto de descarga dentro de um ambiente típico de um almoxarifado de cargas.

1.4 Redução do Escopo

Para fins de praticidade serão assumidas as seguintes simplificações:

- O PVA deverá ter um buffer limitado de missões;
- Obstáculos presentes na rota do PVA serão removidos mediante notificação ao MCM;
- O PVA não dispõe de freios, pois para frenagem simplesmente remove potência de seus motores;
- O PVA possui uma interface dedicada para comunicação wireless com o MCM e recebe apenas uma cadeia de caracteres como status;
- Para navegação será adotada uma fita com fundo de contraste para sinalização;
- O carregador lidará com detalhes de carga de objetos no PVA;

1.5 Especificação de Requisitos

A seguir é descrita e refinada a especificação de requisitos do PSVA (Protótipo de Sistema de Veículo Autônomo).

O PSVA deverá ser capaz de propiciar:

1.5.1 A recepção de sinais de localização do tipo lat/long via um GPS embarcado.

1.5.2 A transmissão para o MCM, em Tempo Real (t <= 3´´), de sinais de status (localização, estado interno de sensores e atuadores, informações sobre a missão, etc).

1.5.3 A recepção de informações do MCM sobre missões atribuídas ao PVA, tipicamente ponto de carga em termos de lat/long.

1.5.4 O controle de navegação do PVA em Tempo Real (t <= 1´´).

1.6 Ordem de Apresentação do Projeto Final

1.6.1 Na Seção 1 (Introdução), apresenta-se a Motivação, o Contexto, Objetivação do Protótipo de Sistemas de Software, a Redução do Escopo e a Especificação de Requisitos deste Projeto Final.

1.6.2 Na Seção 2 (Desenvolvimento) descreve-se a Linha Base Funcional e a Linha Base Alocada dentro de cada fase do RUP (Rational Unified Process).

1.6.3 Na Seção 3 (Conclusões e Recomendações), são sintetizadas as principais conclusões, recomendações e sugestões para aperfeiçoamento deste Protótipo e para a melhoria dessa matéria.

1.6.4 Finalmente, são inclusas as referências bibliográficas e anexos.

II. Desenvolvimento

Para cada Fase do RUP, será reportada a consolidação do material que foi produzido, na Linha Base Funcional e na Linha Base Alocada. Para detalhes sobre os artefatos produzidos vide os portais de documentação do projeto [Dos-Santos04] e [Martins04].

2.1 Linha Base Funcional

A Linha Base Funcional enfoca a 1ª Fase de Iniciação (Inception) do RUP onde foi gerada uma série de artefatos dentre eles os seguintes: Lista de Riscos e Glossário.

A Lista de Riscos assinala os riscos identificados para o PSVA, classificando a importância associada a ações específicas de contingência ou diminuição desses riscos. Os principais riscos identificados foram: (a) Não Cumprimento de Prazos, (b) Inexperiência de Integrantes da Equipe, (c) Atraso na Obtenção de Recursos, (d) Utilização do Processo Unificado Rational (RUP), (e) Falha na especificação de requisitos, (f) Falha na escolha da tecnologia a ser utilizada, (g) Alteração na equipe de desenvolvimento. Dentre os riscos citados alguns não foram aplicáveis devido ao caráter acadêmico do projeto, a saber: atraso na Obtenção de Recursos e falha na escolha da tecnologia a ser utilizada.

O Glossário define a terminologia específica do domínio do problema, explicando termos, que poderão ser desconhecidos para os envolvidos no PSVA. Ele é expandido durante todo o ciclo de vida do projeto. Como o escopo do projeto do PSVA foi limitado para o cumprimento mínimo de requisitos do curso isto se refletiu no número de palavras chaves constantes no glossário.

2.2 Linha Base Alocada

A Linha Base Alocada enfoca a 2ª Fase – Elaboração (Elaboration) do RUP onde foram desenvolvidos artefatos das diversas visões do projeto do PSVA, da visão de Casos de Uso até a visão de Deployment.

Inicialmente serão apresentados os diagramas de visão para o PSVA (Diagrama de Casos de Uso) e então será enfocado o Caso de Uso “VerificarObstáculo” e seus diagramas detalhados (Diagrama de Seqüência, Diagrama de Transição de Estados, Diagrama de Classes).

Figura 1 – Caso de Uso para PSVA.

Figura 2 – Diagrama de Classes com ênfase à cápsula “VerificarObstaculo”.

Figura 3 – Diagrama de Seqüência para cápsula “VerificarObstaculo”.

Figura 4 - Diagrama de Transição de Estados para cápsula “VerificarObstaculo”.

Para documentação de requisitos relativos ao Caso de Uso “VerificarObstaculo” foi empregada a própria ferramenta de modelagem Rose RT, vide a Fig. 5 para detalhes dos requisitos funcionais e suplementares.

1. DESCRIÇÃO Este Caso de Uso ocorre durante a execução de missões no qual o PVA necessita constantemente verificar a existência de obstáculos a sua frente. Caso seja detectado, via o Sensor de Proximidade, a presença de algum objeto na frente do PVA, é enviado um comando de parada ao PVA seguido de um comunicado do incidente ao MCM. O veículo só retomará a missão com a desobstrução de seu caminho que é percebida pelo mesmo sensor. 2. FLUXO DE EVENTOS 2.1 FLUXO BÁSICO 2.1.1 Sensor de proximidade não detecta obstáculo 2.1.2 Missão é concluída. 2.2 FLUXOS ALTERNATIVOS Cenário1: Sensor de proximidade operacional 2.1.1 O sensor de proximidade detecta um obstáculo 2.1.2 PVA lê sensor e acusa obstáculo 2.1.3 PVA informa presença de obstáculo ao MCM 2.1.4 MCM remove obstáculo e sinaliza desobstrução 2.1.5 Sensor de proximidade detecta desobstrução 2.1.6 PVA retoma missão Cenário 2: Sensor de proximidade não-operacional (defeituoso em modo obstruído ou em modo desobstruído) Obs: Este fluxo alternativo não foi analisado. 3. REQUISITOS ESPECIAIS Sensor de proximidade operacional (não defeituoso) 4. PRÉ-CONDIÇÕES 4.1 PVA possui uma missão em execução. 4.2 Autoteste de sensor e de leitor concluídos 4.3 Leitor inicializado 4.4 Sensor de proximidade detecta obstáculo. 5. PÓS-CONDIÇÕES Sensor de proximidade acusa desobstrução. PVA retoma missão. 6. PONTOS DE EXTENSÃO Nenhum.

Figura 5 – Requisitos funcionais e suplementares para o Caso de Uso “VerificarObstáculo”.

A partir do Diagrama de Classes, foi feita a geração automática pela ferramenta Rose RT de código seguindo a implementação dos métodos gerados e da compilação das classes. Para detalhes reportar ao Anexo A.

Para verificação da coesão entre os artefatos gerados pelo sistema, foco da 3ª Fase – Construção (Construction) do RUP, lança-se mão do diagrama de colaboração entre as diversas classes geradas pelo Rose RT com ilustrado a seguir.

Figura 6 – Diagrama de Colaboração para verificação de coesão entre artefatos do PSVA.

III. Conclusões e Recomendações

3.1 Conclusões

A metodologia hands-on adotada pelo curso CE-235 (Sistemas Embarcados de Tempo Real) foi efetiva com relação aos seus propósitos, pois levou os estudantes a percorrerem todas as fases do RUP (Iniciação, Elaboração, Construção e Transição) focadas no projeto e prototipação do software embarcado de Tempo Real do SPVA, o estudo de caso considerado neste trabalho.

Para tanto foram atingidos os seguintes sub-objetivos: Utilização de uma ferramenta I-CASE-E, Familiarização com modelagem UML para Tempo Real, e Familiarização com a abstração de tratamento de sistemas Tempo Real feita pelo Rose RT empregado pelo grupo de estudantes.

A exposição ao I-CASE-E da Rose RT foi valiosa, pois conduz o estudante, a partir da modelagem UML em Tempo Real, até a geração de código, compilação e debug da aplicação final. A ferramenta trabalha com uma cadência de visões (Visão de Caso de Uso, Visão Lógica, Visão de Componentes e Visão de Deployment) para obter um produto final. Adicionalmente, uma suite de ferramentas da Rational (Rational Suite DevelopmentStudio Real Time) está disponível e suporta todos as etapas de ciclo de vida de um projeto de software.

3.2 Recomendações

Para fins de continuidade e aperfeiçoamento do projeto, são recomendados os seguintes pontos:

· Aprofundamento no domínio do problema - para a construção de sistemas embarcados de tempo real efetivos será necessário uma estreita correlação entre o software e o hardware a ser comandado, neste sentido uma maior exposição a exemplos e/ou experiências de sistemas legados dentro do domínio do problema é um fator positivo. Algumas dessas experiências podem ser obtidas

· Aprofundamento na modelagem UML do sistema de software de tempo real – a referência [Lee01] cita o exemplo de modelagem de um simples forno de microondas a partir de três soluções incrementais que refletem indiretamente a experiência do time de desenvolvedores com relação à modelagem do problema. O conhecimento de uma boa metodologia de modelagem também será um fator a ser considerado e irá refletir na qualidade do código gerado.

· Familiarização com o ambiente I-CASE-E – Para exemplificar, a ferramenta Rose RT apresenta uma série de tutoriais. Dentre eles o “Coffee Machine” é um exemplo que deve ser estudado por abordar uma aplicação em tempo real onde todas as abstrações com relação a cápsulas e protocolos são exercitadas. Para maior conhecimento das características de modelagem do Rose RT será sugerido a referência [Rose03]

· Familiarização com Sistemas Operacionais para Tempo Real – foi notado que algumas dúvidas durante a modelagem recaiam sobre tarefas básicas do sistema operacional subjacente (escalonamento, interrupções, etc). Um bom conhecimento sobre tais aspectos poderá ajudar a separar responsabilidades do sistema operacional e dos aplicativos que se servem deste. Para maior detalhes vide [Shaw03]

Referências Bibliográficas

[AGV04] http://summitraj.tripod.com/agv/ - visitada em Agosto/2004.

[Dos-Santos04] http://geocities.yahoo.com.br/walterabrahao2004/ - visitada em Novembro/2004.

[Lee01] Lee, R.C. & Tepfenhardt, W.M – UML and C++ - A Practical Guide to Object-Oriented Development , 2nd Edition, Prentice Hall, Upper Saddle River, 2001.

[Martins04] http://www.comp.ita.br/~osvandre/atividades/ce235/ce235.html - visitada em Novembro/2004.

[Rose03] Rational Software Corporation – Modeling Language Guide, Version 2003.06.00

[Shaw03] Shaw, A.C. – Sistemas e Software de Tempo Real – Bookman, São Paulo, 2003.

Anexo A

Código-fonte obtido através da geração automática de código, seguindo a implementação dos métodos gerados e da compilação das classes.

Código-fonte para VerificarObstaculo.cpp

// {{{RME classifier 'Logical View::XCapsulas::VerificarObstaculo'

#if defined( PRAGMA ) && ! defined( PRAGMA_IMPLEMENTED )

#pragma implementation "VerificarObstaculo.h"

#endif

#include <RTSystem/VerificarObstaculo.h>

#include <VerificarObstaculo.h>

// {{{RME tool 'OT::Cpp' property 'ImplementationPreface'

// {{{USR

// }}}USR

// }}}RME

static const RTRelayDescriptor rtg_relays[] =

{

{

"PortSensProx"

, &CommHwSensorProximidade::Conjugate::rt_class

, 1 // cardinality

}

, {

"PortExec"

, &CommExec_SenProx::Base::rt_class

, 1 // cardinality

}

};

static RTActor * new_VerificarObstaculo_Actor( RTController * _rts, RTActorRef * _ref )

{

return new VerificarObstaculo_Actor( _rts, _ref );

}

const RTActorClass VerificarObstaculo =

{

(const RTActorClass *)0

, "VerificarObstaculo"

, (RTVersionId)0

, 2

, rtg_relays

, new_VerificarObstaculo_Actor

};

static const char * const rtg_state_names[] =

{

"TOP"

, "Desobstruido"

, "Obstruido"

};

#define SUPER RTActor

VerificarObstaculo_Actor::VerificarObstaculo_Actor( RTController * rtg_rts, RTActorRef * rtg_ref )

: RTActor( rtg_rts, rtg_ref )

{

}

VerificarObstaculo_Actor::~VerificarObstaculo_Actor( void )

{

}

// {{{RME operation 'LerSensor()'

bool VerificarObstaculo_Actor::LerSensor( void )

{

// {{{USR

return(1);

// }}}USR

}

// }}}RME

// {{{RME operation 'InformarStatus()'

bool VerificarObstaculo_Actor::InformarStatus( void )

{

// {{{USR

return(1);

// }}}USR

}

// }}}RME

// {{{RME operation 'Inicializar()'

void VerificarObstaculo_Actor::Inicializar( void )

{

// {{{USR

// }}}USR

}

// }}}RME

int VerificarObstaculo_Actor::_followInV( RTBindingEnd & rtg_end, int rtg_portId, int rtg_repIndex )

{

switch( rtg_portId )

{

case 0:

// PortSensProx

if( rtg_repIndex < 1 )

{

rtg_end.port = &PortSensProx;

rtg_end.index = rtg_repIndex;

return 1;

}

break;

case 1:

// PortExec

if( rtg_repIndex < 1 )

{

rtg_end.port = &PortExec;

rtg_end.index = rtg_repIndex;

return 1;

}

break;

default:

break;

}

return RTActor::_followInV( rtg_end, rtg_portId, rtg_repIndex );

}

INLINE_CHAINS void VerificarObstaculo_Actor::chain5_Initial( void )

{

// transition ':TOP:Initial:Initial'

rtgChainBegin( 1, "Initial" );

rtgTransitionBegin();

rtgTransitionEnd();

enterState( 2 );

}

void VerificarObstaculo_Actor::rtsBehavior( int signalIndex, int portIndex )

{

for( int stateIndex = getCurrentState(); ; stateIndex = rtg_parent_state[ stateIndex - 1 ] )

switch( stateIndex )

{

case 1:

// {{{RME state ':TOP'

switch( portIndex )

{

case 0:

switch( signalIndex )

{

case 1:

chain5_Initial();

return;

default:

break;

}

break;

default:

break;

}

unexpectedMessage();

return;

// }}}RME

case 2:

// {{{RME state ':TOP:Desobstruido'

switch( portIndex )

{

case 0:

switch( signalIndex )

{

case 1:

return;

default:

break;

}

break;

default:

break;

}

break;

// }}}RME

case 3:

// {{{RME state ':TOP:Obstruido'

switch( portIndex )

{

case 0:

switch( signalIndex )

{

case 1:

return;

default:

break;

}

break;

default:

break;

}

break;

// }}}RME

default:

unexpectedState();

return;

}

}

const RTActor_class * VerificarObstaculo_Actor::getActorData( void ) const

{

return &VerificarObstaculo_Actor::rtg_class;

}

const RTActor_class VerificarObstaculo_Actor::rtg_class =

{

(const RTActor_class *)0

, rtg_state_names

, 3

, VerificarObstaculo_Actor::rtg_parent_state

, &VerificarObstaculo

, 0

, (const RTComponentDescriptor *)0

, 3

, VerificarObstaculo_Actor::rtg_ports

, 0

, (const RTLocalBindingDescriptor *)0

, 1

, VerificarObstaculo_Actor::rtg_VerificarObstaculo_fields

};

const RTStateId VerificarObstaculo_Actor::rtg_parent_state[] =

{

0

, 1

, 1

};

const RTPortDescriptor VerificarObstaculo_Actor::rtg_ports[] =

{

{

"PortSensProx"

, (const char *)0

, &CommHwSensorProximidade::Conjugate::rt_class

, RTOffsetOf( VerificarObstaculo_Actor, VerificarObstaculo_Actor::PortSensProx )

, 1 // cardinality

, 1

, RTPortDescriptor::KindWired + RTPortDescriptor::NotificationDisabled + RTPortDescriptor::RegisterNotPermitted + RTPortDescriptor::VisibilityPublic

}

, {

"PortTempo"

, (const char *)0

, &Timing::Base::rt_class

, RTOffsetOf( VerificarObstaculo_Actor, VerificarObstaculo_Actor::PortTempo )

, 1 // cardinality

, 2

, RTPortDescriptor::KindSpecial + RTPortDescriptor::NotificationDisabled + RTPortDescriptor::RegisterNotPermitted + RTPortDescriptor::VisibilityProtected

}

, {

"PortExec"

, (const char *)0

, &CommExec_SenProx::Base::rt_class

, RTOffsetOf( VerificarObstaculo_Actor, VerificarObstaculo_Actor::PortExec )

, 1 // cardinality

, 3

, RTPortDescriptor::KindWired + RTPortDescriptor::NotificationDisabled + RTPortDescriptor::RegisterNotPermitted + RTPortDescriptor::VisibilityPublic

}

};

const RTFieldDescriptor VerificarObstaculo_Actor::rtg_VerificarObstaculo_fields[] =

{

// {{{RME classAttribute 'Obstruido'

{

"Obstruido"

, RTOffsetOf( VerificarObstaculo_Actor, Obstruido )

// {{{RME tool 'OT::CppTargetRTS' property 'TypeDescriptor'

, &RTType_bool

// }}}RME

// {{{RME tool 'OT::CppTargetRTS' property 'GenerateTypeModifier'

, (const RTTypeModifier *)0

// }}}RME

}

// }}}RME

};

#undef SUPER

// {{{RME tool 'OT::Cpp' property 'ImplementationEnding'

// {{{USR

// }}}USR

// }}}RME

// }}}RME

Código-fonte para CommHwSensorProximidade.cpp

// {{{RME classifier 'Logical View::InterfacesHw::CommHwSensorProximidade'

#if defined( PRAGMA ) && ! defined( PRAGMA_IMPLEMENTED )

#pragma implementation "CommHwSensorProximidade.h"

#endif

#include <RTSystem/VerificarObstaculo.h>

#include <CommHwSensorProximidade.h>

const RTProtocolDescriptor CommHwSensorProximidade::Base::rt_class =

{

&RTRootProtocol::rt_class

, &CommHwSensorProximidade::Conjugate::rt_class

, "CommHwSensorProximidade"

, 0

, 3

, CommHwSensorProximidade::Base::rt_signals

#if RTRUNTIMEBC

, &RTProtocolDescriptor::getUnknownGlobalSignal, &RTProtocolDescriptor::getUnknownLocalSignal

#endif

};

const RTSignalDescriptor CommHwSensorProximidade::Base::rt_signals[] =

{

{

"LeituraSensor"

, &RTType_bool

, CommHwSensorProximidade::Base::rti_LeituraSensor

}

, {

"rtBound"

, (const RTObject_class *)0

, CommHwSensorProximidade::Base::rti_rtBound

}

, {

"rtUnbound"

, (const RTObject_class *)0

, CommHwSensorProximidade::Base::rti_rtUnbound

}

};

const RTProtocolDescriptor CommHwSensorProximidade::Conjugate::rt_class =

{

&RTRootProtocol::rt_class

, &CommHwSensorProximidade::Base::rt_class

, "CommHwSensorProximidade"

, 0

, 3

, CommHwSensorProximidade::Conjugate::rt_signals

#if RTRUNTIMEBC

, &RTProtocolDescriptor::getUnknownGlobalSignal, &RTProtocolDescriptor::getUnknownLocalSignal

#endif

};

const RTSignalDescriptor CommHwSensorProximidade::Conjugate::rt_signals[] =

{

{

"PedidoLeitura"

, &RTType_void

, CommHwSensorProximidade::Conjugate::rti_PedidoLeitura

}

, {

"rtBound"

, (const RTObject_class *)0

, CommHwSensorProximidade::Conjugate::rti_rtBound

}

, {

"rtUnbound"

, (const RTObject_class *)0

, CommHwSensorProximidade::Conjugate::rti_rtUnbound

}

};

// }}}RME

Código-fonte para CommExec_SenProx.cpp

// {{{RME classifier 'Logical View::InterfacesHw::CommExec_SenProx'

#if defined( PRAGMA ) && ! defined( PRAGMA_IMPLEMENTED )

#pragma implementation "CommExec_SenProx.h"

#endif

#include <RTSystem/VerificarObstaculo.h>

#include <CommExec_SenProx.h>

const RTProtocolDescriptor CommExec_SenProx::Base::rt_class =

{

&RTRootProtocol::rt_class

, &CommExec_SenProx::Conjugate::rt_class

, "CommExec_SenProx"

, 0

, 3

, CommExec_SenProx::Base::rt_signals

#if RTRUNTIMEBC

, &RTProtocolDescriptor::getUnknownGlobalSignal, &RTProtocolDescriptor::getUnknownLocalSignal

#endif

};

const RTSignalDescriptor CommExec_SenProx::Base::rt_signals[] =

{

{

"StatusSensProx"

, &RTType_bool

, CommExec_SenProx::Base::rti_StatusSensProx

}

, {

"rtBound"

, (const RTObject_class *)0

, CommExec_SenProx::Base::rti_rtBound

}

, {

"rtUnbound"

, (const RTObject_class *)0

, CommExec_SenProx::Base::rti_rtUnbound

}

};

const RTProtocolDescriptor CommExec_SenProx::Conjugate::rt_class =

{

&RTRootProtocol::rt_class

, &CommExec_SenProx::Base::rt_class

, "CommExec_SenProx"

, 0

, 3

, CommExec_SenProx::Conjugate::rt_signals

#if RTRUNTIMEBC

, &RTProtocolDescriptor::getUnknownGlobalSignal, &RTProtocolDescriptor::getUnknownLocalSignal

#endif

};

const RTSignalDescriptor CommExec_SenProx::Conjugate::rt_signals[] =

{

{

"PedidoStatus"

, &RTType_void

, CommExec_SenProx::Conjugate::rti_PedidoStatus

}

, {

"rtBound"

, (const RTObject_class *)0

, CommExec_SenProx::Conjugate::rti_rtBound

}

, {

"rtUnbound"

, (const RTObject_class *)0

, CommExec_SenProx::Conjugate::rti_rtUnbound

}

};

// }}}RME