simplified serial again

pull/280/head
connor rigby 2017-03-28 11:01:46 -07:00
parent 837c2d39a3
commit 567c0efb81
8 changed files with 143 additions and 405 deletions

View File

@ -28,7 +28,6 @@ defmodule Farmbot.CeleryScript.Command.ConfigUpdate do
if param_int do
Logger.info ">> is updating #{param_str}: #{val}"
"F22 P#{param_int} V#{val}" |> UartHan.write
Process.sleep(500)
# HACK read the param back because sometimes the firmware decides
# our param sets arent important enough to keep
read_param(%{label: param_str}, [])
@ -48,9 +47,11 @@ defmodule Farmbot.CeleryScript.Command.ConfigUpdate do
@spec filter_params([{binary, any}], map) :: [{binary, any}]
defp filter_params(blah, current) do
Enum.filter(blah, fn({param_str, val}) ->
result = Enum.filter(blah, fn({param_str, val}) ->
current[param_str] != val
end)
# Im sorry about this
if Enum.empty?(result), do: blah, else: result
end
end

View File

@ -151,35 +151,6 @@ defmodule Farmbot.Configurator.Router do
end
end
get "/image/latest" do
list_images = fn() ->
"/tmp/images"
|> File.ls!
|> Enum.reduce("", fn(image, acc) ->
acc <> "<img src=\"/image/#{image}\">"
end)
end
html =
~s"""
<html>
<body>
<form action=/image/capture>
<input type="submit" value="Capture">
</form>
#{list_images.()}
</body>
</html>
"""
conn |> send_resp(200, html)
end
get "/image/capture" do
Farmbot.CeleryScript.Command.take_photo %{}, []
conn
|> put_resp_header("location", "/image/latest")
|> send_resp(302, "OK")
end
# anything that doesn't match a rest end point gets the index.
match _, do: conn |> send_resp(404, "not found")
@ -194,7 +165,7 @@ defmodule Farmbot.Configurator.Router do
:done ->
blerp |> send_resp(200, "OK")
{:error, reason} ->
blerp |> send_resp(400, IO.inspect(reason))
blerp |> send_resp(400, inspect(reason))
end
end

View File

@ -5,12 +5,6 @@ defmodule Farmbot.Serial.Gcode.Parser do
@spec parse_code(binary) :: {binary, tuple}
# ????
def parse_code("R0 Q" <> tag), do: {tag, :idle}
def parse_code("R1 Q" <> tag), do: {tag, :received}
def parse_code("R2 Q" <> tag), do: {tag, :done}
def parse_code("R3 Q" <> tag), do: {tag, :error}
def parse_code("R4 Q" <> tag), do: {tag, :busy}
# / ???
def parse_code("R00 Q" <> tag), do: {tag, :idle}
def parse_code("R01 Q" <> tag), do: {tag, :received}
@ -19,7 +13,7 @@ defmodule Farmbot.Serial.Gcode.Parser do
def parse_code("R04 Q" <> tag), do: {tag, :busy}
# TODO(Connor) Fix these
def parse_code("R05" <> _r), do: :dont_handle_me # Dont care about this.
def parse_code("R05" <> _r), do: {nil, :dont_handle_me} # Dont care about this.
def parse_code("R06 " <> r), do: parse_report_calibration(r)
def parse_code("R21 " <> params), do: parse_pvq(params, :report_parameter_value)
@ -28,8 +22,8 @@ defmodule Farmbot.Serial.Gcode.Parser do
def parse_code("R81 " <> params), do: parse_end_stops(params)
def parse_code("R82 " <> params), do: parse_report_current_position(params)
def parse_code("R83 " <> v), do: parse_version(v)
def parse_code("R99 " <> message) do {:debug_message, message} end
def parse_code("Command" <> _), do: :dont_handle_me # I think this is a bug
def parse_code("R99 " <> message) do {nil, {:debug_message, message}} end
def parse_code("Command" <> _), do: {nil, :dont_handle_me} # I think this is a bug
def parse_code(code) do {:unhandled_gcode, code} end
@spec parse_report_calibration(binary)

View File

@ -10,8 +10,6 @@ defmodule Farmbot.Serial.Handler do
alias Farmbot.BotState
alias Farmbot.Lib.Maths
@race_fix 5000
@typedoc """
Handler pid or name
"""
@ -22,31 +20,20 @@ defmodule Farmbot.Serial.Handler do
"""
@type nerves :: handler
@typedoc """
The current command in the buffer being worked on.
"""
@type current :: %{
reply: nil | term,
handshake: binary,
timeout: reference | nil,
from: {pid, reference}
}
@typedoc """
State of the GenServer
"""
@type state :: %{
nerves: nerves,
tty: binary,
queue: :queue.queue,
current: nil | :no_firm | current
}
@type state :: {:hey, :fixme}
@doc """
Starts a UART GenServer
"""
def start_link(nerves, tty) do
GenServer.start_link(__MODULE__, {nerves, tty})
def start_link(nerves, tty, opts) when is_pid(nerves) and is_binary(tty) do
GenServer.start_link(__MODULE__, {nerves, tty}, opts)
end
@doc """
Starts a UART GenServer
"""
def start_link(tty, opts) when is_binary(tty) do
GenServer.start_link(__MODULE__, tty, opts)
end
@doc """
@ -55,10 +42,12 @@ defmodule Farmbot.Serial.Handler do
@spec available?(handler) :: boolean
def available?(handler \\ __MODULE__)
# If handler is a pid
def available?(handler) when is_pid(handler) do
GenServer.call(handler, :available?)
end
# if its a name, look it up
def available?(handler) do
uh = Process.whereis(handler)
if uh do
@ -97,319 +86,167 @@ defmodule Farmbot.Serial.Handler do
## Private
def init({nerves, tty}) when is_pid(nerves) and is_binary(tty) do
Process.link(nerves)
:ok = open_tty(nerves, tty)
GenServer.cast(Farmbot.BotState.Hardware, :eff)
{:ok, %{nerves: nerves, tty: tty, current: nil}}
end
def init(tty) when is_binary(tty) do
{:ok, nerves} = UART.start_link()
init({nerves, tty})
end
@spec open_tty(nerves, binary) :: :ok
defp open_tty(nerves, tty) do
# Open the tty
:ok = UART.open(nerves, tty)
# configure framing
UART.configure(nerves,
:ok = UART.configure(nerves,
framing: {UART.Framing.Line, separator: "\r\n"},
active: true,
rx_framing_timeout: 500)
# Black magic to fix races
Process.sleep(@race_fix)
# Flush the buffers so we start fresh
UART.flush(nerves)
:ok = UART.flush(nerves)
:ok
end
@spec init({nerves, binary}) :: {:ok, state} | :ignore
def init({nerves, tty}) do
Process.link(nerves)
Logger.info "Starting serial handler: #{tty}"
:ok = open_tty(nerves, tty)
update_default(self())
# generate a handshake
handshake = generate_handshake()
Logger.info "doing handshaking: #{handshake}"
if do_handshake(nerves, tty, handshake) do
UART.write(nerves, "F83 #{handshake}") # ???
do_hax()
state = %{tty: tty, nerves: nerves, queue: :queue.new(), current: nil}
{:ok, state}
else
Logger.warn "Handshake failed!"
state = %{
tty: tty, nerves: nerves, queue: :queue.new(), current: :no_firm
}
{:ok, state}
end
end
# Shhhhh
@spec do_hax :: no_return
defp do_hax, do: GenServer.cast(Farmbot.BotState.Hardware, :eff)
@spec generate_handshake :: binary
defp generate_handshake do
random_int = :rand.uniform(99)
"Q#{random_int}"
end
@spec do_handshake(nerves, binary, binary, integer) :: boolean
defp do_handshake(nerves, tty, handshake, retries \\ 5)
defp do_handshake(_, _, _, 0) do
Logger.info "Could not handshake: to many retries."
false
end
defp do_handshake(nerves, tty, handshake, retries) do
# Write a command to UART
UART.write(nerves, "F83 #{handshake}")
# Wait for it to respong
receive do
# if it sends a partial, we are probably out of sync
# flush the buffer and try again.
{:nreves_uart, ^tty, {:partial, _}} ->
UART.flush(nerves)
do_handshake(nerves, tty, handshake)
# Recieved happens before our actual response, just go to the next one
# if it exists
{:nerves_uart, ^tty, "R01" <> _} -> do_handshake(nerves, tty, handshake)
{:nerves_uart, ^tty, "Command:" <> _} -> do_handshake(nerves, tty, handshake)
# This COULD be our handshake. Check it.
{:nerves_uart, ^tty, str} ->
# if it contains our handshake, check if its the right command.
# flush the buffer and return
if String.contains?(str, handshake) do
Logger.info "Successfully completed handshake!"
"R83 " <> version = String.trim(str, " " <> handshake)
Farmbot.BotState.set_fw_version(version)
UART.flush(nerves)
true
else
# If not, Move on to the next thing in the buffer.
do_handshake(nerves, tty, handshake)
end
uh ->
# if we recieve some other stuff, we have a leak or something.
# I think this can be deleted.
Logger.warn "Could not handshake: #{inspect uh}"
false
after
# After 2 seconds try again.
2_000 ->
Logger.warn "Could not handshake: timeout, retrying."
do_handshake(nerves, tty, handshake, retries - 1)
end
end
@spec update_default(pid) :: :ok | no_return
defp update_default(pid) do
deregister()
# Either way, register this pid as the new one.
Process.register(pid, __MODULE__)
end
@spec deregister :: no_return
defp deregister do
# lookup the old default pid
old_pid = Process.whereis(__MODULE__)
# if one existst, unregister it.
if old_pid do
Logger.info "Deregistering #{inspect old_pid} from default Serial Handler"
Process.unregister(__MODULE__)
end
end
def handle_call(:get_state, _, state), do: {:reply, state, state}
def handle_call(:available?, _from, state) do
case state.current do
:no_firm -> {:reply, false, state}
_ -> {:reply, true, state}
end
end
def handle_call(:available?, _, state), do: {:reply, true, state}
# A new line to write.
def handle_call({:write, str, timeout}, from, state) do
# generate a handshake
handshake = generate_handshake()
# if the queue is empty, write this string now.
if :queue.is_empty(state.queue) do
ref = Process.send_after(self(), {:timeout, from, handshake}, timeout)
current = %{reply: nil, handshake: handshake, timeout: ref, from: from}
UART.write(state.nerves, str <> " #{handshake}")
{:noreply, %{state | current: current}}
else
q = :queue.in({str, handshake, from, timeout}, state.queue)
{:noreply, %{state | queue: q}}
end
UART.write(state.nerves, "#{str} #{handshake}")
timer = Process.send_after(self(), :timeout, timeout)
current = %{status: nil, reply: nil, from: from, q: handshake, timer: timer}
{:noreply, %{state | current: current}}
end
def handle_cast({:update_fw, hex_file, pid}, state) do
def handle_cast({:update_fw, file, pid}, state) do
UART.close(state.nerves)
Process.sleep(1000)
if String.contains?(state.tty, "tnt") do
Logger.warn "Not a real arduino!"
send(pid, :done)
{:noreply, state}
else
UART.close(state.nerves)
Process.sleep(100)
flash_firmware(state.tty, hex_file, pid)
Process.sleep(5000)
{:ok, new_state} = init({state.nerves, state.tty})
{:noreply, new_state}
flash_firmware(state.tty, file, pid)
end
end
def handle_info({:timeout, from, handshake}, state) do
def handle_info(:timeout, state) do
current = state.current
if current do
new_current = maybe_timeout({from, handshake}, current)
{:noreply, %{state | current: new_current}}
GenServer.reply(current.from, :timeout)
{:noreply, %{state | current: nil}}
else
{:noreply, state}
end
end
def handle_info({:nerves_uart, _tty, {:partial, thing}}, state) do
Logger.warn ">> got partial gcode: #{thing}"
{:noreply, state}
end
def handle_info({:nerves_uart, _tty, {:error, :eio}}, state) do
Logger.error "ARDUINO DISCONNECTED!"
{:noreply, %{state | queue: :queue.new(), current: nil}}
end
# This is when we get a code in from nerves_uart
@lint false # this is just a mess sorry
def handle_info({:nerves_uart, tty, gcode}, state) do
unless tty != state.tty do
parsed = Parser.parse_code(gcode)
case parsed do
# if the code has a handshake and its not done
# we just want to handle the code. Nothing special.
# derp
{:debug_message, _message} ->
handle_gcode(parsed, state)
{_hs, :done} ->
current = if state.current do
# cancel the timer
Process.cancel_timer(state.current.timeout)
# reply to the client
GenServer.reply(state.current.from, state.current.reply)
nil
else
state.current
end
handle_gcode(:done, %{state | current: current})
# If its not done,
{hs, code} ->
current = if (state.current || false) && (state.current.handshake == hs) do
%{state.current | reply: code}
else
state.current
end
handle_gcode(code, %{state | current: current})
# anything else just handle the code.
_ -> handle_gcode(parsed, state)
end
def handle_info({:nerves_uart, tty, str}, state) when is_binary(str) do
if tty == state.tty do
current = str |> Parser.parse_code |> do_handle(state.current)
{:noreply, %{state | current: current}}
end
end
defp handle_gcode(:dont_handle_me, state), do: {:noreply, state}
def handle_info({:nerves_uart, _tty, {:partial, _}}, s), do: {:noreply, s}
defp handle_gcode(:idle, state) do
{:noreply, state}
def handle_info({:nerves_uart, tty, {:error, error}}, state) do
Logger.error "#{tty} handler exiting!: #{error}"
{:stop, error, state}
end
defp handle_gcode(:busy, state) do
def terminate(reason, state) do
UART.close(state.nerves)
GenServer.stop(state.nerves, reason)
end
@spec do_handle({binary, any}, map | nil) :: map | nil
defp do_handle({_qcode, parsed}, current) when is_map(current) do
case handle_gcode(parsed) do
{:status, :done} ->
GenServer.reply(current.from, current.reply)
Process.cancel_timer(current.timer)
nil
{:status, status} -> %{current | status: status}
{:reply, reply} -> %{current | reply: reply}
_ -> current
end
end
defp do_handle({_qcode, parsed}, nil) do
handle_gcode(parsed)
nil
end
@spec generate_handshake :: binary
defp generate_handshake, do: "Q#{:rand.uniform(99)}"
@spec handle_gcode(any) :: {:status, any} | {:reply, any} | nil
defp handle_gcode(:idle), do: {:status, :idle}
defp handle_gcode(:busy) do
Logger.info ">>'s arduino is busy.", type: :busy
{:noreply, state}
{:status, :busy}
end
defp handle_gcode(:done, state) do
Process.sleep(100)
# when we get done we need to check the queue for moar commands.
# if there is more create a new current map, start a new timer etc.
defp handle_gcode(:done), do: {:status, :done}
# if there is nothing in the queue, nothing to do here.
if :queue.is_empty(state.queue) do
{:noreply, state}
# if there is something in the queue
else
{{str, handshake, from, millis}, q} = :queue.out(state.queue)
ref = Process.send_after(self(), {:timeout, from, handshake}, millis)
current = %{reply: nil, handshake: handshake, timeout: ref, from: from}
UART.write(state.nerves, str <> " Q#{handshake}")
{:noreply, %{state | current: current, queue: q}}
end
defp handle_gcode(:received), do: {:status, :received}
defp handle_gcode({:debug_message, message}) do
Logger.info ">>'s arduino says: #{message}"
nil
end
defp handle_gcode(:received, state) do
{:noreply, state}
end
defp handle_gcode({:debug_message, _message}, state) do
# Logger.info ">>'s arduino says: #{message}"
{:noreply, state}
end
defp handle_gcode({:report_pin_value, pin, value}, state)
defp handle_gcode({:report_pin_value, pin, value} = reply)
when is_integer(pin) and is_integer(value) do
BotState.set_pin_value(pin, value)
{:noreply, state}
{:reply, reply}
end
defp handle_gcode({:report_current_position, x_steps,y_steps,z_steps}, state) do
defp handle_gcode({:report_current_position, x_steps, y_steps, z_steps} = reply) do
BotState.set_pos(
Maths.steps_to_mm(x_steps, spm(:x)),
Maths.steps_to_mm(y_steps, spm(:y)),
Maths.steps_to_mm(z_steps, spm(:z)))
{:noreply, state}
{:reply, reply}
end
defp handle_gcode({:report_parameter_value, param, value}, state)
defp handle_gcode({:report_parameter_value, param, value} = reply)
when is_atom(param) and is_integer(value) do
unless value == -1 do
BotState.set_param(param, value)
end
{:noreply, state}
{:reply, reply}
end
defp handle_gcode({:reporting_end_stops, x1,x2,y1,y2,z1,z2}, state) do
defp handle_gcode({:reporting_end_stops, x1,x2,y1,y2,z1,z2} = reply) do
BotState.set_end_stops({x1,x2,y1,y2,z1,z2})
{:noreply, state}
{:reply, reply}
end
defp handle_gcode({:report_software_version, version}, state) do
defp handle_gcode({:report_software_version, version} = reply) do
BotState.set_fw_version(version)
{:noreply, state}
{:reply, reply}
end
defp handle_gcode({:unhandled_gcode, code}, state) do
defp handle_gcode(:error), do: {:reply, :error}
defp handle_gcode(:dont_handle_me), do: nil
defp handle_gcode({:unhandled_gcode, code}) do
Logger.warn ">> got an misc gcode #{code}"
{:noreply, state}
{:reply, code}
end
defp handle_gcode({:error, :ebadf}, state) do
{:ok, new_state} = init({state.nerves, state.tty})
{:noreply, new_state}
end
defp handle_gcode(parsed, state) do
defp handle_gcode(parsed) do
Logger.warn "Unhandled message: #{inspect parsed}"
{:noreply, state}
end
def terminate(_, _) do
Process.unregister(__MODULE__)
{:reply, parsed}
end
def flash_firmware(tty, hex_file, pid) do
@ -423,9 +260,6 @@ defmodule Farmbot.Serial.Handler do
"-Uflash:w:#{hex_file}:i"]
"avrdude" |> System.cmd(params) |> log(pid)
# handler = Process.whereis(__MODULE__)
# if handler, do: spawn fn() -> GenServer.stop(handler, :normal) end
# Farmbot.Serial.Supervisor.open_ttys(Farmbot.Serial.Supervisor, [tty])
end
defp log({_, 0}, pid) do
@ -433,9 +267,9 @@ defmodule Farmbot.Serial.Handler do
send pid, :done
end
defp log(_, pid) do
defp log(stuff, pid) do
Logger.error "FAILED TO FLASH FIRMWARE!"
send pid, :error
send pid, {:error, stuff}
end
@spec spm(atom) :: integer
@ -444,17 +278,4 @@ defmodule Farmbot.Serial.Handler do
|> String.to_atom
|> Farmbot.BotState.get_config()
end
@spec maybe_timeout({{pid, reference}, binary}, current) :: current
defp maybe_timeout({from, handshake}, current) do
# if we actually are working on the thing that this timeout was created
# for, reply timeout to it.
if (current.from == from) and (current.handshake == handshake) do
GenServer.reply(from, {:error, :timeout})
nil
else
# this was probably already finished or somthing. /shrug
current
end
end
end

View File

@ -17,6 +17,9 @@ defmodule Farmbot.Serial.Supervisor do
def init([]) do
children = [
# Here we start a task for opening ttys. Since they can change depending
# on who made the arduino, what drivers are running etc, we cant hard
# code it.
worker(Task, [__MODULE__, :open_ttys, [__MODULE__]], restart: :transient)
]
supervise(children, strategy: :one_for_all)
@ -24,20 +27,32 @@ defmodule Farmbot.Serial.Supervisor do
if Mix.Project.config[:target] != "host" do
# if runnin on the device, enumerate any uart devices and open them
# individually.
@spec open_ttys(atom | pid, [binary]) :: :ok | no_return
def open_ttys(supervisor, ttys \\ nil) do
blah = ttys || UART.enumerate() |> Map.drop(["ttyS0","ttyAMA0"]) |> Map.keys
blah |> try_open(supervisor)
case blah do
[one_tty] ->
thing = {one_tty, [name: Farmbot.Serial.Handler]}
try_open([thing], supervisor)
ttys when is_list(ttys) ->
str
|> Enum.map(fn(device) -> {device, []} end)
|> try_open(supervisor)
end
end
else
@tty Application.get_env(:farmbot, :tty, nil)
# If running in the host environment the proper tty is expected to be in
# the environment
@tty System.get_env("ARDUINO_TTY") || Application.get_env(:farmbot, :tty)
@spec open_ttys(atom | pid, [binary]) :: :ok | no_return
def open_ttys(supervisor, list \\ nil)
def open_ttys(supervisor, _) do
if @tty do
try_open([@tty], supervisor)
thing = {@tty, [name: Farmbot.Serial.Handler]}
try_open([thing], supervisor)
else
Logger.warn ">> EXPORT ARDUINO_TTY to initialize arduino in Host mode"
:ok
@ -46,26 +61,28 @@ defmodule Farmbot.Serial.Supervisor do
end
@spec try_open([binary], atom | pid) :: :ok | no_return
@spec try_open([{binary, [any]}], atom | pid) :: :ok | no_return
defp try_open([], _), do: :ok
defp try_open([tty | rest], sup) do
defp try_open([{tty, opts} | rest], sup) do
{:ok, nerves} = UART.start_link()
nerves
|> UART.open(tty, speed: @baud, active: false)
|> bleep(tty, {sup, nerves})
|> bleep({tty, opts}, sup, nerves)
try_open(rest, {sup, nerves})
try_open(rest, sup)
end
@spec bleep(any, binary, {atom | pid, atom | pid})
@spec bleep(any, binary, atom | pid, atom | pid)
:: {:ok, pid} | false | no_return
defp bleep(:ok, tty, {sup, nerves}) do
worker_spec = worker(Handler, [nerves, tty], [restart: :permanent])
defp bleep(:ok, {tty, opts}, sup, nerves) do
worker_spec = worker(Handler, [nerves, tty, opts], [restart: :permanent])
UART.close(nerves)
Process.sleep(1500)
{:ok, _pid} = Supervisor.start_child(sup, worker_spec)
end
defp bleep(_resp, _tty, {_, nerves}) do
defp bleep(resp, {tty, _opts}, _, nerves) do
Logger.error "Could not open #{tty}: #{inspect resp}"
GenServer.stop(nerves, :normal)
false
end

View File

@ -1,67 +0,0 @@
defmodule Farmbot.System.NervesCommon.Cell do
require Logger
@ssdp_fields [
location: "http://localhost:3000/myservice.json",
server: "MyServerName",
"cache-control": "max-age=1800"
]
@cell_ssdp_st "urn:nerves-project-org:service:cell:1"
@cell_ssdp_server "Nerves"
@cell_ssdp_location "/_cell/"
def setup do
config = Application.get_all_env(:nerves_cell)
Logger.info "setting up cell"
Nerves.SSDPServer.publish usn(config), @cell_ssdp_st, fields(config)
end
defp fields(config) do
[ "Server": @cell_ssdp_server,
"Location": @cell_ssdp_location,
"X-Id": board_id() || "unknown",
"X-Version": config[:version],
"X-Firmware-Stream": config[:firmware_stream] ]
|> field(:"X-Platform", platform(config))
|> field(:"X-Tags", config[:tags])
|> field(:"X-Target", config[:target])
|> field(:"X-Node", node_name())
|> field(:"X-Creation-Date", config[:creation_date], &DateTime.to_iso8601/1)
end
# if value truthy, add field with value optionally transformed by fn
@spec field(Keyword.t, atom, term, function) :: Keyword.t
defp field(fields, key, val, f \\ &(&1)) do
if val do
Keyword.put fields, key, f.(val)
else
fields
end
end
defp platform(config), do: config[:platform] || config[:app]
defp usn(config), do: "uuid:#{board_id() || "unknown"}::#{platform(config)}"
# return a board ID, or :unknown if the board ID cannot be generated
# REVIEW TODO cache in ets, move to library, handle other board types better
@lint false
defp board_id do
try do
{raw_id, 0} = System.cmd "boardid", ["-n", "6"]
String.strip(raw_id)
rescue
_ in ErlangError -> nil
end
end
# return a node id as a string if valid, else nil
defp node_name do
if Node.alive? do
Node.self
|> Atom.to_string
else
nil
end
end
end

View File

@ -21,7 +21,6 @@ defmodule Farmbot.System.NervesCommon.Network do
Process.sleep(5000)
GenEvent.add_handler(event_manager(),
Farmbot.System.NervesCommon.EventManager, [])
# Farmbot.System.NervesCommon.Cell.start_link
{:ok, %{}}
end

View File

@ -23,7 +23,9 @@ defmodule Farmbot.Serial.HandlerTest do
nil ->
Process.sleep(10)
wait_for_serial_available()
_ -> Farmbot.CeleryScript.Command.home(%{axis: "all"}, [])
_ ->
Farmbot.CeleryScript.Command.home(%{axis: "all"}, [])
Process.sleep(10)
end
end