Home

Awesome

<a href="https://107-systems.org/"><img align="right" src="https://raw.githubusercontent.com/107-systems/.github/main/logo/107-systems.png" width="15%"></a> :floppy_disk: 107-Arduino-Cyphal

<a href="https://opencyphal.org/"><img align="right" src="https://raw.githubusercontent.com/107-systems/.github/main/logo/opencyphal.svg" width="25%"></a> Arduino Library Badge Compile Examples Smoke test status Unit Tests Code Coverage Arduino Lint keywords.txt Checks General Formatting Checks Spell Check

This Arduino library implements the Cyphal protocol (v1.0-beta) utilizing libcanard.

Note: For commercial support, customisation or contract development contact consulting@lxrobotics.com.

<p align="center"> <a href="https://github.com/107-systems/l3xz"><img src="https://raw.githubusercontent.com/107-systems/.github/main/logo/l3xz-logo-memento-mori-github.png" width="30%"></a> <a href="https://github.com/107-systems/viper"><img src="https://github.com/107-systems/.github/raw/main/logo/viper.jpg" width="30%"></a> </p>

This library works for

arduino-cli compile -b rp2040:rp2040:rpipico -v examples/OpenCyphal-Heartbeat-Publisher -u -p /dev/ttyACM0
arduino-cli compile -b arduino:renesas_portenta:portenta_c33 -v examples/OpenCyphal-Heartbeat-Publisher -u -p /dev/ttyACM0
git clone https://github.com/107-systems/107-Arduino-Cyphal && cd 107-Arduino-Cyphal
mkdir build && cd build
cmake .. && make

or

cmake -DBUILD_EXAMPLES=ON .. && make

Reference-Implementations

Examples

Publisher

#include <107-Arduino-Cyphal.h>
/* ... */
cyphal::Node::Heap<cyphal::Node::DEFAULT_O1HEAP_SIZE> node_heap;
cyphal::Node node_hdl(node_heap.data(), node_heap.size(), micros, [] (CanardFrame const & frame) { /* ... */ });

cyphal::Publisher<Heartbeat_1_0> heartbeat_pub = node_hdl.create_publisher<Heartbeat_1_0>
  (1*1000*1000UL /* = 1 sec in usecs. */);
/* ... */
void loop() {
  /* Process all pending OpenCyphal actions. */
  node_hdl.spinSome();
  /* ... */
  uavcan::node::Heartbeat_1_0 msg;

  msg.uptime = now / 1000;
  msg.health.value = uavcan::node::Health_1_0::NOMINAL;
  msg.mode.value = uavcan::node::Mode_1_0::OPERATIONAL;
  msg.vendor_specific_status_code = 0;

  heartbeat_pub->publish(msg);
  /* ... */
}

Subscriber

#include <107-Arduino-Cyphal.h>
/* ... */
cyphal::Node::Heap<cyphal::Node::DEFAULT_O1HEAP_SIZE> node_heap;
cyphal::Node node_hdl(node_heap.data(), node_heap.size(), micros, [] (CanardFrame const & frame) { /* ... */ });

cyphal::Subscription heartbeat_subscription = node_hdl.create_subscription<Heartbeat_1_0>(onHeartbeat_1_0_Received);
/* ... */
void loop() {
  /* Process all pending OpenCyphal actions. */
  node_hdl.spinSome();
}
/* ... */
void onHeartbeat_1_0_Received(Heartbeat_1_0 const & msg)
{
  char msg_buf[64];
  snprintf(msg_buf, sizeof(msg_buf),
           "Uptime = %d, Health = %d, Mode = %d, VSSC = %d",
           msg.uptime, msg.health.value, msg.mode.value, msg.vendor_specific_status_code);
  Serial.println(msg_buf);
}

Service Server

#include <107-Arduino-Cyphal.h>
/* ... */
cyphal::Node::Heap<cyphal::Node::DEFAULT_O1HEAP_SIZE> node_heap;
cyphal::Node node_hdl(node_heap.data(), node_heap.size(), micros, [] (CanardFrame const & frame) { /* ... */ });

cyphal::ServiceServer execute_command_srv = node_hdl.create_service_server<ExecuteCommand::Request_1_1, ExecuteCommand::Response_1_1>
  (2*1000*1000UL, onExecuteCommand_1_1_Request_Received);
/* ... */
void loop() {
  /* Process all pending OpenCyphal actions. */
  node_hdl.spinSome();
}
/* ... */
ExecuteCommand::Response_1_1 onExecuteCommand_1_1_Request_Received(ExecuteCommand::Request_1_1 const & req)
{
  ExecuteCommand::Response_1_1 rsp;
  rsp.status = ExecuteCommand::Response_1_1::STATUS_SUCCESS;
  return rsp;
}

Service Client

#include <107-Arduino-Cyphal.h>
/* ... */
cyphal::Node::Heap<cyphal::Node::DEFAULT_O1HEAP_SIZE> node_heap;
cyphal::Node node_hdl(node_heap.data(), node_heap.size(), micros, [] (CanardFrame const & frame) { /* ... */ });

cyphal::ServiceClient<ExecuteCommand::Request_1_1> srv_client = node_hdl.create_service_client<ExecuteCommand::Request_1_1, ExecuteCommand::Response_1_1>
  (2*1000*1000UL, onExecuteCommand_1_1_Response_Received);
/* ... */
void setup() {
  ExecuteCommand::Request_1_1 req;
  req.command = 0xCAFE;

  if (!srv_client->request(27 /* remote node id */, req))
    Serial.println("Service request failed.");
}
void loop() {
  /* Process all pending OpenCyphal actions. */
  node_hdl.spinSome();
}
/* ... */
void onExecuteCommand_1_1_Response_Received(ExecuteCommand::Response_1_1 const & rsp)
{
  if (rsp.status == ExecuteCommand::Response_1_1::STATUS_SUCCESS)
    Serial.println("Response: Success");
  else
    Serial.println("Response: Error");
}