aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mavigator-bindings/mavlink/common.xml5
-rw-r--r--mavigator-cockpit/src/main/scala/mavigator/cockpit/Instruments.scala58
-rw-r--r--mavigator-cockpit/src/main/scala/mavigator/cockpit/Layout.scala45
-rw-r--r--mavigator-cockpit/src/main/scala/mavigator/cockpit/MavlinkWebSockets.scala5
-rw-r--r--mavigator-uav/src/main/resources/reference.conf2
-rw-r--r--mavigator-uav/src/main/scala/mavigator/uav/Core.scala60
6 files changed, 119 insertions, 56 deletions
diff --git a/mavigator-bindings/mavlink/common.xml b/mavigator-bindings/mavlink/common.xml
index 163abe6..b91e165 100644
--- a/mavigator-bindings/mavlink/common.xml
+++ b/mavigator-bindings/mavlink/common.xml
@@ -3234,6 +3234,11 @@
<field type="float" name="size_x">Size in radians of target along x-axis</field>
<field type="float" name="size_y">Size in radians of target along y-axis</field>
</message>
+ <message id="150" name="Stability">
+ <description>Stability issues</description>
+ <field type="uint8_t" name="stable">Is it stable?</field>
+ </message>
+
<!-- MESSAGE IDs 180 - 240: Space for custom messages in individual projectname_messages.xml files -->
<message id="241" name="VIBRATION">
<description>Vibration levels and accelerometer clipping</description>
diff --git a/mavigator-cockpit/src/main/scala/mavigator/cockpit/Instruments.scala b/mavigator-cockpit/src/main/scala/mavigator/cockpit/Instruments.scala
index c8715f4..f6a32db 100644
--- a/mavigator-cockpit/src/main/scala/mavigator/cockpit/Instruments.scala
+++ b/mavigator-cockpit/src/main/scala/mavigator/cockpit/Instruments.scala
@@ -97,38 +97,36 @@ trait Instruments { page: Page =>
val overlayStyle = """
- |.hud-overlay {
- | position: absolute;
- | left: 0;
- | right: 0;
- | top: 0;
- | bottom: 0;
- |
- | display: flex;
- | flex-direction: row;
- | justify-content: center;
- | align-items: center;
- |}
- |.hud-overlay > * {
- | flex: 1 1 0;
- | width: 100%;
- | height: 100%;
- | max-width: 100%;
- | max-height: 100%;
- |}""".stripMargin
-
-
- def mode(name: String, kind: String, on: Boolean = false) = {
- div(`class` := s"mode $kind ${if (!on) "off"}")(name)
+ .hud-overlay {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ }
+ .hud-overlay > * {
+ flex: 1 1 0;
+ width: 100%;
+ height: 100%;
+ max-width: 100%;
+ max-height: 100%;
+ }"""
+
+
+ def mode(name: String, level: String) = new Instrument[Boolean] {
+ override val element: html.Element = div(`class` := s"mode $level off")(name).render
+ def update(newValue: Boolean): Unit = {
+ val classes = element.classList
+ if (newValue) classes.add("off") else classes.remove("off")
+ }
}
- //TODO make these into real instruments and lazy vals
- def modes = div(style := "float: right;")(
- mode("LINK", "danger", true),
- mode("BAT", "warning", true),
- mode("GPS", "warning", true),
- mode("STABILIZED", "info", true)
- )
+ val unstable = mode("UNSTABLE", "danger")
val modeStyle = """
.mode {
diff --git a/mavigator-cockpit/src/main/scala/mavigator/cockpit/Layout.scala b/mavigator-cockpit/src/main/scala/mavigator/cockpit/Layout.scala
index 991ee9a..67db95b 100644
--- a/mavigator-cockpit/src/main/scala/mavigator/cockpit/Layout.scala
+++ b/mavigator-cockpit/src/main/scala/mavigator/cockpit/Layout.scala
@@ -13,7 +13,9 @@ trait Layout { self: Page with Instruments =>
def mcp = div(id := "mcp")(
img(src := asset("images/logo-invert.svg"), style:="height: 20px; margin: 5px;"),
span(`class`:="mode warning")("Demo System"),
- modes
+ div(`style` := "float: right")(
+ unstable.element
+ )
)
/** Element to deisplay on heads-up display (main area). */
@@ -23,27 +25,26 @@ trait Layout { self: Page with Instruments =>
)
val layoutStyle = """
- |#cockpit {
- | width: 100%;
- | height: 100%;
- | display: flex;
- | flex-direction: column;
- | justify-content: flex-start;
- | align-items: stretch;
- |
- | background-color: pink;
- |}
- |
- |#mcp {
- | flex: 0 1 0;
- | background-color: #222222;
- |}
- |
- |#hud {
- | flex: 1 1 auto;
- | position: relative;
- | background-color: lightblue;
- |}""".stripMargin
+ #cockpit {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: stretch;
+
+ background-color: pink;
+ }
+
+ #mcp {
+ flex: 0 1 0;
+ background-color: #222222;
+ }
+ #hud {
+ flex: 1 1 auto;
+ position: relative;
+ background-color: lightblue;
+ }"""
override def styles = Seq(layoutStyle) ++ instrumentStyles
diff --git a/mavigator-cockpit/src/main/scala/mavigator/cockpit/MavlinkWebSockets.scala b/mavigator-cockpit/src/main/scala/mavigator/cockpit/MavlinkWebSockets.scala
index b2ecf48..d4b0239 100644
--- a/mavigator-cockpit/src/main/scala/mavigator/cockpit/MavlinkWebSockets.scala
+++ b/mavigator-cockpit/src/main/scala/mavigator/cockpit/MavlinkWebSockets.scala
@@ -55,6 +55,11 @@ trait MavlinkWebSockets { self: Instruments =>
case a: Attitude =>
attitudeOverlay.update((a.pitch, a.roll))
horizonOverlay.update((a.pitch, a.roll))
+ case Stability(v) => {
+ unstable.update(v != 0)
+ println("stability " + v)
+ }
+
case _ => ()
}
diff --git a/mavigator-uav/src/main/resources/reference.conf b/mavigator-uav/src/main/resources/reference.conf
index 282df90..bbd7f49 100644
--- a/mavigator-uav/src/main/resources/reference.conf
+++ b/mavigator-uav/src/main/resources/reference.conf
@@ -25,7 +25,7 @@ mavigator.uav {
# Settings related to mock connections
mock {
# Mavlink system ID of the simulated UAV
- remote_system_id = 42
+ remote_system_id = 1
# Mavlink component ID of the simulated UAV
remote_component_id = 0
# Divide simulated message frequency
diff --git a/mavigator-uav/src/main/scala/mavigator/uav/Core.scala b/mavigator-uav/src/main/scala/mavigator/uav/Core.scala
index 4418dae..02a8779 100644
--- a/mavigator-uav/src/main/scala/mavigator/uav/Core.scala
+++ b/mavigator-uav/src/main/scala/mavigator/uav/Core.scala
@@ -5,9 +5,12 @@ import akka.NotUsed
import akka.actor.{ActorLogging, ActorRef, ActorSystem, Props}
import akka.stream.Materializer
import akka.stream.actor.{ActorPublisher, ActorPublisherMessage}
-import akka.stream.scaladsl.{Flow, Sink, Source}
+import akka.stream.scaladsl.{ Flow, RunnableGraph, Sink, Source }
import akka.util.ByteString
+import org.mavlink.Assembler
+import org.mavlink.messages._
import org.reactivestreams.{Publisher, Subscriber}
+import scala.concurrent.duration._
/** A core enables dynamic creation and removal of clients and backend connections.
* It is essentially a dynamic stream multiplexer. */
@@ -31,8 +34,18 @@ class Core(implicit val system: ActorSystem, val materializer: Materializer) {
Source.asSubscriber[ByteString]
)((toClient, fromClient) => (toClient, fromClient))
- private lazy val runnable = clients.joinMat(backend){ case ((toClient, fromClient), (toBackend, fromBackend)) =>
- toClient
+ private lazy val runnable: RunnableGraph[Publisher[ByteString]] = {
+ val timer = Source.tick(2.seconds, 2.seconds, ())
+ val generator: Source[ByteString, _] = timer.flatMapConcat{ _ =>
+ Util.barrelRoll via Util.assembler
+ }
+
+ val merged: Flow[ByteString, ByteString, _] = Util.merge(generator, backend)
+
+ merged.joinMat(clients){case (_, (toClient, _)) =>
+ toClient
+ }
+
}
private lazy val clientPublisher: Publisher[ByteString] = {
@@ -55,6 +68,47 @@ class Core(implicit val system: ActorSystem, val materializer: Materializer) {
}
+object Util {
+ import akka.stream.scaladsl._
+ import akka.stream.FlowShape
+
+
+ def merge[A](preferred: Source[A, _], other: Flow[A, A, _]): Flow[A, A, _] = {
+ val graph = GraphDSL.create(preferred, other)((_, _)) { implicit builder =>
+ (pref, flow) =>
+
+ import GraphDSL.Implicits._
+
+ val merge = builder.add(MergePreferred[A](1))
+
+ pref.out ~> merge.preferred
+ flow.out ~> merge.in(0)
+
+ FlowShape(flow.in, merge.out)
+ }
+ Flow.fromGraph(graph)
+ }
+
+ def assembler: Flow[Message, ByteString, _] = Flow[Message].map{ msg =>
+ val as = new Assembler(1, 1)
+ val (id, payload) = Message.pack(msg)
+ val bytes = as.assemble(id, payload).toArray
+ ByteString(bytes)
+ }
+
+ def barrelRoll(): Source[Message, _] = {
+ val angle: Source[Float, _] =
+ Source.tick(10.millis, 10.millis, 0.1f).scan(0.0f)(_+_).takeWhile(_ < 2 * math.Pi)
+ val attitude = angle.map{ a =>
+ Attitude(0,a,0,0,0,0,0)
+ }
+
+ Source.single(Stability(0)) concat attitude concat Source.single(Stability(1))
+ }
+
+}
+
+
object Core {
private class BackendPublisher extends ActorPublisher[ByteString] with ActorLogging {