<<PackageHeader(rve_rpc)>> <<TOC(4)>> == Why? == `rve_rpc` is essentially a service replacement. You may ask, then, what the advantages of `rve_rpc` are vs. services. * `rve_rpc` is topic based. This means any topic-based tools such as [[rosbag]] will work with `rve_rpc`. Note that things like `rostopic echo` will not work properly due to how `rve_rpc` works internally. A [[rostopic]] equivalent for `rve_rpc` is planned. Also, because it is topic based, `rve_rpc` clients are always connected to their servers, meaning every `rve_rpc` call is equivalent to a persistent service call. * `rve_rpc` allows multiple rpc methods to be called over a single connection. This means fewer lookups to the master, and the ability to order asynchronous calls to different rpc methods. * `rve_rpc` provides an asynchronous interface, both for server callback responses, and for client method calls. These could be implemented for services as well. * `rve_rpc` can use any pair of messages as a request/response, and does not require a separate definition or separate generated code. == Examples == `rve_rpc` was mainly designed for use by [[rve_interface_gen]], so its API could probably use some work. Using it standalone is still fairly easy though. === Server === A server callback looks something like this: {{{ #!cplusplus void callback(rve_rpc::CallHandle<RequestMessage, ResponseMessage>& handle) { const RequestMessageConstPtr& req = handle.getRequest(); // do stuff with req // ... TestResponsePtr res(new TestResponse); handle.respond(res); } }}} `handle` here allows you to either respond immediately (like in the example), or store it off and respond later. If an `rve_rpc::CallHandle` is destroyed without ever responding, it responds with an exception. To indicate an error, you can either call `handle.except("my error message goes here")`, or you can throw an exception derived from `std::exception` from within your callback. Setting up the server is done using the `rve_rpc::Server` class, like so: {{{ #!cplusplus Server s("server_name", nh); s.addMethod<RequestMessage, ResponseMessage>("callMe", callback); s.ready(); }}} === Client === Use of a client looks something like this: {{{ #!cplusplus Client c("server_name", nh); Method<RequestMessage, ResponseMessage> m = c.addMethod<RequestMessage, ResponseMessage>("callMe"); c.connect(); ReqeustMessagePtr req(new RequestMessagePtr); // fill out req... ResponseMessageConstPtr res = m.call(req); }}} Alternatively, you can use it asynchronously like so: {{{ #!cplusplus m.callAsync(req, callback); }}} where `callback` is of the form: {{{ #!cplusplus void callback(const MethodResponse<ResponseMessage>& res) { if (res.error_code == rve_rpc::Response::SUCCESS) { const ResponseMessageConstPtr& msg = res.response; //... } } }}} == Internals == An `rve_rpc` client/server pair operate on a "request/response" topic. For example: {{{ /server_name/request /server_name/response }}} These topics are always of the type `rve_rpc::Request` and `rve_rpc::Response`. The request/response messages are serialized into a uint8 array inside the container message. This is why "rostopic echo" won't give you what you might expect with these topics. `rve_rpc` uses `RequestWrapper` and `ResponseWrapper` classes that serialize to the same wire format as the messages to support no-copy "serialization" when running intraprocess. ## AUTOGENERATED DON'T DELETE ## CategoryPackage