mavlink / MAVSDK-Java

MAVSDK client for Java.
71 stars 41 forks source link

Can Android connect over serial? #23

Open JonasVautherin opened 5 years ago

JonasVautherin commented 5 years ago

Asked on Slack, copying here for the record:

Hello!

Just wanted to know whats the best way to create a custom android groundstation app with mavsdk? There doesn't seem to be any framework for connecting to a serial connection on android to a telemetry module. I tried modifying the qgroundcontrol app but it isn't java based so it doesn't work for my purposes. I also tried using dronekit but their code is so old, much of it is unsupported by android studio, same story with trying to fork Android Tower.

Thanks in advance!

divyanshupundir commented 3 years ago

That is resulting in permission denied. So at this point, I really don't know. :sweat:

This is the log message that I get just before Mavsdk sends the permission denied message:

2020-10-10 20:49:55.688 14944-14944/<package> W/<package>: type=1400 audit(0.0:44009): avc: denied { search } for name="usb" dev="tmpfs" ino=907304 scontext=u:r:untrusted_app:s0:c184,c258,c512,c768 tcontext=u:object_r:usb_device:s0 tclass=dir permissive=0
2020-10-10 20:49:55.706 14944-14944/<package> E/Mavsdk: open failed: Permission denied
2020-10-10 20:49:55.706 14944-14944/<package> E/Mavsdk: Connection failed: Connection error
JonasVautherin commented 3 years ago

I am a bit confused, sorry :sweat_smile:. When do you get the permission denied error? What changed since your previous comment?

Also, do you have a way to share your code, such that one could possibly try to reproduce?

divyanshupundir commented 3 years ago

When do you get the permission denied error?

Oh, sorry, I went back to the original problem (i.e. trying to open the serial port using serial:///path/to/serial/device). This comment.

Also, do you have a way to share your code, such that one could possibly try to reproduce?

The code for the Android app or the changes that I made to MAVSDK?

JonasVautherin commented 3 years ago

The code for the Android app or the changes that I made to MAVSDK?

I guess both. Didn't you try that in a fork of MAVSDK-Java and MAVSDK? It's just that it is more likely that somebody else will try to reproduce if you share the code :innocent:.

divyanshupundir commented 3 years ago

The MAVSDK changes are in the android-serial branch. Over here: https://github.com/divyanshu1234/MAVSDK/tree/android-serial

I can't share the Android app code. Instead, I'll create a new project with only the relevant parts and make that public on GitHub. I'll try to do it in a few hours.

JonasVautherin commented 3 years ago

In the meantime, I had a quick look at usb-serial-for-android, since that's what is used by QGC. In the README, they use it (from Java) like this:

port.write(request, WRITE_WAIT_MILLIS);

Looking at the write implementation, they write the data using a UsbDeviceConnection.bulkTransfer (see here):

amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, timeout);

