svpcom / wfb-ng

WFB-NG - the next generation of long-range packet radio link based on raw WiFi radio
https://docs.px4.io/main/en/tutorials/video_streaming_wifi_broadcast.html
GNU General Public License v3.0
1.02k stars 241 forks source link

Inject IMU data into image data frame #371

Closed lida2003 closed 5 days ago

lida2003 commented 1 month ago

Hi

We are trying VINS-Fusion, which is for Non-GPS navigation.

Currently, it's quite good with Mono-Camera + IMU data. As most IPC camera is not that powerful, I want to move Fusion algorithm on the computer.

So I want to pack IMU data into image frame, which is about 60 or 120FPS.

Is it possible to add this into wfb-ng?

svpcom commented 1 month ago

yes, but you should do it on the camera (video encoder) side. CCTV cameras do this for metadata (for example to log motion detection) via adding NAL with invalid type which normal video decoder can skip. But for your case is more simple to mix it as prefix (or suffix) to RTP packets

lida2003 commented 1 month ago

Currently, I'm using SSC338Q, which uses https://github.com/OpenIPC/majestic for encoding. And it's NOT opensource. Is there any alternative opensource code can be used (Or I can try to modify the code?), any performance impact?

svpcom commented 1 month ago

In case of openipc camera which is very restricted by disk size the more preferrable way is patch wfb_tx to mix IMU data to every incoming packet. See https://github.com/svpcom/wfb-ng/blob/1ba87b259c03e00bdd1a4b40c17e284369e3c7db/src/tx.cpp#L944. You need to add size of you IMU data struct to the buf size and set .iov_base = buf + sizeof(imu),

svpcom commented 1 month ago

On the rx side just write a simple proxy that will split prefixes from UDP packets and produce normal RTP and imu data streams

lida2003 commented 1 month ago

You're a genius! I'll test it later. Thanks a lot. If it works, I'll submit a PR.

svpcom commented 1 month ago

But as long-term solution I'll recommend to write simple proxy in C that will receive mavlink from uart, udp from majectic then mix latest IMU data from mavlink as prefix to incoming rtp udp packet and send resulting udp packet to wfb_tx. It will have much simplier logic than hacking wfb_tx. See https://github.com/OpenIPC/mavfwd for reference

lida2003 commented 1 month ago

Yes, I did some test on VINS-Fusion. Actually it's really time sensitive. And I have no idea about image part below.

Now I'm thinking there are a few steps as follows:

Image part:(no idea right now??? how to get timestamp on image frame level(no experience here))

  1. get image time from camera
  2. do image data time syn, line up with IPC system time
  3. do image process lined up with IPC system time (NOT camera RTC/driver time)
  4. wfb-ng tunnel transfer the image data

IMU part:

  1. do FC time sync, line up with IPC system time
  2. get IMU data with system time - time_offset
  3. inject data to wfb-ng udp packet
svpcom commented 1 month ago

I think you don't need separate timestamp from image. Just use timestamp from flight controller (bundle it with IMU data). Because frequency of IMU readings >> video framerate they always will be correct. So proposed algorithm is:

wait for mavlink from /dev/ttySXX or RTP packet:
    if mavlink:
          timestamp = data
          imu = data
    if rtp:
        send_udp(timestamp, imu, rtp_data)
lida2003 commented 1 month ago

There are some troubles here:

  1. I looked into the format of RTP packets containing timestamps, and it seems that the RTP timestamp differs from what I understand as a system timestamp.

} rtp_header_t;

-  system time from epoch

