自动驾驶技术栈——SOME/IP协议

一,关于车载软件通信

传统的车载软件通信采用的是经典的总线协议(比如CAN、LIN、FlexRay),这些总线采用的是面向信号的数据传输(Signal-based),基于信号在双绞线中的传输来通信,但是这些协议的传输带宽和传输速率有限,且不容易实现基于无线网更新车载软件(OTA)的需求。因此,新一代的车载软件通信更多采用了SOA架构下的SOME/IP协议,该协议采用的是面向服务的数据传输(Service-Oriented),基于ECU的服务在车载以太网中被请求或订阅来通信。

二,SOME/IP简介

SOME/IP是基于以太网实现的中间件通信协议。SOME/IP 是”Scalable Service-Oriented Middleware over IP”的缩写。

图片

SOME/IP在以太网模型的分层中,位于TCP/UDP传输层以上,属于应用层。

三,SOME/IP的特点

1.支持序列化操作。作为通信节点的ECU可能有不同的软件架构或者操作系统,为了保证传输机制的一致性,SOME/IP允许将UDP/TCP报文进行序列化操作。

2.支持远程过程调用 (RPC)。客户端可以远程地向服务器端请求数据,也可以远程地在服务器端执行某些函数。

3.服务发现(SD)。在面向服务的架构中,服务必须是可发现的,SOME/IP有个单独的SD模块负责服务的实现。

4.支持发布/订阅。客户端可以订阅服务器的内容,从而可以动态地接收来自服务器的更新数据。

四,SOME/IP消息格式

SOME/IP序列化消息的数据头格式如下:

Message ID: 用来标识参与远程调用的Method或者Event

Request ID: 用来标识不同的Client对象或者同一个Client对象发起的不同Session会话

Message Type: 用来区分消息体类型

常见的消息体类型:request/response/notification/error

Return Code: 通常返回E_OK(0x00),如果返回的是Response或Error消息体类型就不会是 0x0

Payload: 参与传输的数据段

五,SOME/IP的主要通信模式

1.Request/Response Methods

客户端发送请求到服务器,以及从服务器返回响应到客户端。服务器的错误响应也会返回给客户端。

2.Fire and Forget Methods

客户端向服务器发送请求,服务端不返回响应。

3.Notification Events

客户端订阅服务器的内容,每当服务器有数据变化或执行某任务后通知给订阅过的客户端。哪些客户端需要订阅由SOME/IP-SD来管理。

4.Field

一个字段表示一个状态,订阅该字段的客户端将字段值作为初始事件。字段值后面的每次更新都会通知给客户端。

六,SD 服务发现流程

1.SD有两种机制:

第一种机制是“提供服务”,服务器可以使用它向网络提供可用服务。另一种是“查找服务”,它使客户端能够请求到可用服务。

2.服务发现具体流程:
1.服务器通过广播发布消息

2.客户端通过广播查找消息

3.客户端找到消息后,进行订阅和确认(Subscribe – Ack)

3.SD过程的工作模式:

    客户端的两种模式:请求和监听(Request and Listen)

    服务器端的两种模式:提供和静默(Offer and Silent)

七,常见的开源实现–基于vSomeIP

BMW基于 SOME/IP 标准实现了开源的vsomeip框架,vsomeip能够独立集成到各种操作系统。

代码样例–Request/Response模式:

服务器端:

include

include

include

include

define SAMPLE_SERVICE_ID 0x1234

define SAMPLE_INSTANCE_ID 0x5678

define SAMPLE_METHOD_ID 0x0421

std::shared_ptr app;

void on_message(const std::shared_ptr &_request) {
std::shared_ptr its_payload = _request->get_payload();
vsomeip::length_t l = its_payload->get_length();

// Get payload
std::stringstream ss;
for (vsomeip::length_t i=0; i<l; i++) {
   ss << std::setw(2) << std::setfill('0') << std::hex
      << (int)*(its_payload->get_data()+i) << " ";
}

std::cout << "SERVICE: Received message with Client/Session ["
    << std::setw(4) << std::setfill('0') << std::hex << _request->get_client() << "/"
    << std::setw(4) << std::setfill('0') << std::hex << _request->get_session() << "] "
    << ss.str() << std::endl;

// Create response
std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get()->create_response(_request);
its_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> its_payload_data;
for (int i=9; i>=0; i--) {
    its_payload_data.push_back(i % 256);
}
its_payload->set_data(its_payload_data);
its_response->set_payload(its_payload);
app->send(its_response, true);

}