Looking at the documentation for [UsbDeviceConnection](https://developer.android.com/reference/android/hardware/usb/UsbDeviceConnection#getFileDescriptor()), there is a getFileDescriptor:

getFileDescriptor (Added in API level 12)
-------------------------------------------------------

- public int getFileDescriptor ()

Returns the native file descriptor for the device, or -1 if the device is not opened. This is intended for passing to native code to access the device.

Which returns a FileDescriptor, as an int:

Returns
--
int | the native file descriptor

Could it be that this is a better way to get a FileDescriptor? Did you compare your Java code to how they get this UsbDeviceConnection instance?

divyanshupundir commented 3 years ago

This is exactly what I have been using. usb-serial-for-android has been built on top of the code provided in android.hardware.usb classes, so it uses the same UsbDeviceConnection and other classes.

divyanshupundir commented 3 years ago

Here's the repository. The entire code is in master. Please have a look at it and let me know if it is working fine. Currently, it works only for arm64 devices.

If you want to try a different build of libmavsdk_server.so, you can replace the one in this directory app/src/main/jniLibs/arm64-v8a.

You can see if it's working with SITL by setting this flag to be true, and changing the system address over here.

I have not added the runtime permission for the USB yet, but it will work fine when you connect the module and start the app from the list displayed by the OS. If it is not showing the app even then, simply add your USB device over here.

And thank you again for taking out your time for this.

divyanshupundir commented 3 years ago

I came up with a solution to the problem. The code is available in the tcp_server branch of MavsdkAndroidSerialTest.

Basically, a separate thread is created that runs a local TCP server, implemented using Java Sockets in TcpInputOutputManager. It's structure is similar to SerialInputOutputManager.

Now, instead of sending the serial device address, I send that TCP server's IP (which is simply the localhost) and port to the MAVSDK server here. The input stream data that is received by the TCP server (from the MAVSDK server) is sent to the serial port here. And similarly, serial data input is routed to the output stream of the TCP server here (which is then sent to the MAVSDK server).

I haven't tested it completely, but for now, I am able to receive the telemetry data and am also able to arm my physical drone.

If you get a chance, please have a look at the code, and let me know in case you find some bugs.

JonasVautherin commented 3 years ago

Right, so you use the serial connection from Java instead of C++. I wish we could find a way to pass this file descriptor :confused:.

divyanshupundir commented 3 years ago

I agree. That would've been a better solution. The current solution requires two dedicated threads (one to transfer data from JNI to Java, and another back from Java to C++).

MichaelSwan3 commented 3 years ago

Hi, I incorporated the below project into my own - It's a usb serial terminal that seems to work quite well - no need to have additional C++ libraries. https://github.com/kai-morich/SimpleUsbTerminal So I can read the RAW data coming out of the FMU chip I'm connecting to - it's a bunch of hex.

How do I turn that RAW data into a mavlink message I can understand? Do I have to bounce it in and out of mavserver somehow?

File descriptor: I don't think you can use file descriptors to send and receive data in android - not sure on that.

But establishing a connection UsbDeviceConnection connection = manager.openDevice(driver.getDevice());

and getting the file descriptor returns a int number that wasn't -1. fileDesc = connection.getFileDescriptor(); No idea what to do with that number though.

JonasVautherin commented 3 years ago

How do I turn that RAW data into a mavlink message I can understand?

Well, what you can do is get the data from USB, pretend to be the drone and send them again over UDP to mavsdk_server. But because mavsdk_server is already able to read serial data, the best would be to pass the file descriptor (or whatever is needed to read the serial data) to mavsdk_server directly...

You can read serial data from USB in Java, so there should be a way to do that in C++, right? :innocent:

MichaelSwan3 commented 3 years ago

How do I send the file descriptor to mavsdk server ? It's an int and it's value is 246. When I run usb device info I get "dev/bus/usb/001/002"

JonasVautherin commented 3 years ago

How do I send the file descriptor to mavsdk server ? It's an int and it's value is 246.

That's exactly what was discussed above and apparently was not working properly :smile:. I don't know more than that, I haven't tried it myself. The idea was to modify libmavsdk_server such that it can take a file descriptor as an input.

divyanshupundir commented 3 years ago

@MichaelSwan3, you can refer to this comment. I had added the code to pass the file descriptor in this branch of my fork of MAVSDK. You can try to build it and see if the file descriptor that you're getting works or not.

MichaelSwan3 commented 3 years ago

Have you tried it on a rooted device ?

Not sure if this helps. https://stackoverflow.com/questions/25129446/how-can-one-open-a-usbdevice-object-as-a-file-similar-to-usbaccessory-using-fi

divyanshupundir commented 3 years ago

Have you tried it on a rooted device ?

No, I haven't. But, it will not fulfil my purpose. I intend to make an app for non-rooted devices.

There is a work-around to this problem that works fine for now. (here)

zealrussell commented 2 years ago

I wonder could I use serialAddress like "serial:///dev/bus/002/002:56700" to connect a radio now? I use OTG connect my phone with my radio(a drone data link communication module), and the QGROUNDCONTROL app can detect the radio and operate the drone successfully, but MAVSDK-Java couldn't. I think the error occurred in mavsdkServer.run(serialAddress ) Is there any method to solve this?

divyanshupundir commented 2 years ago

If you look over here. You'll find that QGoundControl uses the same USB IO manager interface as I have mentioned in my solution. Android does not let you access the serial port directly through its address.

jankrystianserafim commented 2 years ago

If you look over here. You'll find that QGoundControl uses the same USB IO manager interface as I have mentioned in my solution. Android does not let you access the serial port directly through its address.

Hi @divyanshu1234 ! Can I ask if you managed to connect the Android app to a SiK radio connected to the Android phone using this solution [https://github.com/divyanshu1234/MavsdkAndroidSerialTest.git] ? In other words, have you managed to get the mavsdkserver to connect with the SiK radio via the Android device's USB port? Thanks!

divyanshupundir commented 2 years ago

Yes. I have been using it for over an year now. It works flawlessly. I have made some improvements though, but they are architectural, the core method remains the same.

For most purposes the solution mentioned works well.

jankrystianserafim commented 2 years ago

I came up with a solution to the problem. The code is available in the tcp_server branch of MavsdkAndroidSerialTest.

Basically, a separate thread is created that runs a local TCP server, implemented using Java Sockets in TcpInputOutputManager. It's structure is similar to SerialInputOutputManager.

Now, instead of sending the serial device address, I send that TCP server's IP (which is simply the localhost) and port to the MAVSDK server here. The input stream data that is received by the TCP server (from the MAVSDK server) is sent to the serial port here. And similarly, serial data input is routed to the output stream of the TCP server here (which is then sent to the MAVSDK server).

I haven't tested it completely, but for now, I am able to receive the telemetry data and am also able to arm my physical drone.

If you get a chance, please have a look at the code, and let me know in case you find some bugs.

Did you add this code to the MAVSDK-Java android-client example app, or did you test this seperatley?

divyanshupundir commented 2 years ago

I haven't added it to the android-client example. It's in my repository over here.

jankrystianserafim commented 2 years ago

I haven't added it to the android-client example. It's in my repository over here.

Ok, thanks. Which files did you modify? Only the native-lib.cpp and MavsdkSeriver.Java, or also some other files?

jankrystianserafim commented 2 years ago

In MAVSDK--src--core-serial_connection.cpp,I can't find anything about android.

No, it's just creating a serial link, it doesn't have to know about Android. Currently, it opens a file descriptor from thepath you give (e.g. if you pass serial:///dev/ttyACM0, it will open a file descriptor for /dev/ttyACM0). Your tests suggest that we can't create a file descriptor on Android like this.

What I believe we should try is the following:

The first step is to add the possibility to pass a file descriptor to serial_connection.cpp (here). The rest will be done in MAVSDK-Java (actually in the mavsdk_server Android library, here).

Does that make sense?

Dose QGroundControl use mavsdk-server?

No, QGC uses its own MAVLink implementation. Though if you look at the sources, I'm pretty sure QGC does something similar (get the file descriptor and uses it to open the serial connection).

I could not successfully find my virtual Drone by udp://:14540

This has nothing to do with serial, so if you have issues using UDP, it should go in another issue 👍

So according to your advice here, the ideal situtation is that: Connection::SerialConnection() takes the file descriptor instead of the path like it is now here and then that _serial_node() takes the file descriptor here. Do I understand correctly @JonasVautherin ?

divyanshupundir commented 2 years ago

No. I've summarised the solution in this comment over here.

zealrussell commented 1 year ago

So is that mean I can use the USB IO manager in my mavsdk project  like QGC to connect my radio? Thank you for your reply.

------------------ 原始邮件 ------------------ 发件人: "Divyanshu @.>; 发送时间: 2022年5月6日(星期五) 晚上8:58 收件人: @.>; 抄送: @.>; @.>; 主题: Re: [mavlink/MAVSDK-Java] Can Android connect over serial? (#23)

If you look over here. You'll find that QGoundControl uses the same USB IO manager interface as I have mentioned in my solution. Android does not let you access the serial port directly through its address.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

Jai-GAY commented 1 year ago

I explore incorporating MavsdkAndroidSerialTest and usb-serial-for-android under one project to work on Android 11, USB host breakthrough, MAVSDK breakthrough but no Distance, Height, Charge, etc. data. My physical drone is running 4.3.0 arducopter firmware. wireless connection via Holybro SikRadio.

no read activities, wonder what I missed.

2022-12-14 13:43:15.862 LOG_DroneRepository D DroneRepository connect stage : false 2022-12-14 13:43:15.864 LOG_DroneRepository D initializeUsbDevice 2022-12-14 13:43:15.864 LOG_DroneRepository D device id = 2002 device id rcv = 2002 2022-12-14 13:43:15.865 UsbRequestJNI D init 2022-12-14 13:43:15.866 FtdiSerialPort D baud rate=19200, effective=19200, error=0.0%, value=0x809c, index=0x0000, divisor=156, subdivisor=2 2022-12-14 13:43:15.866 LOG_DroneRepository D connected = true 2022-12-14 13:43:15.866 LOG_DroneRepository D initializeUsbDevice: port isOpen: true 2022-12-14 13:43:15.867 LOG_DroneRepository D initializeUsbAndTcp 2022-12-14 13:43:15.867 SerialInpu...putManager I Running ... 2022-12-14 13:43:15.884 LOG_DroneRepository D initializeServerAndDrone exit 2022-12-14 13:43:15.884 LOG_MavsdkFragment D onCreateView out id = 2002 portnum = 0 rate = 19200 2022-12-14 13:43:15.884 Mavsdk I MAVSDK version: v1.4.6-dirty 2022-12-14 13:43:15.884 MAVSDK-Server D Running mavsdk_server with connection url: tcp://:8888 2022-12-14 13:43:15.884 Mavsdk I Waiting to discover system on tcp://:8888... 2022-12-14 13:43:15.886 LOG_TcpInp...putManager I Running ... 2022-12-14 13:43:15.886 LOG_TcpInp...putManager D Writing data len=1 2022-12-14 13:43:15.887 LOG_MavsdkFragment D onResume 2022-12-14 13:43:15.887 Quality I Skipped: false 10 cost 89.67633 refreshRate 0 processName com.hoho.android.usbserial.examples 2022-12-14 13:43:15.895 LOG_MavsdkFragment D onPause 2022-12-14 13:43:15.951 ColorModeChangeItem D preExecute mColorMode=0,token=android.os.BinderProxy@5bf6dbb 2022-12-14 13:43:15.952 LOG_MavsdkFragment D onResume 2022-12-14 13:43:15.954 OplusThermalStats E Error getting package info: com.hoho.android.usbserial.examples 2022-12-14 13:43:15.998 LOG_TcpInp...putManager D Writing data len=1 2022-12-14 13:43:16.014 LOG_TcpInp...putManager D Writing data len=2 2022-12-14 13:43:16.453 AuthDialogHelper E CheckNotificationCanBeSetSecond: check com.hoho.android.usbserial.examples , Notification master switch on, unable to pop dialog 2022-12-14 13:43:16.974 LOG_TcpInp...putManager D Writing data len=4 2022-12-14 13:43:18.004 LOG_TcpInp...putManager D Writing data len=1 2022-12-14 13:43:18.019 LOG_TcpInp...putManager D Writing data len=3

divyanshupundir commented 1 year ago

@Jai-GAY there may be some problems with using MAVSDK with Ardupilot. Can you test it with a PX4 drone?

Jai-GAY commented 1 year ago

I am sooooo careless, baud rate was not set correctly. read activities appeared but still no Distance, Height, charge, etc.

2022-12-14 15:13:47.813 Mavsdk I MAVSDK version: v1.4.6-dirty 2022-12-14 15:13:47.813 Quality I Skipped: true 2 cost 23.43949 refreshRate 0 processName com.hoho.android.usbserial.examples 2022-12-14 15:13:47.813 MAVSDK-Server D Running mavsdk_server with connection url: tcp://:8888 2022-12-14 15:13:47.813 Mavsdk I Waiting to discover system on tcp://:8888... 2022-12-14 15:13:47.815 LOG_TcpInp...putManager I Running ... 2022-12-14 15:13:47.815 LOG_TcpInp...putManager D Writing data len=1 2022-12-14 15:13:48.252 AuthDialogHelper E CheckNotificationCanBeSetSecond: check com.hoho.android.usbserial.examples , Notification master switch on, unable to pop dialog 2022-12-14 15:13:48.317 LOG_TcpInp...putManager D Writing data len=21 2022-12-14 15:13:48.318 Mavsdk D New: System ID: 1 Comp ID: 1 2022-12-14 15:13:48.318 Mavsdk D Component Autopilot (1) added. 2022-12-14 15:13:48.318 Mavsdk W Vehicle type changed (new type: 2, old type: 0) 2022-12-14 15:13:48.318 Mavsdk D Discovered 1 component(s) 2022-12-14 15:13:48.318 Mavsdk I System discovered 2022-12-14 15:13:48.318 LOG_TcpInp...putManager D Read data len=44 2022-12-14 15:13:48.319 LOG_TcpInp...putManager D Read data len=17 2022-12-14 15:13:48.320 Mavsdk I Server started 2022-12-14 15:13:48.320 Mavsdk I Server set to listen on 0.0.0.0:39985 2022-12-14 15:13:48.320 MAVSDK-Server D mavsdk_server is now running, listening on port 39985 2022-12-14 15:13:48.322 LOG_DroneRepository D initializeServerAndDrone systemAddress: tcp://:8888 port: 39985 2022-12-14 15:13:48.328 LOG_TcpInp...putManager D Read data len=21 2022-12-14 15:13:48.829 Mavsdk W sending again after 0.510295 s, retries to do: 3 (520). 2022-12-14 15:13:48.829 LOG_TcpInp...putManager D Read data len=44 2022-12-14 15:13:49.278 LOG_TcpInp...putManager D Writing data len=10 2022-12-14 15:13:49.295 LOG_TcpInp...putManager D Writing data len=11 2022-12-14 15:13:49.319 LOG_TcpInp...putManager D Read data len=21 2022-12-14 15:13:49.339 Mavsdk W sending again after 1.02104 s, retries to do: 2 (520). 2022-12-14 15:13:49.340 LOG_TcpInp...putManager D Read data len=44 2022-12-14 15:13:49.358 LOG_TcpInp...putManager D Writing data len=21 2022-12-14 15:13:49.359 Mavsdk D New: System ID: 51 Comp ID: 68 2022-12-14 15:13:49.359 Mavsdk D Component Unsupported component (68) added. 2022-12-14 15:13:49.422 LOG_TcpInp...putManager D Writing data len=5 2022-12-14 15:13:49.454 LOG_TcpInp...putManager D Writing data len=228 2022-12-14 15:13:49.454 Mavsdk W Received ack for not-existing command: 520! Ignoring... 2022-12-14 15:13:49.500 LOG_TcpInp...putManager D Writing data len=106 2022-12-14 15:13:49.500 Mavsdk W Received ack for not-existing command: 520! Ignoring... 2022-12-14 15:13:50.316 LOG_TcpInp...putManager D Writing data len=21 2022-12-14 15:13:50.320 LOG_TcpInp...putManager D Read data len=21 2022-12-14 15:13:51.229 LOG_TcpInp...putManager D Writing data len=17 2022-12-14 15:13:51.293 LOG_TcpInp...putManager D Writing data len=42 2022-12-14 15:13:51.319 LOG_TcpInp...putManager D Read data len=21 2022-12-14 15:13:52.253 LOG_TcpInp...putManager D Writing data len=17 2022-12-14 15:13:52.317 LOG_TcpInp...putManager D Writing data len=21 2022-12-14 15:13:52.327 LOG_TcpInp...putManager D Read data len=21 2022-12-14 15:13:52.333 LOG_TcpInp...putManager D Writing data len=21 2022-12-14 15:13:52.382 LOG_TcpInp...putManager D Writing data len=21 2022-12-14 15:14:02.101 Mavsdk D MAVLink: critical: PreArm: Throttle below failsafe 2022-12-14 15:14:02.101 Mavsdk D MAVLink: critical: PreArm: Hardware safety switch

Jai-GAY commented 1 year ago

There seem to exist a timing issue where a user launches the MAVSDK the second time or the previous closing was not "clean" enough.

2022-12-14 17:17:41.421 LOG_DroneRepository D initializeServerAndDrone exit 2022-12-14 17:17:41.421 Mavsdk I MAVSDK version: v1.4.6-dirty 2022-12-14 17:17:41.421 LOG_MavsdkFragment D onCreateView out id = 2002 portnum = 0 rate = 115200 2022-12-14 17:17:41.422 MAVSDK-Server D Running mavsdk_server with connection url: tcp://:8888 2022-12-14 17:17:41.422 Mavsdk I Waiting to discover system on tcp://:8888... 2022-12-14 17:17:41.423 Mavsdk E connect error: Connection refused 2022-12-14 17:17:41.423 Mavsdk E Connection failed: Socket connection error 2022-12-14 17:17:41.423 SerialInpu...putManager I Running ... 2022-12-14 17:17:41.423 LOG_MavsdkFragment D onResume 2022-12-14 17:17:41.424 Quality I Skipped: false 3 cost 30.638237 refreshRate 0 processName com.hoho.android.usbserial.examples 2022-12-14 17:17:41.432 LOG_MavsdkFragment D onPause

Jai-GAY commented 1 year ago

@Jai-GAY there may be some problems with using MAVSDK with Ardupilot. Can you test it with a PX4 drone?

The result for PX4 stack is the same seem like.

2023-01-09 12:06:34.605 Mavsdk I MAVSDK version: v1.4.6-dirty 2023-01-09 12:06:34.605 MAVSDK-Server D Running mavsdk_server with connection url: tcp://:8888 2023-01-09 12:06:34.605 Mavsdk I Waiting to discover system on tcp://:8888... 2023-01-09 12:06:34.606 TrafficStats D tagSocket(136) with statsTag=0xffffffff, statsUid=-1 2023-01-09 12:06:34.607 LOG_TcpInp...putManager I Running ... 2023-01-09 12:06:34.607 LOG_TcpInp...putManager D Writing data len=23 2023-01-09 12:06:34.608 LOG_MavsdkFragment D onResume 2023-01-09 12:06:34.608 Quality I Skipped: false 9 cost 82.73453 refreshRate 8333333 bit true processName com.hoho.android.usbserial.examples 2023-01-09 12:06:34.616 LOG_MavsdkFragment D onPause 2023-01-09 12:06:34.634 VRI[MainActivity] D onFocusEvent false 2023-01-09 12:06:34.692 LOG_TcpInp...putManager D Writing data len=64 2023-01-09 12:06:34.693 Mavsdk D New: System ID: 1 Comp ID: 1 2023-01-09 12:06:34.693 Mavsdk D Component Autopilot (1) added. 2023-01-09 12:06:34.721 ColorModeChangeItem D preExecute mColorMode=0,token=android.os.BinderProxy@7e9d87c 2023-01-09 12:06:34.722 Compatibil...geReporter D Compat change id reported: 78294732; UID 10362; state: ENABLED 2023-01-09 12:06:34.722 LOG_MavsdkFragment D onResume 2023-01-09 12:06:34.727 OplusThermalStats E Error getting package info: com.hoho.android.usbserial.examples 2023-01-09 12:06:34.730 VRI[MainActivity] D onFocusEvent true 2023-01-09 12:06:34.749 LOG_TcpInp...putManager D Writing data len=81 2023-01-09 12:06:34.843 LOG_TcpInp...putManager D Writing data len=36 2023-01-09 12:06:34.903 LOG_TcpInp...putManager D Writing data len=76 2023-01-09 12:06:34.946 LOG_TcpInp...putManager D Writing data len=36 2023-01-09 12:06:34.997 LOG_TcpInp...putManager D Writing data len=36 2023-01-09 12:06:35.121 LOG_TcpInp...putManager D Writing data len=134 2023-01-09 12:06:35.204 LOG_TcpInp...putManager D Writing data len=36 2023-01-09 12:06:35.273 LOG_TcpInp...putManager D Writing data len=112 2023-01-09 12:06:35.361 LOG_TcpInp...putManager D Writing data len=36 2023-01-09 12:06:35.413 LOG_TcpInp...putManager D Writing data len=39 2023-01-09 12:06:35.413 Mavsdk W Vehicle type changed (new type: 2, old type: 0) 2023-01-09 12:06:35.413 Mavsdk D Discovered 1 component(s) 2023-01-09 12:06:35.413 Mavsdk I System discovered 2023-01-09 12:06:35.414 LOG_TcpInp...putManager D Read data len=26 2023-01-09 12:06:35.420 LOG_TcpInp...putManager D Read data len=21 2023-01-09 12:06:35.424 Mavsdk I Server started 2023-01-09 12:06:35.424 Mavsdk I Server set to listen on 0.0.0.0:43285 2023-01-09 12:06:35.424 MAVSDK-Server D mavsdk_server is now running, listening on port 43285 2023-01-09 12:06:35.431 LOG_DroneRepository D initializeServerAndDrone systemAddress: tcp://:8888 port: 43285 2023-01-09 12:06:35.465 LOG_TcpInp...putManager D Writing data len=36 2023-01-09 12:06:35.496 LOG_TcpInp...putManager D Read data len=44 2023-01-09 12:06:35.519 LOG_TcpInp...putManager D Writing data len=57 2023-01-09 12:06:35.519 Mavsdk D New: System ID: 51 Comp ID: 68 2023-01-09 12:06:35.519 Mavsdk D Component Unsupported component (68) added. 2023-01-09 12:06:35.583 LOG_TcpInp...putManager D Writing data len=82 2023-01-09 12:06:35.641 LOG_TcpInp...putManager D Writing data len=130 2023-01-09 12:06:35.641 Mavsdk D MAVLink: info: data link #0 regained 2023-01-09 12:06:35.695 LOG_TcpInp...putManager D Writing data len=126 2023-01-09 12:06:35.742 LOG_TcpInp...putManager D Writing data len=126

ponnamkarthik commented 1 year ago

Hello i am trying to connect to board via usb from android device

D/MAVSDK-Server: Running mavsdk_server with connection url: serial:///dev/bus/usb/001/022:57600
I/Mavsdk: Waiting to discover system on serial:///dev/bus/usb/001/022:57600...
E/Mavsdk: open failed: Permission denied
E/Mavsdk: Connection failed: Connection error

i am getting above error

this is my runMavsdkServer function

private void runMavsdkServer(String systemAddress) {
    MavsdkEventQueue.executor().execute(() -> {
      Log.d("TAG", "runMavsdkServer: " + systemAddress);
      int mavsdkServerPort = mavsdkServer.run("serial://" + systemAddress + ":57600");
      drone = new System(BACKEND_IP_ADDRESS, mavsdkServerPort);

      disposables.add(drone.getTelemetry().getFlightMode().distinctUntilChanged()
              .subscribe(flightMode -> logger.debug("flight mode: " + flightMode)));
      disposables.add(drone.getTelemetry().getArmed().distinctUntilChanged()
              .subscribe(armed -> logger.debug("armed: " + armed)));
      disposables.add(drone.getTelemetry().getPosition().subscribe(position -> {
        LatLng latLng = new LatLng(position.getLatitudeDeg(), position.getLongitudeDeg());
        viewModel.currentPositionLiveData.postValue(latLng);
      }));

      isMavsdkServerRunning = true;
      runOnUiThread(() -> buttonRunDestroyMavsdkServer.setText(R.string.destroy_mavsdk_server));
    });
  }
Jai-GAY commented 1 year ago

D/MAVSDK-Server: Running mavsdk_server with connection url: serial:///dev/bus/usb/001/022:57600 I/Mavsdk: Waiting to discover system on serial:///dev/bus/usb/001/022:57600...

Even though Android underlying is Linux kernel or Linux way, the way of getting the serial port file descriptive is super challenging, so @divyanshu1234 suggested TCPIP over serial io manager that breakthrough the serial communication, my experience is it can read and write with the flight controller, but Android side still missing a puzzle to decode it correctly, that's my understanding, not sure am I correct.

JonasVautherin commented 1 year ago

I have never tried it myself (and I don't have the serial radio available right now), but I just had a quick look. If I was to do it, I would try to get the FileDescriptor from Java and pass it through JNI. It's not just an int, it's a FileDescriptor, so apparently it needs to be converted.

For Android <= 30, I would try this, i.e. something like:

void ***_setDataSource(JNIEnv *env, jobject thiz, 
    jobject fileDescriptor, jlong offset, jlong length)
{
    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);

That's passing the Java FileDescriptor object over JNI and making a corresponding int fd in C++. The FileDescriptor should be created from Java, the int fd should be passed to MAVSDK in C++ (something like what @divyanshu1234 did here).

For Android > 30, I would use AFileDescriptor_getFd, which supposedly does the same thing but officially: "Returns the Unix file descriptor represented by the given java.io.FileDescriptor."

For some more "official" mentions of those, see here.

divyanshupundir commented 1 year ago

Actually, using the fd from cpp side never worked. I finally used this solution. And 2 years and 3 months later, this solution still works flawlessly. In my app I haven't changed it much, just made some minor optimizations.

I believe that the cpp fd solution wouldn't work easily because Android requires special USB permissions to use the serial port. This is trivial to do using the Java SDK, but quite difficult on the cpp side. Even QGC uses the UsbSerial Java library to access the USB port for the Android app.

Jai-GAY commented 1 year ago

I am very curious how the universal cross-platform Mission Planner is able to connect to an Android USB device and communicate and parser the Ardupilot data.

so the magic lies in this file?

divyanshupundir commented 1 year ago

Actually, this Mission Planner file is responsible for handling the serial port on Android.

They are using the Xamarin.Android framework. You can think of it as the C# wrapper for the Android SDK. So they are not bypassing the Android framework.

As the driver they are using UsbSerialForAndroid, which is the Xamarin port of usb-serial-for-android.

Jai-GAY commented 1 year ago

very similar to Linux.cs file, this is the way they get the hardware id, that's the issue where previously cannot connect to the driver and port?

divyanshupundir commented 1 year ago

Yes. That solution never worked. I think it's because Android has the permission checks in place. We just can't use the USB port like that. We have to use the Android SDK and get the permissions.

Jai-GAY commented 1 year ago

So they are not bypassing the Android framework. Android has the permission checks in place. We just can't use the USB port like that.

I thought Android MP has permission checking wrapped inside the Xamarin.

var intent = PendingIntent.GetBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), PendingIntentFlags.Mutable);

That solution never worked. Is a puzzle for me.

divyanshupundir commented 1 year ago

Yes, as I said, Xamarin is like a C# wrapper for the Android SDK.

Jai-GAY commented 1 year ago

problems with using MAVSDK with Ardupilot.

For Ardupilot, I suggest considering this.

mfran89 commented 1 year ago

Hi, thanks for creating this conversation chain! I am currently trying to do what the original question is asking and I am having a lot of trouble.

My current problem is that I am trying to connect a Ardupilot pixhawk over usb to an android tablet. Based on the documentation in this repo I used the executor to have the mavsdk server run at: int serverport = _mavsdkServer.run("serial:///dev/bus/usb/001/015:57600"); but keep getting the error "open failed : permission denied" and "connection failed: connection error" from Mavsdk . I also get this strange one from the audit service running in the background implying the same thing type=1400 audit(1688669663.762:1569): avc: denied { search } for pid=31507 comm="mavsdk-event-qu" name="usb" dev="tmpfs" ino=7050 scontext=u:r:untrusted_app_30:s0:c19,c257,c512,c768 tcontext=u:object_r:usb_device:s0 tclass=dir permissive=0 SEPF_SM-X200_12_0001 unfiltered I followed the Android documentation (https://developer.android.com/guide/topics/connectivity/usb/host#java) and used the usb manager to request permission for the device which I do get permission for the device so I am not sure where I am going wrong.

From reading this chain it sounds like there needs to be multiple services written in c++ and in java and over tcp for this to work but I cant say for sure. So if there is a solution to this problem I am asking help for I would appreciate a response to this with alittle more clarity and direction.

Also fwiw I tried using this repo https://github.com/mik3y/usb-serial-for-android to open up a connection from my android app to the autopilot and it looks like it worked when I set the driver to a CDC type. However I havent tried reading and writing to the autopilot since I am hoping that mavsdk server can handle that portion. My point being that it looks like the other repo is able to interface to the autopilot so maybe I am missing something for mavsdk server to do the same thing.