SOME/IP: protocol that should enable autonomous driving (2024)

10 minute read

Published:

Autonomous driving puts a lot of challanges in front of developers. One of the challanges is an effective communication mechanism between different components of the car. Let’s take a look on the protocol that designed to enable autonomous driving.

What is SOME/IP

SOME/IP is an automotive/embedded communication protocol which supports remote procedure calls, event notifications and the underlying serialization/wire format.

The SOME/IP was design with the purpose:

  • Fulfills the hard requirements regarding resource consumption in an embedded world
  • Is compatible through as many use-cases and communication partners as possible
  • Compatible with AUTOSAR at least on the wire-format level; i.e. can communicate with PDUs AUTOSAR, can receive and send without modification to the AUTOSAR standard. The mappings within AUTOSAR shall be chosen according to the SOME/IP specification.
  • Provides the features required by automotive use-cases
  • Is scalable from tiny to large platforms

SOME/IP designed to enable communication between ECUs. SOME/IP supports User Datagram Protocol (UDP) and Transmission Control Protocol (TCP).

SOME/IP vs. SOME/IP-SD

You should distinguish SOME/IP and SOME/IP-SD (service discovery).

SOME/IP-SD is used to:

  • Locate service instances.
  • Detect if service instances are running.
  • Implement the Publish/Subscribe handling.

SOME/IP is responsible for message and event sending as well as RPC. These two protocols work together, but they are defined by different documents according to the AUTOSAR.

Key words of the protocol

Proxy/Skeleton

SOME/IP: protocol that should enable autonomous driving (1)

In case of the AUTOSAR proxy and skeleton is partially auto-generated. Proxy is a client that will consume, for example a RPC, from skeleton (service).

Service

A logical combination of zero or more methods, zero or more events, and zero or more fields.

Event/Eventgroup

A uni-directional data transmission that is only invoked on changes or cyclically and is sent from the producer of data to the consumers.

A logical grouping of events and notification events of fields inside a service in order to allow subscription

Method

A method, procedure, function, or subroutine that is called/invoked.

Example of the message

SOME/IP: protocol that should enable autonomous driving (2)

As we can see, we have a huge overhead. It means protocol will not fit if you have a lot of messages with low payload. Keep this in mind when you consider this protocol.

High level architecture

Please take a look on typical communication flow of the SOME/IP. Here is nothing special.

We have a server/client communication. Server announces about available service. Client subscribes and gets notification, once the evnt is triggered.

SOME/IP: protocol that should enable autonomous driving (3)

Implementation

SOME/IP is a standart and AUTOSAR does not provides the implementation. One of the commonly used libraries (implementation) for the SOME/IP is vsomeip.

vsomeip provides a lot of features, open source and distributed under the Mozilla Public License Version 2.0.

Let’s take a look how some basic communication of the vsomeip will look like.

Building the libary is very simple. Here is the example of the docker file to build and install the vsomeip:

FROM ubuntu:18.04RUN apt-get update && apt-get install -y \ build-essential \ cmake \ libboost-all-dev \ libgtest-dev \ wget \ zipRUN wget https://github.com/GENIVI/vsomeip/archive/3.1.20.3.zipRUN unzip 3.1.20.3.zip && rm -f 3.1.20.3.zipRUN mv vsomeip-3.1.20.3 vsomeipRUN mkdir /vsomeip/build && cd /vsomeip/build && \ cmake -DENABLE_SIGNAL_HANDLING=1 .. && \ make all -j8 && \ make install -j8

You can also install it on your localhost and no need to build it in Docker. I just use Docker to show you all dependencies and if you want to replicate and play with examples you can easily recreate the same behaviour.

Hello world vsomeip

Examples that we will check are the part of the vsomeip. All code can be found here: https://github.com/GENIVI/vsomeip/tree/master/examples

The most simple programm with SOME/IP is to start the SOME/IP daemon and create simple client-server applications on the same host. The daemon part is handled by the library and as a developer you do not need to care about it.

Client and server has a json file that provides some important parameters, like the IP address of the application, identifiers of the applications, name of the applications and roouting format and some other basic configurations of the SOME/IP.

I will not go deep into details all parameters are available in the official documentation. Here is the example of the simple hello world client-server that should run on the same host.

