Dust DDS — это встроенная в Rust реализация служб распределения данных OMG (DDS) и издателя-подписчика в реальном времени (RTPS), разработанная S2E Software Systems.
Цель этого крейта — предоставить высококачественную реализацию минимального профиля DDS на Rust. Под высоким качеством подразумевается, что реализация выполняется с использованием стабильного Rust, без небезопасного кода и с большим покрытием кода модульных тестов.
DDS — это протокол промежуточного программного обеспечения и стандарт API, предназначенный для подключения, ориентированного на данные. По своей сути DDS стремится облегчить беспрепятственный обмен соответствующими данными именно там, где и когда это необходимо, даже между издателями и подписчиками, работающими асинхронно во времени. С помощью DDS приложения могут обмениваться информацией посредством чтения и записи объектов данных, идентифицируемых определяемыми пользователем именами (темами) и ключами. Одной из его определяющих особенностей является надежный контроль над параметрами качества обслуживания (QoS), включая надежность, пропускную способность, сроки доставки и распределение ресурсов.
Стандарт DDS «определяет как интерфейсы приложений (API), так и семантику связи (поведение и качество обслуживания), которые обеспечивают эффективную доставку информации от производителей информации соответствующему потребителю». Дополнением к этому стандарту является спецификация DDSI-RTPS, которая определяет проводной протокол совместимости для DDS. Его основная цель — обеспечить взаимодействие приложений, основанных на реализациях DDS разных производителей. Реализация Dust DDS в первую очередь сосредоточена на стандартах DDS и DDSI-RTPS.
Базовый пример использования Dust DDS. Сторона издателя может быть реализована как:
use dust_dds :: {
domain :: domain_participant_factory :: DomainParticipantFactory ,
infrastructure :: { qos :: QosKind , status :: NO_STATUS } ,
topic_definition :: type_support :: DdsType ,
} ;
# [ derive ( DdsType ) ]
struct HelloWorldType {
# [ dust_dds ( key ) ]
id : u8 ,
msg : String ,
}
let domain_id = 0 ;
let participant_factory = DomainParticipantFactory :: get_instance ( ) ;
let participant = participant_factory
. create_participant ( domain_id , QosKind :: Default , None , NO_STATUS )
. unwrap ( ) ;
let topic = participant
. create_topic :: < HelloWorldType > ( "HelloWorld" , "HelloWorldType" , QosKind :: Default , None , NO_STATUS )
. unwrap ( ) ;
let publisher = participant
. create_publisher ( QosKind :: Default , None , NO_STATUS )
. unwrap ( ) ;
let writer = publisher
. create_datawriter :: < HelloWorldType > ( & topic , QosKind :: Default , None , NO_STATUS )
. unwrap ( ) ;
let hello_world = HelloWorldType {
id : 8 ,
msg : "Hello world!" . to_string ( ) ,
} ;
writer . write ( & hello_world , None ) . unwrap ( ) ;
Абонентская часть может быть реализована как:
use dust_dds :: {
domain :: domain_participant_factory :: DomainParticipantFactory ,
infrastructure :: { qos :: QosKind , status :: NO_STATUS } ,
subscription :: sample_info :: { ANY_INSTANCE_STATE , ANY_SAMPLE_STATE , ANY_VIEW_STATE } ,
topic_definition :: type_support :: DdsType ,
} ;
# [ derive ( Debug , DdsType ) ]
struct HelloWorldType {
# [ dust_dds ( key ) ]
id : u8 ,
msg : String ,
}
let domain_id = 0 ;
let participant_factory = DomainParticipantFactory :: get_instance ( ) ;
let participant = participant_factory
. create_participant ( domain_id , QosKind :: Default , None , NO_STATUS )
. unwrap ( ) ;
let topic = participant
. create_topic :: < HelloWorldType > ( "HelloWorld" , "HelloWorldType" , QosKind :: Default , None , NO_STATUS )
. unwrap ( ) ;
let subscriber = participant
. create_subscriber ( QosKind :: Default , None , NO_STATUS )
. unwrap ( ) ;
let reader = subscriber
. create_datareader :: < HelloWorldType > ( & topic , QosKind :: Default , None , NO_STATUS )
. unwrap ( ) ;
let samples = reader
. read ( 1 , ANY_SAMPLE_STATE , ANY_VIEW_STATE , ANY_INSTANCE_STATE ) ;
if let Ok ( hello_world_samples ) = samples {
println ! ( "Received: {:?}" , hello_world_samples [ 0 ] . data ( ) . unwrap ( ) ) ;
}
Если вы используете только Rust, вы можете использовать процедурные макросы, чтобы включить передачу типа с помощью DustDDS. Ключевые поля также могут быть определены как часть макроса.
use dust_dds :: topic_definition :: type_support :: DdsType ;
# [ derive ( DdsType ) ]
struct HelloWorldType {
# [ dust_dds ( key ) ]
id : u8 ,
msg : String ,
}
Если вы используете разные языки программирования или разных поставщиков, тип DDS можно сгенерировать из IDL-файла OMG с помощью крейта пыли_dds_gen.
Dust DDS предоставляет как «синхронный», так и «асинхронный» API, что позволяет интегрировать DDS в наибольшее количество приложений с максимальной производительностью. В общем, первым вариантом должно быть использование API синхронизации и использование определенных функций DDS, таких как прослушиватели для программ, основанных на событиях.
При реализации приложений, которые уже используют асинхронность, необходимо использовать асинхронный API. В частности, при использовании среды выполнения Tokio использование Sync API приведет к панике из-за блокировки вызовов. Вы можете найти пример в папке примеров.
Если вы хотите взаимодействовать со своими данными DDS с помощью REST API, вы можете использовать наше программное обеспечение Nebula DDS WebLink. Nebula DDS WebLink предоставляет сервер, реализующий стандарт Web-Enabled DDS v1.0 группы управления объектами (OMG).
Совместимость DDS обычно тестируется с использованием демонстрации фигур. Демо-версия Dust DDS Shapes доступна в нашем репозитории, и ее можно запустить, запустив cargo run --package dust_dds_shapes_demo
из корневой папки.
Dust DDS не придерживается фиксированного графика выпусков, но мы будем выпускать выпуски по мере реализации новых функций.
Этот проект распространяется по лицензии Apache версии 2.0.