All telemetry going again in web app.
This commit is contained in:
parent
1ea1d5477f
commit
679f2e1913
10 changed files with 175 additions and 68 deletions
|
@ -8,11 +8,11 @@ defmodule Augie.Sensor.IMU do
|
|||
|
||||
@type t :: %IMU{
|
||||
orientation: Quaternion.t(),
|
||||
accelerometer: Vector.t(),
|
||||
magnetometer: Vector.t(),
|
||||
gyroscope: Vector.t(),
|
||||
gravity: Vector.t(),
|
||||
linear_acceleration: Vector.t(),
|
||||
# accelerometer: Vector.t(),
|
||||
# magnetometer: Vector.t(),
|
||||
# gyroscope: Vector.t(),
|
||||
# gravity: Vector.t(),
|
||||
# linear_acceleration: Vector.t(),
|
||||
temperature: float
|
||||
}
|
||||
|
||||
|
@ -22,11 +22,11 @@ defmodule Augie.Sensor.IMU do
|
|||
@type t :: %__MODULE__{x: float, y: float, z: float, w: float}
|
||||
end
|
||||
|
||||
defmodule Vector do
|
||||
@moduledoc "Holds the `x`, `y` and `z` values for a vector."
|
||||
defstruct ~w[x y z]a
|
||||
@type t :: %__MODULE__{x: float, y: float, z: float}
|
||||
end
|
||||
# defmodule Vector do
|
||||
# @moduledoc "Holds the `x`, `y` and `z` values for a vector."
|
||||
# defstruct ~w[x y z]a
|
||||
# @type t :: %__MODULE__{x: float, y: float, z: float}
|
||||
# end
|
||||
|
||||
@doc """
|
||||
Convert incoming telemetry into a structure.
|
||||
|
@ -37,21 +37,21 @@ defmodule Augie.Sensor.IMU do
|
|||
orientation_y,
|
||||
orientation_z,
|
||||
orientation_w,
|
||||
accelerometer_x,
|
||||
accelerometer_y,
|
||||
accelerometer_z,
|
||||
magnetometer_x,
|
||||
magnetometer_y,
|
||||
magnetometer_z,
|
||||
gyroscope_x,
|
||||
gyroscope_y,
|
||||
gyroscope_z,
|
||||
gravity_x,
|
||||
gravity_y,
|
||||
gravity_z,
|
||||
linear_acceleration_x,
|
||||
linear_acceleration_y,
|
||||
linear_acceleration_z,
|
||||
# accelerometer_x,
|
||||
# accelerometer_y,
|
||||
# accelerometer_z,
|
||||
# magnetometer_x,
|
||||
# magnetometer_y,
|
||||
# magnetometer_z,
|
||||
# gyroscope_x,
|
||||
# gyroscope_y,
|
||||
# gyroscope_z,
|
||||
# gravity_x,
|
||||
# gravity_y,
|
||||
# gravity_z,
|
||||
# linear_acceleration_x,
|
||||
# linear_acceleration_y,
|
||||
# linear_acceleration_z,
|
||||
temperature
|
||||
]) do
|
||||
{:ok,
|
||||
|
@ -62,15 +62,15 @@ defmodule Augie.Sensor.IMU do
|
|||
z: orientation_z,
|
||||
w: orientation_w
|
||||
},
|
||||
accelerometer: %Vector{x: accelerometer_x, y: accelerometer_y, z: accelerometer_z},
|
||||
magnetometer: %Vector{x: magnetometer_x, y: magnetometer_y, z: magnetometer_z},
|
||||
gyroscope: %Vector{x: gyroscope_x, y: gyroscope_y, z: gyroscope_z},
|
||||
gravity: %Vector{x: gravity_x, y: gravity_y, z: gravity_z},
|
||||
linear_acceleration: %Vector{
|
||||
x: linear_acceleration_x,
|
||||
y: linear_acceleration_y,
|
||||
z: linear_acceleration_z
|
||||
},
|
||||
# accelerometer: %Vector{x: accelerometer_x, y: accelerometer_y, z: accelerometer_z},
|
||||
# magnetometer: %Vector{x: magnetometer_x, y: magnetometer_y, z: magnetometer_z},
|
||||
# gyroscope: %Vector{x: gyroscope_x, y: gyroscope_y, z: gyroscope_z},
|
||||
# gravity: %Vector{x: gravity_x, y: gravity_y, z: gravity_z},
|
||||
# linear_acceleration: %Vector{
|
||||
# x: linear_acceleration_x,
|
||||
# y: linear_acceleration_y,
|
||||
# z: linear_acceleration_z
|
||||
# },
|
||||
temperature: temperature
|
||||
}}
|
||||
end
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
defmodule Augie.Sensor.Logger do
|
||||
defstruct ~w[message at]a
|
||||
alias __MODULE__
|
||||
|
||||
@moduledoc """
|
||||
Storage struct for telemetry logs.
|
||||
"""
|
||||
|
||||
@type t :: %Logger{message: String.t(), at: DateTime.t()}
|
||||
|
||||
@doc """
|
||||
Convert incoming telemetry into a structure.
|
||||
"""
|
||||
@spec build([String.t()]) :: {:ok, Logger.t()} | {:error, any}
|
||||
def build([message]) when is_binary(message),
|
||||
do: {:ok, %Logger{message: message, at: DateTime.utc_now()}}
|
||||
|
||||
def build(_data), do: {:error, :bad_data}
|
||||
end
|
|
@ -2,7 +2,7 @@ defmodule Augie.SerialTelemetry do
|
|||
use GenServer
|
||||
alias Augie.SerialTelemetry.Decoder
|
||||
alias Circuits.UART
|
||||
alias MidiProto.{Firmata, Parser}
|
||||
alias MidiProto.Parser
|
||||
alias Phoenix.PubSub
|
||||
require Logger
|
||||
|
||||
|
@ -40,8 +40,15 @@ defmodule Augie.SerialTelemetry do
|
|||
{:ok, messages, parser} ->
|
||||
for message <- messages do
|
||||
case Decoder.decode(message) do
|
||||
{:ok, message} -> Logger.debug("Decoded message: #{inspect(message)}")
|
||||
{:error, _} -> Logger.debug("Cannot decode message: #{inspect(message)}")
|
||||
{:ok, name, message} ->
|
||||
PubSub.broadcast(Augie.PubSub, name, message)
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.warn(
|
||||
"Unable to decode incoming Firmata message: #{inspect(reason)}: #{
|
||||
inspect(message, limit: :infinity)
|
||||
}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -87,7 +94,7 @@ defmodule Augie.SerialTelemetry do
|
|||
UART.open(UART, uart,
|
||||
active: true,
|
||||
speed: @baud_rate,
|
||||
framing: UART.Framing.MIDI,
|
||||
framing: UART.Framing.None,
|
||||
rx_framing_timeout: 0
|
||||
) do
|
||||
Logger.info("Connected to Teensy on #{uart}")
|
||||
|
|
|
@ -1,17 +1,57 @@
|
|||
defmodule Augie.SerialTelemetry.Decoder do
|
||||
alias Augie.Sensor.{GPS, IMU, Power}
|
||||
alias MidiProto.Message.SystemExclusive
|
||||
use Bitwise
|
||||
|
||||
def decode(%SystemExclusive{vendor_id: 1, payload: <<2, 0, lsb, msb>>}) do
|
||||
value = lsb + (msb <<< 7)
|
||||
{:ok, %{name: :imu_temperature, value: value}}
|
||||
@moduledoc """
|
||||
This file is a bit of an omega mess because it uses binary pattern matching to
|
||||
decode the message payloads.
|
||||
"""
|
||||
|
||||
def decode(%SystemExclusive{vendor_id: 1, payload: <<2, 0, payload::binary>>}) do
|
||||
with {:ok,
|
||||
<<bus_voltage::little-float-size(32), shunt_voltage::little-float-size(32),
|
||||
current::little-float-size(32),
|
||||
power::little-float-size(32)>>} <- depad_binary(<<>>, payload),
|
||||
{:ok, update} <- Power.build([bus_voltage, shunt_voltage, current, power]) do
|
||||
{:ok, "telemetry.power", update}
|
||||
end
|
||||
end
|
||||
|
||||
# def decode(%SystemExclusive{
|
||||
# vendor_id: 1,
|
||||
# payload: <<1, 0, lsb0, msb0, lsb1, msb1, lsb2, msb2, lsb3, msb3>>
|
||||
# }) do
|
||||
# end
|
||||
def decode(%SystemExclusive{vendor_id: 1, payload: <<1, 0, payload::binary>>}) do
|
||||
with {:ok,
|
||||
<<ox::little-float-size(64), oy::little-float-size(64), oz::little-float-size(64),
|
||||
ow::little-float-size(64),
|
||||
temp::little-signed-integer-size(8)>>} <- depad_binary(<<>>, payload),
|
||||
{:ok, update} <- IMU.build([ox, oy, oz, ow, temp]) do
|
||||
{:ok, "telemetry.imu", update}
|
||||
end
|
||||
end
|
||||
|
||||
def decode(%SystemExclusive{vendor_id: 1, payload: <<0, 0, payload::binary>>}) do
|
||||
with {:ok,
|
||||
<<latitude::little-signed-integer-size(32), longitude::little-signed-integer-size(32),
|
||||
altitude::little-signed-integer-size(32), speed::little-signed-integer-size(32),
|
||||
heading::little-float-size(32), satellites::little-integer-size(8),
|
||||
status::little-integer-size(8)>>} <- depad_binary(<<>>, payload),
|
||||
{:ok, update} <-
|
||||
GPS.build([latitude, longitude, altitude, heading, speed, satellites, status]) do
|
||||
{:ok, "telemetry.gps", update}
|
||||
end
|
||||
end
|
||||
|
||||
def decode(_), do: {:error, "Unknown message"}
|
||||
|
||||
defp depad_binary(result, ""), do: {:ok, result}
|
||||
|
||||
defp depad_binary(
|
||||
result,
|
||||
<<0::integer-size(1), lsb::integer-size(7), 0::integer-size(1), msb::integer-size(7),
|
||||
rest::binary>>
|
||||
) do
|
||||
value = (msb <<< 7) + lsb &&& 0xFF
|
||||
depad_binary(<<result::binary, value::integer-size(8)>>, rest)
|
||||
end
|
||||
|
||||
defp depad_binary(_result, <<_>>), do: {:error, "Lost synchronisation"}
|
||||
end
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
<%= live_render(@socket, AugieWeb.OrientationLive, id: :orientation) %>
|
||||
<%= live_render(@socket, AugieWeb.TemperatureLive, id: :temperature) %>
|
||||
<%= live_render(@socket, AugieWeb.PowerLive, id: :power) %>
|
||||
</div>
|
||||
<div class="cell small-12 medium-6 large-4">
|
||||
<%= live_render(@socket, AugieWeb.GpsLive, id: :gps) %>
|
||||
|
|
|
@ -20,7 +20,7 @@ defmodule AugieWeb.GpsLive do
|
|||
@map_opts [size: "640x320", key: "AIzaSyBibH_1Yibm3gshxsQDUKw7mjaH9SyMrgw", maptype: "hybrid"]
|
||||
|
||||
def mount(_params, _context, socket) do
|
||||
if connected?(socket), do: PubSub.subscribe(Augie.PubSub, "GPS")
|
||||
if connected?(socket), do: PubSub.subscribe(Augie.PubSub, "telemetry.gps")
|
||||
|
||||
socket =
|
||||
socket
|
||||
|
|
|
@ -9,7 +9,7 @@ defmodule AugieWeb.OrientationLive do
|
|||
@moduledoc false
|
||||
|
||||
def mount(_params, _context, socket) do
|
||||
if connected?(socket), do: PubSub.subscribe(Augie.PubSub, "IMU")
|
||||
if connected?(socket), do: PubSub.subscribe(Augie.PubSub, "telemetry.imu")
|
||||
|
||||
{:ok, assign(socket, data_ready: false)}
|
||||
end
|
||||
|
|
31
webapp/lib/augie_web/live/power_live.ex
Normal file
31
webapp/lib/augie_web/live/power_live.ex
Normal file
|
@ -0,0 +1,31 @@
|
|||
defmodule AugieWeb.PowerLive do
|
||||
use Phoenix.LiveView
|
||||
alias Augie.Sensor.Power
|
||||
alias Phoenix.PubSub
|
||||
|
||||
@moduledoc false
|
||||
|
||||
def mount(_params, _context, socket) do
|
||||
if connected?(socket), do: PubSub.subscribe(Augie.PubSub, "telemetry.power")
|
||||
|
||||
{:ok, assign(socket, bus_voltage: nil, shunt_voltage: nil, current: nil, power: nil)}
|
||||
end
|
||||
|
||||
def handle_info(
|
||||
%Power{
|
||||
bus_voltage: bus_voltage,
|
||||
shunt_voltage: shunt_voltage,
|
||||
current: current,
|
||||
power: power
|
||||
},
|
||||
socket
|
||||
),
|
||||
do:
|
||||
{:noreply,
|
||||
assign(socket,
|
||||
bus_voltage: bus_voltage,
|
||||
shunt_voltage: shunt_voltage,
|
||||
current: current,
|
||||
power: power
|
||||
)}
|
||||
end
|
47
webapp/lib/augie_web/live/power_live.html.leex
Normal file
47
webapp/lib/augie_web/live/power_live.html.leex
Normal file
|
@ -0,0 +1,47 @@
|
|||
<div class="card">
|
||||
<div class="card-divider">
|
||||
<h4>Power</h4>
|
||||
</div>
|
||||
<div class="card-section">
|
||||
<div class="grid-x">
|
||||
<div class="cell auto"><strong>Bus voltage</strong></div>
|
||||
<div class="cell auto text-right">
|
||||
<%= if @bus_voltage do %>
|
||||
<%= Float.round(@bus_voltage, 2) %>V
|
||||
<% else %>
|
||||
-
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-x">
|
||||
<div class="cell auto"><strong>Shunt voltage</strong></div>
|
||||
<div class="cell auto text-right">
|
||||
<%= if @shunt_voltage do %>
|
||||
<%= Float.round(@shunt_voltage, 2) %>V
|
||||
<% else %>
|
||||
-
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-x">
|
||||
<div class="cell auto"><strong>Current</strong></div>
|
||||
<div class="cell auto text-right">
|
||||
<%= if @current do %>
|
||||
<%= Float.round(@current, 2) %>mA
|
||||
<% else %>
|
||||
-
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-x">
|
||||
<div class="cell auto"><strong>Power</strong></div>
|
||||
<div class="cell auto text-right">
|
||||
<%= if @power do %>
|
||||
<%= Float.round(@power, 2) %>W
|
||||
<% else %>
|
||||
-
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -6,7 +6,7 @@ defmodule AugieWeb.TemperatureLive do
|
|||
@moduledoc false
|
||||
|
||||
def mount(_params, _context, socket) do
|
||||
if connected?(socket), do: PubSub.subscribe(Augie.PubSub, "IMU")
|
||||
if connected?(socket), do: PubSub.subscribe(Augie.PubSub, "telemetry.imu")
|
||||
|
||||
{:ok, assign(socket, temperature: nil)}
|
||||
end
|
||||
|
|
Reference in a new issue