{ "unicast":"192.168.178.61", "logging": { "level":"debug", "console":"true" }, "applications": [ { "name":"hello_world_service", "id":"0x4444" }, { "name":"hello_world_client", "id":"0x5555" } ], "services": [ { "service":"0x1111", "instance":"0x2222", "unreliable":"30509" } ], "routing":"hello_world_service", "service-discovery": { "enable":"false" }}

Here is the implementation of the client class:

// global variables that should reflect what you defined in the // json config file.static vsomeip::service_t service_id = 0x1111;static vsomeip::instance_t service_instance_id = 0x2222;static vsomeip::method_t service_method_id = 0x3333;class hello_world_client {public: // Get the vSomeIP runtime and // create a application via the runtime, we could pass the application name // here otherwise the name supplied via the VSOMEIP_APPLICATION_NAME // environment variable is used hello_world_client() : rtm_(vsomeip::runtime::get()), app_(rtm_->create_application()) { } bool init() { // init the application if (!app_->init()) { LOG_ERR ("Couldn't initialize application"); return false; } // register a state handler to get called back after registration at the // runtime was successful app_->register_state_handler( std::bind(&hello_world_client::on_state_cbk, this, std::placeholders::_1)); // register a callback for responses from the service app_->register_message_handler(vsomeip::ANY_SERVICE, service_instance_id, vsomeip::ANY_METHOD, std::bind(&hello_world_client::on_message_cbk, this, std::placeholders::_1)); // register a callback which is called as soon as the service is available app_->register_availability_handler(service_id, service_instance_id, std::bind(&hello_world_client::on_availability_cbk, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); return true; } void start() { // start the application and wait for the on_event callback to be called // this method only returns when app_->stop() is called app_->start(); } void on_state_cbk(vsomeip::state_type_e _state) { if(_state == vsomeip::state_type_e::ST_REGISTERED) { // we are registered at the runtime now we can request the service // and wait for the on_availability callback to be called app_->request_service(service_id, service_instance_id); } } /* Function responsible for the availabilitz check */ void on_availability_cbk(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { // Check if the available service is the the hello world service if(service_id == _service && service_instance_id == _instance && _is_available) { // The service is available then we send the request // Create a new request std::shared_ptr<vsomeip::message> rq = rtm_->create_request(); // Set the hello world service as target of the request rq->set_service(service_id); rq->set_instance(service_instance_id); rq->set_method(service_method_id); // Create a payload which will be sent to the service std::shared_ptr<vsomeip::payload> pl = rtm_->create_payload(); std::string str("World"); std::vector<vsomeip::byte_t> pl_data(std::begin(str), std::end(str)); pl->set_data(pl_data); rq->set_payload(pl); // Send the request to the service. Response will be delivered to the // registered message handler LOG_INF("Sending: %s", str.c_str()); app_->send(rq); } } /* Function that is invoked once the server requested. */ void on_message_cbk(const std::shared_ptr<vsomeip::message> &_response) { if(service_id == _response->get_service() && service_instance_id == _response->get_instance() && vsomeip::message_type_e::MT_RESPONSE == _response->get_message_type() && vsomeip::return_code_e::E_OK == _response->get_return_code()) { // Get the payload and print it std::shared_ptr<vsomeip::payload> pl = _response->get_payload(); std::string resp = std::string( reinterpret_cast<const char*>(pl->get_data()), 0, pl->get_length()); LOG_INF("Received: %s", resp.c_str()); stop(); } } void stop() { // unregister the state handler app_->unregister_state_handler(); // unregister the message handler app_->unregister_message_handler(vsomeip::ANY_SERVICE, service_instance_id, vsomeip::ANY_METHOD); // alternatively unregister all registered handlers at once app_->clear_all_handler(); // release the service app_->release_service(service_id, service_instance_id); // shutdown the application app_->stop(); }private: std::shared_ptr<vsomeip::runtime> rtm_; std::shared_ptr<vsomeip::application> app_;};

Server implementation:

