@Alex-Kushleyev
That's not perfect but I created a shell script based on https://docs.modalai.com/qgc-via-adb/ for the drone configuraiton.
For my PC configuration, I created an udev rule to force an interface name since usb0 is renamed in "enx******". My udev rule can only work with my drone (I think). To define IP address, I add a conf file in /etc/systemd/network/
I have only tested on my linux and it works perfectly :
#!/usr/bin/env bash
set -euo pipefail
# See ModalAI doc : https://docs.modalai.com/qgc-via-adb/
UDEV_RULE_DRONE="/etc/udev/rules.d/80-usb-ncm.rules"
UDEV_RULE_PC="/etc/udev/rules.d/99-voxl-usb-ncm.rules"
SYSTEMD_CONF_PC="/etc/systemd/network/10-voxl0.network"
USB_COMP_QUALCOM="/sbin/usb/compositions/901D"
# Network configuration
USB_IFACE="usb0"
USB_NET="192.168.7.0/24"
PC_IP="192.168.7.1"
DRONE_IP="192.168.7.2"
NM_CONN_NAME="voxl-usb-ncm"
show_help() {
echo "Usage: $0 [--pc] [--drone] [--uninstall]"
echo
echo "Enable USB NCM networking for ModalAI VOXL / Starling 2 Max"
echo
echo "Options:"
echo " --pc Configure host PC only"
echo " --drone Configure drone via adb only"
echo " --uninstall Remove configuration"
echo " --help Show this help"
echo
echo "Defaults: if neither --pc nor --drone is provided, both are processed."
}
do_pc_install() {
echo "[INFO][PC] Installing udev rule for VOXL USB NCM"
cat > "$UDEV_RULE_PC" <<EOF
SUBSYSTEM=="net", ACTION=="add", ATTRS{idVendor}=="05c6", ATTRS{idProduct}=="901d", ATTRS{serial}=="890d035c", NAME="voxl0"
EOF
echo "[INFO][PC] Creating systemd-networkd config for voxl0"
cat > "$SYSTEMD_CONF_PC" <<EOF
[Match]
Name=voxl0
[Network]
Address=${PC_IP}/24
LinkLocalAddressing=no
IPv6AcceptRA=no
EOF
echo "[INFO][PC] Reloading udev rules"
udevadm control --reload-rules
udevadm trigger
echo "[INFO][PC] Restarting systemd-networkd"
systemctl restart systemd-networkd
echo "[INFO][PC] PC installation complete"
}
do_pc_uninstall() {
echo "[INFO][PC] Removing PC configuration"
if [ -f "$UDEV_RULE_PC" ]; then
rm -f "$UDEV_RULE_PC"
echo "[INFO][PC] Removed udev rule"
fi
if [ -f "$SYSTEMD_CONF_PC" ]; then
rm -f "$SYSTEMD_CONF_PC"
echo "[INFO][PC] Removed systemd-networkd config"
fi
echo "[INFO][PC] Reloading udev rules"
udevadm control --reload-rules
udevadm trigger
echo "[INFO][PC] Restarting systemd-networkd"
systemctl restart systemd-networkd
echo "[INFO][PC] PC uninstallation complete"
}
do_drone_install() {
echo "[INFO][DRONE] Enabling USB NCM networking on VOXL via adb"
adb root
adb remount
echo "[INFO][DRONE] Updating USB composition in Qualcomm script \
$USB_COMP_QUALCOM configure the usb gadget with \
the addition of the function NCM"
echo "[INFO][DRONE] In $USB_COMP_QUALCOM, \
add the line 'ln -s functions/ncm.0 configs/c.1/f3 2>/dev/null | true' \
just after the line 'ln -s functions/ffs.adb configs/c.1/f2'"
adb shell "sed -i '/ln -s functions\\/ffs.adb configs\\/c.1\\/f2/a \
\\ ln -s functions\\/ncm.0 configs\\/c.1\\/f3 2>\\/dev\\/null | true' \
$USB_COMP_QUALCOM"
echo "[INFO][DRONE] Creating udev rule $UDEV_RULE_DRONE for usb0 with IP ${DRONE_IP}"
adb shell "cat << 'EOF' > $UDEV_RULE_DRONE
ACTION==\"add\", SUBSYSTEM==\"net\", KERNEL==\"usb0\", \
RUN+=\"/bin/sh -c 'sleep 2; /sbin/ifconfig usb0 ${DRONE_IP} netmask 255.255.255.0 up'\"
EOF"
echo "[INFO][DRONE] NCM enabled — reboot required"
}
do_drone_uninstall() {
echo "[INFO][DRONE] Removing NCM configuration"
adb root
adb remount
echo "[INFO][DRONE] Removing udev rule $UDEV_RULE_DRONE"
adb shell "rm -f $UDEV_RULE_DRONE || true"
echo "[INFO][DRONE] Reverting USB composition (901D)"
adb shell "
sed -i '/ln -s functions\\/ncm.0 configs\\/c.1\\/f3/d' \
$USB_COMP_QUALCOM
"
echo "[INFO][DRONE] USB NCM configuration removed"
echo "[INFO][DRONE] Reboot required to fully apply changes"
}
# Arg parsing
TARGET_PC=false
TARGET_DRONE=false
DO_UNINSTALL=false
for arg in "$@"; do
case "$arg" in
--help) show_help; exit 0 ;;
--pc) TARGET_PC=true ;;
--drone) TARGET_DRONE=true ;;
--uninstall) DO_UNINSTALL=true ;;
*)
echo "[ERROR] Unknown argument: $arg";
show_help;
exit 1 ;;
esac
done
# Default to both if none selected
if ! $TARGET_PC && ! $TARGET_DRONE; then
TARGET_PC=true
TARGET_DRONE=true
fi
# Execute
if $DO_UNINSTALL; then
$TARGET_PC && do_pc_uninstall
$TARGET_DRONE && do_drone_uninstall
else
$TARGET_PC && do_pc_install
$TARGET_DRONE && do_drone_install
fi
echo "[INFO] All done."
``