Open murphym18 opened 3 years ago
I looked into using mavros to control the gimbal. Mavros doesn't provide a high-level interface for controlling the gimbal.
Instead we'll need to create/parse MAVLink messages (in binary form).
Unfortunately this is made slightly harder because the version of pymavlink
on PyPi doesn't include the message definitions we need. So we'll need to build a custom version and this page explains how to do it.
To figure this out, I made a hardware test that parses all the mavlink it receives from the typhoon h480 (simulated in gazebo). It raises errors like these:
[ERROR] [1634601784.341581]: bad callback: <function read_gimbal_cid.<locals>.cb at 0x7fd83f50c5e0>
Traceback (most recent call last):
File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 750, in _invoke_callback
cb(msg)
# more output...
File "...site-packages/pymavlink/dialects/v20/common.py", line 12383, in decode
raise MAVError('unknown MAVLink message ID %s' % str(mapkey))
pymavlink.dialects.v20.common.MAVError: unknown MAVLink message ID 284
[ERROR] [1634601784.357548]: bad callback: <function read_gimbal_cid.<locals>.cb at 0x7fd83f50c5e0>
Traceback (most recent call last):
File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 750, in _invoke_callback
cb(msg)
# more output...
File "...site-packages/pymavlink/dialects/v20/common.py", line 12383, in decode
raise MAVError('unknown MAVLink message ID %s' % str(mapkey))
pymavlink.dialects.v20.common.MAVError: unknown MAVLink message ID 285
Message IDs 284, and 285 are among the missing defintions. They refer to GIMBAL_DEVICE_SET_ATTITUDE
and GIMBAL_DEVICE_ATTITUDE_STATUS
messages.
But we need a version of pymavlink with other message definitions too. Including these:
LINK_NODE_STATUS
(caused an error)GIMBAL_MANAGER_STATUS
(caused an error)GIMBAL_MANAGER_SET_ATTITUDE
GIMBAL_DEVICE_INFORMATION
GIMBAL_DEVICE_SET_ATTITUDE
(caused an error)GIMBAL_DEVICE_ATTITUDE_STATUS
(caused an error)AUTOPILOT_STATE_FOR_GIMBAL_DEVICE
GIMBAL_MANAGER_SET_PITCHYAW
GIMBAL_MANAGER_SET_MANUAL_CONTROL
Building pymavlink
is pretty involved. We're not going to want to do this every time we make a docker image so I created a pip-installable archive. When we wanna get the hardware tests set up quickly we can just install the archive. I included it as a dependency in the requirements.txt
file. But for our future reference, here is a script that will generate and install pymavlink from source:
#!/bin/bash
if [ `id -u` -eq 0 ]
then
apt update
apt install --yes git python3 python-is-python3 python3-pip python3-lxml libxml2-utils
else
sudo apt update
sudo apt install --yes git python3 python-is-python3 python3-pip python3-lxml libxml2-utils
fi
python -m pip install --user future
git clone --recurse-submodules https://github.com/mavlink/mavlink.git
cd mavlink
export PYTHONPATH="$PYTHONPATH:$PWD"
MAVLINK_DIR="$PWD"
### Generate the python modules
# 2.0
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/AVSSUAS.py" external/dialects/AVSSUAS.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/storm32.py" external/dialects/storm32.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/ASLUAV.py" message_definitions/v1.0/ASLUAV.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/all.py" message_definitions/v1.0/all.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/ardupilotmega.py" message_definitions/v1.0/ardupilotmega.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/common.py" message_definitions/v1.0/common.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/development.py" message_definitions/v1.0/development.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/icarous.py" message_definitions/v1.0/icarous.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/matrixpilot.py" message_definitions/v1.0/matrixpilot.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/minimal.py" message_definitions/v1.0/minimal.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/paparazzi.py" message_definitions/v1.0/paparazzi.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/python_array_test.py" message_definitions/v1.0/python_array_test.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/standard.py" message_definitions/v1.0/standard.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/test.py" message_definitions/v1.0/test.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/uAvionix.py" message_definitions/v1.0/uAvionix.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output="$MAVLINK_DIR/pymavlink/dialects/v20/ualberta.py" message_definitions/v1.0/ualberta.xml
# 1.0
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/AVSSUAS.py" external/dialects/AVSSUAS.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/storm32.py" external/dialects/storm32.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/ASLUAV.py" message_definitions/v1.0/ASLUAV.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/all.py" message_definitions/v1.0/all.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/ardupilotmega.py" message_definitions/v1.0/ardupilotmega.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/common.py" message_definitions/v1.0/common.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/development.py" message_definitions/v1.0/development.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/icarous.py" message_definitions/v1.0/icarous.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/matrixpilot.py" message_definitions/v1.0/matrixpilot.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/minimal.py" message_definitions/v1.0/minimal.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/paparazzi.py" message_definitions/v1.0/paparazzi.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/python_array_test.py" message_definitions/v1.0/python_array_test.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/standard.py" message_definitions/v1.0/standard.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/test.py" message_definitions/v1.0/test.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/uAvionix.py" message_definitions/v1.0/uAvionix.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=1.0 --output="$MAVLINK_DIR/pymavlink/dialects/v10/ualberta.py" message_definitions/v1.0/ualberta.xml
# 0.9
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/AVSSUAS.py" external/dialects/AVSSUAS.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/storm32.py" external/dialects/storm32.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/ASLUAV.py" message_definitions/v1.0/ASLUAV.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/all.py" message_definitions/v1.0/all.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/ardupilotmega.py" message_definitions/v1.0/ardupilotmega.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/common.py" message_definitions/v1.0/common.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/development.py" message_definitions/v1.0/development.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/icarous.py" message_definitions/v1.0/icarous.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/matrixpilot.py" message_definitions/v1.0/matrixpilot.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/minimal.py" message_definitions/v1.0/minimal.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/paparazzi.py" message_definitions/v1.0/paparazzi.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/python_array_test.py" message_definitions/v1.0/python_array_test.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/standard.py" message_definitions/v1.0/standard.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/test.py" message_definitions/v1.0/test.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/uAvionix.py" message_definitions/v1.0/uAvionix.xml
python -m pymavlink.tools.mavgen --lang=Python --wire-protocol=0.9 --output="$MAVLINK_DIR/pymavlink/dialects/v09/ualberta.py" message_definitions/v1.0/ualberta.xml
python -m pip uninstall pymavlink
cd "$MAVLINK_DIR/pymavlink"
export NOGEN=1
python setup.py install --user
Yes, I'm thankful the missing message definitions were in the github.com/mavlink/mavlink repo. I was able to build that from source using the script in my last comment. It's too bad the verson of that library on PyPi is outdated. The pip-installable package I made, is just a more up-to-date version (with some slight modification so that it installs). There is a bug in pymavlink's setup.py file. My modification is a work-around. I wonder if that bug is preventing them from updating pymavlink on PyPi.
Streamline Designs has sourced a gimbal for our drones. The gimbal accepts the conventions put forth by MAVLink 1.0. So to control it, you must send it Storm32 commands (or so I believe). The Gimbal Manager built into PX4 may or may not be able to control a MAVLink 1.0 gimbal. If it can, then we should use the gimbal manager because that would give us a consistent interface moving forward. If it can’t then we may need to bypass the gimbal manager and address our gimbal commands directly to the gimbal.
We need to investigate how to move forward.