// this global variables should be the same you define in the // json config file.static vsomeip::service_t service_id = 0x1111;static vsomeip::instance_t service_instance_id = 0x2222;static vsomeip::method_t service_method_id = 0x3333;class hello_world_service {public: // Get the vSomeIP runtime and // create a application via the runtime, we could pass the application name // here otherwise the name supplied via the VSOMEIP_APPLICATION_NAME // environment variable is used hello_world_service() : rtm_(vsomeip::runtime::get()), app_(rtm_->create_application()), stop_(false), stop_thread_(std::bind(&hello_world_service::stop, this)) { } ~hello_world_service() { stop_thread_.join(); } bool init() { // init the application if (!app_->init()) { LOG_ERR("Couldn't initialize application"); return false; } // register a message handler callback for messages sent to our service app_->register_message_handler(service_id, service_instance_id, service_method_id, std::bind(&hello_world_service::on_message_cbk, this, std::placeholders::_1)); // register a state handler to get called back after registration at the // runtime was successful app_->register_state_handler( std::bind(&hello_world_service::on_state_cbk, this, std::placeholders::_1)); return true; } void start() { // start the application and wait for the on_event callback to be called // this method only returns when app_->stop() is called app_->start(); } void stop() { std::unique_lock<std::mutex> its_lock(mutex_); while(!stop_) { condition_.wait(its_lock); } std::this_thread::sleep_for(std::chrono::seconds(5)); // Stop offering the service app_->stop_offer_service(service_id, service_instance_id); // unregister the state handler app_->unregister_state_handler(); // unregister the message handler app_->unregister_message_handler(service_id, service_instance_id, service_method_id); // shutdown the application app_->stop(); } void terminate() { std::lock_guard<std::mutex> its_lock(mutex_); stop_ = true; condition_.notify_one(); } /* Function that reports the status of the application. * and is responsible to inform all actors in the network * about available service. */ void on_state_cbk(vsomeip::state_type_e _state) { if(_state == vsomeip::state_type_e::ST_REGISTERED) { // we are registered at the runtime and can offer our service app_->offer_service(service_id, service_instance_id); } } /* Functin that will be invoked once any actor in the network will call a service offered * by this class. */ void on_message_cbk(const std::shared_ptr<vsomeip::message> &_request) { // Create a response based upon the request std::shared_ptr<vsomeip::message> resp = rtm_->create_response(_request); // Construct string to send back std::string str("Hello "); str.append( reinterpret_cast<const char*>(_request->get_payload()->get_data()), 0, _request->get_payload()->get_length()); // Create a payload which will be sent back to the client std::shared_ptr<vsomeip::payload> resp_pl = rtm_->create_payload(); std::vector<vsomeip::byte_t> pl_data(str.begin(), str.end()); resp_pl->set_data(pl_data); resp->set_payload(resp_pl); // Send the response back app_->send(resp); // we have finished terminate(); }private: std::shared_ptr<vsomeip::runtime> rtm_; std::shared_ptr<vsomeip::application> app_; bool stop_; std::mutex mutex_; std::condition_variable condition_; std::thread stop_thread_;};

More examples

The vsomeip library has 2 more examples:

  1. Request-response example on different hosts
  2. Subscribe-notify example on different hosts

They are not too much different from simple hello-world, but still have minor changes in json config and couple more calls in the implementation. Feel free to check them for more insites.

What to take out from this article

  1. SOME/IP can be used if you have multiple application that have to communicate via the IP.
  2. It simplifies the IP configuration.
  3. It is not efficient for small messages. Keep in mind the overhead of each message.
  4. This will be the default communication protocol for the ADAPTIVE AUTOSAR that will be havily used in automotive. As well for ADAS. So expect to hear about this protocol in the future.

Used resources

SOME/IP: protocol that should enable autonomous driving (2024)
Top Articles
Latest Posts
Article information

Author: Pres. Carey Rath

Last Updated:

Views: 6224

Rating: 4 / 5 (41 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Pres. Carey Rath

Birthday: 1997-03-06

Address: 14955 Ledner Trail, East Rodrickfort, NE 85127-8369

Phone: +18682428114917

Job: National Technology Representative

Hobby: Sand art, Drama, Web surfing, Cycling, Brazilian jiu-jitsu, Leather crafting, Creative writing

Introduction: My name is Pres. Carey Rath, I am a faithful, funny, vast, joyous, lively, brave, glamorous person who loves writing and wants to share my knowledge and understanding with you.