int main() {
app = vsomeip::runtime::get()->create_application(“World”);
app->init();
app->register_message_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_METHOD_ID, on_message);
app->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->start();
}

客户端:

include

include

include

include

include

include

define SAMPLE_SERVICE_ID 0x1234

define SAMPLE_INSTANCE_ID 0x5678

define SAMPLE_METHOD_ID 0x0421

std::shared_ptr< vsomeip::application > app;
std::mutex mutex;
std::condition_variable condition;

void run() {
std::unique_lock its_lock(mutex);
condition.wait(its_lock);

std::shared_ptr< vsomeip::message > request;
request = vsomeip::runtime::get()->create_request();
request->set_service(SAMPLE_SERVICE_ID);
request->set_instance(SAMPLE_INSTANCE_ID);
request->set_method(SAMPLE_METHOD_ID);

std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload();
std::vector< vsomeip::byte_t > its_payload_data;
for (vsomeip::byte_t i=0; i<10; i++) { its_payload_data.push_back(i % 256); } its_payload->set_data(its_payload_data);
request->set_payload(its_payload);
app->send(request, true);
}

void on_message(const std::shared_ptr &_response) {

std::shared_ptr its_payload = _response->get_payload();
vsomeip::length_t l = its_payload->get_length();

// Get payload
std::stringstream ss;
for (vsomeip::length_t i=0; iget_data()+i) << ” “;
}

std::cout << “CLIENT: Received message with Client/Session [” << std::setw(4) << std::setfill(‘0’) << std::hex << _response->get_client() << “/” << std::setw(4) << std::setfill(‘0’) << std::hex << _response->get_session() << “] “
<< ss.str() << std::endl;
}

void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) {
std::cout << “CLIENT: Service [“
<< std::setw(4) << std::setfill(‘0’) << std::hex << _service << “.” << _instance
<< “] is “
<< (_is_available ? “available.” : “NOT available.”)
<< std::endl;
condition.notify_one();
}

int main() {
app = vsomeip::runtime::get()->create_application(“Hello”);
app->init();
app->register_availability_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, on_availability);
app->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->register_message_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_METHOD_ID, on_message);
std::thread sender(run);
app->start();
}

服务器端的配置:

{
“unicast” : “172.17.0.2”,
“logging” :
{
“level” : “debug”,
“console” : “true”,
“file” : { “enable” : “false”, “path” : “/tmp/vsomeip.log” },
“dlt” : “false”
},
“applications” :
[
{
“name” : “World”,
“id” : “0x1212”
}
],
“services” :
[
{
“service” : “0x1234”,
“instance” : “0x5678”,
“unreliable” : “30509”
}
],
“routing” : “World”,
“service-discovery” :
{
“enable” : “true”,
“multicast” : “224.224.224.245”,
“port” : “30490”,
“protocol” : “udp”,
“initial_delay_min” : “10”,
“initial_delay_max” : “100”,
“repetitions_base_delay” : “200”,
“repetitions_max” : “3”,
“ttl” : “3”,
“cyclic_offer_delay” : “2000”,
“request_response_delay” : “1500”
}
}

客户端的配置:

{
“unicast” : “172.17.0.1”,
“logging” :
{
“level” : “debug”,
“console” : “true”,
“file” : { “enable” : “false”, “path” : “/var/log/vsomeip.log” },
“dlt” : “false”
},
“applications” :
[
{
“name” : “Hello”,
“id” : “0x1313”
}
],
“routing” : “Hello”,
“service-discovery” :
{
“enable” : “true”,
“multicast” : “224.224.224.245”,
“port” : “30490”,
“protocol” : “udp”,
“initial_delay_min” : “10”,
“initial_delay_max” : “100”,
“repetitions_base_delay” : “200”,
“repetitions_max” : “3”,
“ttl” : “3”,
“cyclic_offer_delay” : “2000”,
“request_response_delay” : “1500”
}
}

参考阅读:

1.https://inspiredhobbyist.org/what-is-some-ip-in-autosar/

2.https://mdnice.com/writing/6c21d60b8e74456b8d84004ced9baae2

3.https://github.com/COVESA/vsomeip/wiki/vsomeip-in-10-minutes

慢慢进步吧,waiting and hope.

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/206813.html

联系我们
联系我们
分享本页
返回顶部