RCP (the new RUDP)

Some months ago I found this awesome blog with research and a usable implementation of rfmon for uni-directional wireless communication. It uses libpcap and a modified firmware for the TP 721N dongle to send encoded video packets and telemetry to the GS. It’s unidirectional and this has some advantages. The biggest advantage for me was that it doesn’t require pairing nor connection handshake. Perfect for a quad!

So I included rfmon in RUDP and renamed the result to RCP (Reliable Comms Protocol…). It’s bidirectional in my case as I need to send control data to the quad as well but the advantages still apply.

Performance is great, I can send 1024×768 video @30 FPS, 2Mbps using around 4-4.5Mbps with very little CPU usage.

The problem I’ve hit is this: the more data I send, the more packets get lost due to interference, etc. Having a fixed retransmit rate – like every packet 3 times – requires a fixed amount of bandwidth but doesn’t scale at all to low-bandwidth situations. So I need a way to use the least amount of bandwidth possible while still ensuring that frames arrive at the other end.
One solution is to add ACK packets to reduce retransmission – which is what RCP does – but this also has an issue. Every confirmation packet keeps the channel busy for a little while – in turn dropping the total bandwidth of the system.
Current solution is to gather many confirmations and send them with low frequency – around MAX_RETRANSMIT_TIME / 2 (currently every 10ms). So fast enough to avoid retransmission, but not as fast as to keep the channel busy unnecessarily. So far this works beautifully.
Code time!

The brain on the UAV uses RCP setup with a RFMON socket:

 

auto s = new util::RCP_RFMON_Socket("mon0", 5);//5 is the end-point ID
m_socket.reset(s);
m_rcp.reset(new util::RCP);

util::RCP::Socket_Handle handle = m_rcp->add_socket(s);
if (handle >= 0)
{
    m_rcp->set_internal_socket_handle(handle);
    m_rcp->set_socket_handle(SETUP_CHANNEL, handle);
    m_rcp->set_socket_handle(PILOT_CHANNEL, handle);
    m_rcp->set_socket_handle(VIDEO_CHANNEL, handle);
    m_rcp->set_socket_handle(TELEMETRY_CHANNEL, handle);
}

 

So – this code adds a socket to the RCP instance and then instructs all channels to go through this socket. Same for the internal data – which represents the ACKs, pings (for RTT estimation) and connection requests.

The reason for this indirection is to allow different sockets for different channels. For example – use RFMON for unidirectional video streaming and another socket over a 433Mhz radio (like this one) for all other comms and ACKs.

In the near future I’ll try this – sending all channels except video through the RFM22B socket, as this should give me better range & penetration compared to 2.4Ghz.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s