struct timespec { time_t tv_sec; // Seconds since the Epoch (Jan 1, 1970) long tv_nsec; // Nanoseconds (1 second = 1,000,000,000 nanoseconds) };


2. Additionally, if IMU data is injected into the image data stream, it would involve wfb-ng interacting with the application logic rather than merely functioning as an RF communication channel software. 

3. I am not entirely sure when the start of a data frame occurs.

**Therefore, I would like to confirm the following questions:**

1. During the testing process of wfb-ng, does polling for data in the code indicate the start of a frame is avaliable?

https://github.com/svpcom/wfb-ng/blob/7d9367ade04973cdfbe2c52dcf64ae5a96b438ff/src/tx.cpp#L932-L935

2. And at that moment, does the UDP stream remain uninterrupted until the entire data is fully transmitted, continuously running in the `for(;;)` loop?

https://github.com/svpcom/wfb-ng/blob/7d9367ade04973cdfbe2c52dcf64ae5a96b438ff/src/tx.cpp#L940

**If the above undestading is OK, then** 

1. Assuming the system time is obtained from the scenario in question 1. Then I can send this system timestamp to the backend server indicating a image frame is obtained at that moment.

2.  Both the timestamp and IMU data are sent to the server through another wfb-ng channel, which just add a hook to wfb-ng for sending the timestamp to local imu agent. If there is an opensource image capture program, I think it will NOT be necessary to modify any of wfb-ng code. But right now, majestic is NOT opensouce.

3. The imu agent is mainly focused on sending timestamped imu data and image timestamp marker to back server using anohter wfb-ng tunnel. (Maybe a time sync alignment function can be implemented to see TOF between the agent and server.)

4. Then the server compare and match the image timestamp upon receiving the frame data? (Of course, certain anomalies such as packet loss might need to be handled.)

Please let me know what have got in your mind? Any advice? Thanks.
svpcom commented 1 month ago

If you bundle IMU data to the same UDP packet with video data on the TX side then on RX IMU and video will be always coherent. You don't need to add (or use) any timestamps to the video stream.

[ camera ] ---|mipi|--> [ majectic] ---| RTP | --> mixer ---> wfb_tx --- .... radio ... --> wfb_rx --> splitter -- |RTP|--> OpenCV
                 [flight controller] ---> mavlink----+                                                     +---|mavlink| ---+

where mixer and splitter are simple udp proxies.

If use separate streams or tunnels for video and mavlink then they will use different queues (in kernel, in card, etc) and always be out of sync.

svpcom commented 1 month ago

In approach above you don't need to modify to majestic and wfb-ng

lida2003 commented 1 month ago

It's worth trying. And get back to you when I get result.

lida2003 commented 1 month ago

@svpcom Does Majestic support to change RTP packet size. Currently I found my test rtp source output 1400 bytes packet. And IPv4 IP(20)+UDP(8)+payload, 1500 - 20 - 8 = 1472, only 72 extra for IMU/time.

What would happen if I send UDP packet size beyond or large than MTU size(1500)? Any trouble with wfb-ng?Will the underlying layer perform fragmentation?

svpcom commented 1 month ago

@lida2003

  1. In /etc/majestic.yaml you can set rtp packet size
  2. For 8812au/eu with latest drivers mtu (max udp packet size) is 3993 but see note https://github.com/svpcom/wfb-ng/blob/4ea700606c259960ea169bad1f55fde77850013d/src/wifibroadcast.hpp#L103

If you will try to inject packet larger than wifi mtu then it will be truncated and you will unable to decrypt it on the RX side. Also all mtu > 1500 may have interoperability issues with non 8812au/eu cards (for example with ath9k)

lida2003 commented 1 month ago

OK, that's good news. I will switch to openipc camera(SSC338Q) and find out more.

And I have found there are glitches on Rpi3B+, I'm NOT sure why?

lida2003 commented 2 weeks ago

I have got an error(Error: Unable to inject packet: Message too long) on openipc-ssc30kq IMX335 8812EU.

How to configure to use large MTU?

RTW: module init start
RTW: rtl88x2eu v5.15.0.1-186-g768722062.20230815_COEX20230616-330a
RTW: build time: Apr 10 2024 12:55:07
RTW: rtl88x2eu BT-Coex version = COEX20230616-330a
RTW: rtw_inetaddr_notifier_register
# wfb_tx -p 0 -u 5600 -R 456000 -K /etc/drone.key -B 20 -M 1 -S 1 -L 1 -G long -k 8 -n 12 -T 0 -i 7669206 -f data -C 8000 wlan0
Using data frames
Listen on 5600 for wlan0
Listen on 8000 for management commands
169142 PKT     0:0:0:0:0:0:0
170142 TX_ANT  ff      627:0:29:47:278
170142 PKT     0:418:499658:627:788490:0:0
Error: Unable to inject packet: Message too long
svpcom commented 2 weeks ago

@lida2003 ifconfig wlan0 mtu 3000

lida2003 commented 1 week ago

@lida2003 ifconfig wlan0 mtu 3000

OK, I'll try if needed. Right now I didn't see that much IMU packet needed for transfer.

But it seems still have sync issue: https://github.com/HKUST-Aerial-Robotics/VINS-Fusion/issues/263 Hmm... Not sure what to do next....

lida2003 commented 5 days ago

Time issue, need to further investigate, definitly NOT wfb-ng issue.

Thanks for supports @svpcom