Arduino Uno Q (App Lab) as a USB Host to an Uno R3? Python environment sees 0 devices

Hello everyone,

I'm working on a Master-Slave hardware project and trying to use an Arduino Uno Q SBC as the main controller. I want it to communicate with a peripheral Arduino Uno R3 via a standard USB cable.

My Setup:

  • Uno Q is the Master.

  • A USB Hub is plugged into the Uno Q.

  • The Uno R3 is plugged into that USB Hub.

  • I am coding this inside the Arduino App Lab.

What I'm trying to do: I'm using the arduino.app_utils Bridge. My C++ sketch passes a string to my main.py Python script. I want Python to use pyserial to send that string to the Uno R3 (which should show up as /dev/ttyACM0 or /dev/ttyUSB0).

The Error: The Python script runs, but it is completely blind to the USB port. When I run serial.tools.list_ports.comports(), the console explicitly outputs: Linux sees 0 USB/Serial devices plugged in.

My Questions for the community:

  1. Is this even possible? Does the Uno Q's hardware/Zephyr kernel actually support USB OTG Host mode to talk to standard serial peripherals?

  2. Is it a sandbox issue? Is the Python Virtual Environment inside the App Lab completely isolated from the host OS's hardware? Is there an app.yaml configuration to expose /dev/tty* devices to the Python script?

  3. Alternatives? If the USB-C port is strictly a "Device" port and cannot act as a "Host", what is the cleanest alternative to achieve isolated, long-distance serial communication between the Uno Q and the Uno R3 without using I2C (due to address conflicts with identical LCD screens)? Can I use the native RX/TX pins on the Uno Q header to talk directly to the Uno R3's USB chip via an FTDI adapter?

Any guidance on App Lab's hardware permissions would be hugely appreciated!

Run your python script directly on Q (from ssh) to check p.2

If it works, there are options how to use containers or communicate with MCU from the same host script

Uno Q works great at USB host. The easy way is to NOT use App Lab Python for
this. Run regular Linux apps. For example, I would try socat to make a serial
to TCP bridge. Then open a TCP socket in the STM32 sketch to the socat bridge.
Use nohup to keep socat running even after logout. If you want this to auto
start when the system boots I would try crontab and @reboot. I do not have time
to try this out but I have used all these Linux utils on other Debian Linux
systems such Ubuntu and Raspberry Pi OS. They should work fine when run outside
of App Lab docker.

How to make a TCP to serial bridge with socat and nohup.

$ nohup socat TCP-LISTEN:5000,reuseaddr,fork FILE:/dev/ttyACM0,raw,echo=0 &

A regular Linux app can communicate with a sketch running on the STM32 using
TCP. The Uno Q User Manual includes an example of a sketch accessing a time
server using TCP.

The Arduino RouterBridge github repo has more examples.

Specifically, a sketch running on the STM32 should be able to read/write the Uno serial port by opening a TCP socket to localhost port 5000.

socat, nohup, and crontab are standard Linux utils with man pages. You may need to install socat.

I’ve beaten my head against this a bit and here’s what I’ve found:
Yes, Uno Q can see dev/ttyACM* but python scripts in App Lab are containerized and container can’t reliably see USB CDC as far as I could test. You can prove this by SSH into your board and run lsusb with your R3 plugged into the hub.
Obviously, all of this only applies in Network or SBC mode, since your computer will take Master if you have it plugged into the USB hub…
Essentially, the MCU on the Uno Q acts as a serial device claimed by dev/ttyHS1, which is owned by the router daemon service. Everything that happens on that internal serial line goes through that via RPC. In other words, even the MCU that’s on the board isn’t really “in” the App Lab app container.
I got around this by creating a similar daemon running on the host that opens dev/ttyACM* (in my case with an Uno R4 is was ACM0, still working on multiplexing…). Expose that through the router and then you should be able to talk to that daemon much the same as the on-board MCU at dev/ttyHS1
I hope this makes sense!

Hi bcstamper. Would it be possible for you to tell how to do this with a bit more details or some kind of method ?

Yes. In fact, I will share my project repo if you want.

My goal is to develop a fully functional USB serial “brick” that will bring serial devices into App Lab projects. I have proven it outside of App Lab with bi-directional multiplexing through a USB-C hub with Uno Q as master. Next step is to package it up so App Lab can use it just like the pre-made bricks. It currently uses an install script that must be run from the Uno Q terminal.

The basic premise is that it uses a host-side daemon I’ve called usbseriald.service which does the following:

  • Claims /dev/tty* devices
  • Creates a connection to the Arduino Router at /var/run/arduino-router.sock
  • Registers methods with Arduino Router

So basically the daemon owns the any serial devices connected to the Uno Q, becoming a client of the Arduino Router (that the Linux host side already uses to execute the remote procedure calls between the MPU and the MCU) and allowing you to bring serial devices into the App Lab container (and your individual app containers) through remote procedure call.
I have to do a little more testing to find the practical throughput limits of this project before I share, but I should be able to drop a repo link by the end of the week.

1 Like

Oh that’s neat ! Being able to see your repo and at the same time test it would be great. I’m not quite good with this kind of things but I need a way to read LiDAR data send through a serial connection on a /dev/ttyACM0 device, so it could be great.

I’ve never worked with LiDAR before. How fast a serial connection does it require? I haven’t done any speed or rate testing yet. My next step is to test maximum chunk size, then maximum devices, then maximum message rate.

Well, in my case it’s a 2D LiDAR so it doesn’t require that much. It sends data through a UART protocol at 115200 bauds rate with frames of 34 bytes (and 1 more frame of 28 bytes every 2250 frames sent).

It would be simpler to connect the LIDAR UART to the STM32 UART on pin 0 and 1 (Serial). Also connect ground.

Yup that’s definitely the way to do it. @ashio have you tried direct interface with the Uno Q? Judging by your original post, it sounds like your LiDAR device has a USB cable/port so just grab yourself a $5 USB to TTL UART adapter and go straight to the Uno Q.

The issue here is that I don’t have a lot of freedom since it’s a college project and the specs we have to follow are pretty tight. We can’t add any compnents or modify the plans we have been given.

It still found a way to do it tho by asking on another subject that I’ll link after.
https://forum.arduino.cc/t/uno-q-possible-to-connect-python-not-containerized-with-arduino/1436102/8?u=ashio

1 Like

From this thread of @ashio
" I had to connect it to the MPU because it what is asked in the project requirements, and we also believe that it makes the communication between the LiDAR and core programs more reliable."

Yeah I just saw that going back to it. Sounds like a lot of constraints we don’t know about for this project. Anyhow, not sure if I agree with the assumption that it makes the communication between LiDAR and “core programs” more reliable…

I believe that, from a processing perspective, the MPU is preferred, especially if the goal is to generate 3D representations from LiDAR data. However, proper interfacing hardware (such as a suitable shield or level-shifting circuitry) would be required from @ashio side to connect a 5 V or 3.3 V LiDAR sensor to the 1.8V MPU side of the UNO Q board.

Maybe, but if his constraints are “can’t add components” I would assume that means no level shifter, no shields, etc… I would still want it going through my MCU, which can do a lot of the deterministic stuff really fast and just bridge the important stuff. For instance, instead of a raw serial stream from the LiDAR, extract the useful stuff at the MCU level and send it over the bridge to the MPU for decision-making.

This is a good idea which @ashio may consider.