Instituto
Tecnológico de Aeronáutica
Divisão de Ciência da Computação
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
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:
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:
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