Commit d1cba94c authored by Don Gagne's avatar Don Gagne

Add Solo video support

parent 70124a1e
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include "QGCMAVLink.h" #include "QGCMAVLink.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include <QTcpSocket>
QGC_LOGGING_CATEGORY(APMFirmwarePluginLog, "APMFirmwarePluginLog") QGC_LOGGING_CATEGORY(APMFirmwarePluginLog, "APMFirmwarePluginLog")
static const QRegExp APM_COPTER_REXP("^(ArduCopter|APM:Copter)"); static const QRegExp APM_COPTER_REXP("^(ArduCopter|APM:Copter)");
...@@ -49,6 +51,8 @@ static const QString MIN_COPTER_VERSION_WITH_CORRECT_SEVERITY_MSGS("APM:Copter V ...@@ -49,6 +51,8 @@ static const QString MIN_COPTER_VERSION_WITH_CORRECT_SEVERITY_MSGS("APM:Copter V
static const QString MIN_PLANE_VERSION_WITH_CORRECT_SEVERITY_MSGS("APM:Plane V3.4.0"); static const QString MIN_PLANE_VERSION_WITH_CORRECT_SEVERITY_MSGS("APM:Plane V3.4.0");
static const QString MIN_ROVER_VERSION_WITH_CORRECT_SEVERITY_MSGS("APM:Rover V2.6.0"); static const QString MIN_ROVER_VERSION_WITH_CORRECT_SEVERITY_MSGS("APM:Rover V2.6.0");
const char* APMFirmwarePlugin::_artooIP = "10.1.1.1"; ///< IP address of ARTOO controller
const int APMFirmwarePlugin::_artooVideoHandshakePort = 5502; ///< Port for video handshake on ARTOO controller
/* /*
* @brief APMFirmwareVersion is a small class to represent the firmware version * @brief APMFirmwareVersion is a small class to represent the firmware version
...@@ -372,11 +376,21 @@ bool APMFirmwarePlugin::_handleStatusText(Vehicle* vehicle, mavlink_message_t* m ...@@ -372,11 +376,21 @@ bool APMFirmwarePlugin::_handleStatusText(Vehicle* vehicle, mavlink_message_t* m
// The following messages are incorrectly labeled as warning message. // The following messages are incorrectly labeled as warning message.
// Fixed in newer firmware (unreleased at this point), but still in older firmware. // Fixed in newer firmware (unreleased at this point), but still in older firmware.
if (messageText.contains(APM_COPTER_REXP) || messageText.contains(APM_SOLO_REXP) || messageText.contains(APM_PLANE_REXP) || messageText.contains(APM_ROVER_REXP) || if (messageText.contains(APM_COPTER_REXP) || messageText.contains(APM_PLANE_REXP) || messageText.contains(APM_ROVER_REXP) ||
messageText.contains(APM_PX4NUTTX_REXP) || messageText.contains(APM_FRAME_REXP) || messageText.contains(APM_SYSID_REXP)) { messageText.contains(APM_PX4NUTTX_REXP) || messageText.contains(APM_FRAME_REXP) || messageText.contains(APM_SYSID_REXP)) {
_setInfoSeverity(message); _setInfoSeverity(message);
} }
if (messageText.contains(APM_SOLO_REXP)) {
qDebug() << "Found Solo";
// Fix up severity
_setInfoSeverity(message);
// Start TCP video handshake with ARTOO
_soloVideoHandshake(vehicle);
}
// ArduPilot PreArm messages can come across very frequently especially on Solo, which seems to send them once a second. // ArduPilot PreArm messages can come across very frequently especially on Solo, which seems to send them once a second.
// Filter them out if they come too quickly. // Filter them out if they come too quickly.
if (messageText.startsWith("PreArm")) { if (messageText.startsWith("PreArm")) {
...@@ -599,3 +613,18 @@ void APMFirmwarePlugin::pauseVehicle(Vehicle* vehicle) ...@@ -599,3 +613,18 @@ void APMFirmwarePlugin::pauseVehicle(Vehicle* vehicle)
// Best we can do in this case // Best we can do in this case
vehicle->setFlightMode("Loiter"); vehicle->setFlightMode("Loiter");
} }
void APMFirmwarePlugin::_soloVideoHandshake(Vehicle* vehicle)
{
Q_UNUSED(vehicle);
QTcpSocket* socket = new QTcpSocket();
socket->connectToHost(_artooIP, _artooVideoHandshakePort);
QObject::connect(socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error), this, &APMFirmwarePlugin::_artooSocketError);
}
void APMFirmwarePlugin::_artooSocketError(QAbstractSocket::SocketError socketError)
{
qgcApp()->showMessage(tr("Error during Solo video link setup: %1").arg(socketError));
}
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include "QGCLoggingCategory.h" #include "QGCLoggingCategory.h"
#include "APMParameterMetaData.h" #include "APMParameterMetaData.h"
#include <QAbstractSocket>
Q_DECLARE_LOGGING_CATEGORY(APMFirmwarePluginLog) Q_DECLARE_LOGGING_CATEGORY(APMFirmwarePluginLog)
class APMFirmwareVersion class APMFirmwareVersion
...@@ -107,6 +109,9 @@ protected: ...@@ -107,6 +109,9 @@ protected:
/// All access to singleton is through stack specific implementation /// All access to singleton is through stack specific implementation
APMFirmwarePlugin(void); APMFirmwarePlugin(void);
void setSupportedModes(QList<APMCustomMode> supportedModes); void setSupportedModes(QList<APMCustomMode> supportedModes);
private slots:
void _artooSocketError(QAbstractSocket::SocketError socketError);
private: private:
void _adjustSeverity(mavlink_message_t* message) const; void _adjustSeverity(mavlink_message_t* message) const;
...@@ -118,11 +123,16 @@ private: ...@@ -118,11 +123,16 @@ private:
void _handleParamSet(Vehicle* vehicle, mavlink_message_t* message); void _handleParamSet(Vehicle* vehicle, mavlink_message_t* message);
bool _handleStatusText(Vehicle* vehicle, mavlink_message_t* message); bool _handleStatusText(Vehicle* vehicle, mavlink_message_t* message);
void _handleHeartbeat(Vehicle* vehicle, mavlink_message_t* message); void _handleHeartbeat(Vehicle* vehicle, mavlink_message_t* message);
void _soloVideoHandshake(Vehicle* vehicle);
APMFirmwareVersion _firmwareVersion; APMFirmwareVersion _firmwareVersion;
bool _textSeverityAdjustmentNeeded; bool _textSeverityAdjustmentNeeded;
QList<APMCustomMode> _supportedModes; QList<APMCustomMode> _supportedModes;
QMap<QString, QTime> _noisyPrearmMap; QMap<QString, QTime> _noisyPrearmMap;
static const char* _artooIP;
static const int _artooVideoHandshakePort;
}; };
#endif #endif
...@@ -56,6 +56,9 @@ public: ...@@ -56,6 +56,9 @@ public:
GuidedModeCapability = 1 << 3, ///< Vehicle Support guided mode commands GuidedModeCapability = 1 << 3, ///< Vehicle Support guided mode commands
} FirmwareCapabilities; } FirmwareCapabilities;
/// Called when Vehicle is first created to send any necessary mavlink messages to the firmware.
virtual void initializeVehicle(Vehicle* vehicle);
/// @return true: Firmware supports all specified capabilites /// @return true: Firmware supports all specified capabilites
virtual bool isCapable(FirmwareCapabilities capabilities); virtual bool isCapable(FirmwareCapabilities capabilities);
...@@ -130,9 +133,6 @@ public: ...@@ -130,9 +133,6 @@ public:
/// @param message[in,out] Mavlink message to adjust if needed. /// @param message[in,out] Mavlink message to adjust if needed.
virtual void adjustOutgoingMavlinkMessage(Vehicle* vehicle, mavlink_message_t* message); virtual void adjustOutgoingMavlinkMessage(Vehicle* vehicle, mavlink_message_t* message);
/// Called when Vehicle is first created to send any necessary mavlink messages to the firmware.
virtual void initializeVehicle(Vehicle* vehicle);
/// Determines how to handle the first item of the mission item list. Internally to QGC the first item /// Determines how to handle the first item of the mission item list. Internally to QGC the first item
/// is always the home position. /// is always the home position.
/// @return /// @return
......
...@@ -40,7 +40,7 @@ FlightDisplayViewController::FlightDisplayViewController(QObject *parent) ...@@ -40,7 +40,7 @@ FlightDisplayViewController::FlightDisplayViewController(QObject *parent)
* This is the receiving end of an UDP RTP stream. The sender can be setup with this command: * This is the receiving end of an UDP RTP stream. The sender can be setup with this command:
* *
* gst-launch-1.0 uvch264src initial-bitrate=1000000 average-bitrate=1000000 iframe-period=1000 name=src auto-start=true src.vidsrc ! \ * gst-launch-1.0 uvch264src initial-bitrate=1000000 average-bitrate=1000000 iframe-period=1000 name=src auto-start=true src.vidsrc ! \
* video/x-h264,width=1280,height=720,framerate=24/1 ! h264parse ! rtph264pay ! udpsink host=192.168.1.9 port=5000 * video/x-h264,width=1280,height=720,framerate=24/1 ! h264parse ! rtph264pay ! udpsink host=192.168.1.9 port=5600
* *
* Where the main parameters are: * Where the main parameters are:
* *
...@@ -63,7 +63,7 @@ FlightDisplayViewController::FlightDisplayViewController(QObject *parent) ...@@ -63,7 +63,7 @@ FlightDisplayViewController::FlightDisplayViewController(QObject *parent)
*/ */
_videoSurface = new VideoSurface; _videoSurface = new VideoSurface;
_videoReceiver = new VideoReceiver(this); _videoReceiver = new VideoReceiver(this);
_videoReceiver->setUri(QLatin1Literal("udp://0.0.0.0:5000")); _videoReceiver->setUri(QLatin1Literal("udp://0.0.0.0:5600")); // Port 5600=Solo UDP port, if you change you will break Solo video support
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
_videoReceiver->setVideoSink(_videoSurface->videoSink()); _videoReceiver->setVideoSink(_videoSurface->videoSink());
connect(&_frameTimer, &QTimer::timeout, this, &FlightDisplayViewController::_updateTimer); connect(&_frameTimer, &QTimer::timeout, this, &FlightDisplayViewController::_updateTimer);
......
...@@ -12,19 +12,19 @@ If you do have the proper GStreamer development libraries installed where QGC lo ...@@ -12,19 +12,19 @@ If you do have the proper GStreamer development libraries installed where QGC lo
For the time being, the pipeline is somewhat hardcoded, using h.264. It's best to use a camera capable of hardware encoding h.264, such as the Logitech C920. On the sender end, you would run something like this: For the time being, the pipeline is somewhat hardcoded, using h.264. It's best to use a camera capable of hardware encoding h.264, such as the Logitech C920. On the sender end, you would run something like this:
``` ```
gst-launch-1.0 uvch264src initial-bitrate=1000000 average-bitrate=1000000 iframe-period=1000 device=/dev/video0 name=src auto-start=true src.vidsrc ! video/x-h264,width=1920,height=1080,framerate=24/1 ! h264parse ! rtph264pay ! udpsink host=xxx.xxx.xxx.xxx port=5000 gst-launch-1.0 uvch264src initial-bitrate=1000000 average-bitrate=1000000 iframe-period=1000 device=/dev/video0 name=src auto-start=true src.vidsrc ! video/x-h264,width=1920,height=1080,framerate=24/1 ! h264parse ! rtph264pay ! udpsink host=xxx.xxx.xxx.xxx port=5600
``` ```
Where xxx.xxx.xxx.xxx is the IP address where QGC is running. You may tweak the bitrate, the resolution and the FPS based on your needs and/or available bandwidth. Where xxx.xxx.xxx.xxx is the IP address where QGC is running. You may tweak the bitrate, the resolution and the FPS based on your needs and/or available bandwidth.
To test using a test source on localhost, you can run this command: To test using a test source on localhost, you can run this command:
``` ```
gst-launch-1.0 videotestsrc pattern=ball ! x264enc ! rtph264pay ! udpsink host=127.0.0.1 port=5000 gst-launch-1.0 videotestsrc pattern=ball ! x264enc ! rtph264pay ! udpsink host=127.0.0.1 port=5600
``` ```
On the receiving end, if you want to test it from the command line, you can use something like: On the receiving end, if you want to test it from the command line, you can use something like:
``` ```
gst-launch-1.0 udpsrc port=5000 caps='application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264' ! rtph264depay ! avdec_h264 ! autovideosink fps-update-interval=1000 sync=false gst-launch-1.0 udpsrc port=5600 caps='application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264' ! rtph264depay ! avdec_h264 ! autovideosink fps-update-interval=1000 sync=false
``` ```
### Linux ### Linux
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment