Tutorial 2: Javelin setup and configuration

This tutorial will outline how to install, set up, and use Javelin on your computer. This will include information on the required software, a shell script to automate a lot of the setup, and examples on how to use some of the tools at Javelin's disposal including how to send a command using GraphQL.

Installation

To install Javelin, either clone the repository or download it as a ZIP file from the GitLab repository. It would also be a good idea to download the javelin-scripts repository as that contains some helpful examples that extend beyond the scope of these tutorials. You should also ensure that you have Python 3.9+, GraphQL, and GNU Radio installed as these are required for some tools. Some helpful links for these are given below.

Environment setup

There are five main steps to installing and configuring Javelin to your system. These will be outlined step-by-step below, however, they will also be placed into a shell script file which can be run directly from the main Javelin directory.

Step 1: Make the virtual environment and install requirements

1
python3 -m venv venv
2
source venv/bin/activate
3
pip install --upgrade pip
4
pip install -r requirments.txt

Step 2: Rename TLE file

1
mv ~/Documents/javelin-main/example.tle.txt ~/Documents/javelin-main/tle.txt

Step 3: Make log files

1
cd ~/Documents/javelin-main/logs
2
mkdir "commands"
3
cd ~/Documents/javelin-main/logs/commands
4
touch command.log
5
6
cd ~/Documents/javelin-main/logs
7
mkdir "control"
8
cd ~/Documents/javelin-main/logs/control
9
touch control.log
10
11
cd ~/Documents/javelin-main/logs
12
mkdir "rigctl"
13
cd ~/Documents/javelin-main/logs/rigctl
14
touch rigctl.log
15
16
cd ~/Documents/javelin-main/logs
17
mkdir "rotctl"
18
cd ~/Documents/javelin-main/logs/rotctl
19
touch rotctl.log
20
21
cd ~/Documents/javelin-main/logs
22
mkdir "kubos_ftp"
23
cd ~/Documents/javelin-main/logs/kubos_ftp/
24
mkdir "download"
25
mkdir "upload"

Step 4: Make data log directory

1
cd ~/Documents/javelin-main/data/
2
mkdir "beacon"

Step 5: Make groundstation control logs

These are separate from the logs created in step 3 and hold different information on the Groundstation control tools.
1
cd ~/Documents/javelin-main/rig_utils
2
mkdir "logs"
3
4
cd ~/Documents/javelin-main/rig_utils/logs
5
mkdir "rigctl"
6
cd ~/Documents/javelin-main/rig_utils/logs/rigctl
7
touch rigctl.log
8
9
cd ~/Documents/javelin-main/rotor_utils
10
mkdir "logs"
11
12
cd ~/Documents/javelin-main/rotor_utils/logs
13
mkdir "rotctl"
14
cd ~/Documents/javelin-main/rotor_utils/logs/rotctl
15
touch rotctl.log

Using Javelin

Javelin has four main modes of operation. This tutorial will take you through one of those modes and will give a brief explanation on the other three modes. It is recommended that a “satellite” (in this case a Beaglebone Black (BBB) running Kubos) is set up and configured to connect however it is not necessary to complete this tutorial.
To configure your “satellite”, go to the source folder and open the file titled config.py. This is where the network connection information for the “satellite” and the host machine. This file has the following structure;
Line numbersDescription
2 → 4Ground Station position (Longitude, Latitude, Altitude).
7 → 8"Satellite" Command network connection settings (IP and port number).
13 → 16File Transfer Protocol (FTP) connection settings (“Satellite IP and port, Host IP and port).
23Ground station view above the horizon.
29 → 30Radio Settings (Gain, etc).
35Setting to save local copies of the Wave files (True/False).
Along with this, you will need to update the port mapper dictionary in the source/commands/utils.py file so they match those used by your KubOS System. This is also explained in the README.

Modes of operation

As mentioned, Javelin has four main modes of operation. A brief overview of these modes is given below.

GraphQL commands over a network

This mode of motion sends GraphQL commands to the 'satellite' via a network connection. It requires you to configure the correct network settings into Javelin before operating.
This mode uses a BBB radio emulator (run on the BBB) to take messages in the CubeSat Space Protocol (CSP) packet format. This is the mode that this tutorial uses and is what the majority of examples provided in both the Javelin and Javelin Scripts repositories use.
This mode is Javelin's staging tool. It is aimed at users who have developed the applications and commands using the previous two modes of motion. A GNU radio file is provided in the flowgraphs directory of Javelin to give a generic example.

Full tracking mode

This mode is reserved for use once your satellite has been launched. The Javelin repository contains all the required tools for you to autonomously track and send data to your spacecraft.

Javelin examples

Sending a command

The first example will use the RF emulator link mode of operation to send a ping to the BBB's app service.
The first step in this process is to turn the radio emulator on. This can be done by one of the following methods. In the terminal, run the following command.
1
python3 bbb_radio_emulator/radio.py
or run the following shell script file
1
#!/bin/sh
2
3
cd ~/Documents/javelin-main
4
python3 bbb_radio_emulator/radio.py
Once our radio is on, we can build our command file that we're going to send to the satellite. Since we want to ping the app service, we're going to use a GraphQL query. We are going to have 3 attempts with a 5-second timeout on each attempt. This is structured within the text file as follows:
1
graphql app query{ping} -t 5 -r 3
To send the file, we can put this into the terminal within the javelin-main directory.
1
python3 send_cmd_script.py ~/<path_to_file>/Test_Command.txt
Our terminal will then begin to print the following:
1
[2022-07-05 06:55:22,764] - commands - INFO - cmd : {"query": "query{ping}"}, num. message sent : 0, num. bytes : 40 - message sent : 00000000002200000000000000001f407b227175657279223a202271756572797b70696e677d227d
2
[2022-07-05 06:55:22,943] - commands - INFO - message received : 0, num bytes : 86, response time : 0.178683 - message received : 00000000005000000000000000001f407b22726573706f6e7365223a202250696e672052656365697665642c2048656c6c6f20646f776e2074686572652066726f6d207468652061707020736572766963652121227d
3
[2022-07-05 06:55:22,943] - commands - INFO - Raw response data:[b'\x00\x00\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x1f@{"response": "Ping Received, Hello down there from the app service!!"}']
4
5
6
Ping Received, Hello down there from the app service!!
Let's see what happens if we get no response.
1
sending pkt b'\x00\x00\x00\x00\x00"\x00\x00\x00\x00\x00\x00\x00\x00\x1f@{"query": "query{ping}"}'
2
[2022-07-06 01:15:43,438] - commands - INFO - cmd : {"query": "query{ping}"}, num. message sent : 0, num. bytes : 40 - message sent : 00000000002200000000000000001f407b227175657279223a202271756572797b70696e677d227d
3
[2022-07-06 01:15:48,443] - commands - INFO - message received : NONE
4
[2022-07-06 01:15:48,444] - commands - ERROR - failed to receive message, sent message {"query": "query{ping}"}
5
got back b''
6
sending pkt b'\x00\x00\x00\x00\x00"\x00\x00\x00\x00\x00\x00\x00\x00\x1f@{"query": "query{ping}"}'
7
[2022-07-06 01:15:48,444] - commands - INFO - cmd : {"query": "query{ping}"}, num. message sent : 1, num. bytes : 40 - message sent : 00000000002200000000000000001f407b227175657279223a202271756572797b70696e677d227d
8
[2022-07-06 01:15:53,449] - commands - INFO - message received : NONE
9
[2022-07-06 01:15:53,450] - commands - ERROR - failed to receive message, sent message {"query": "query{ping}"}
10
got back b''
11
sending pkt b'\x00\x00\x00\x00\x00"\x00\x00\x00\x00\x00\x00\x00\x00\x1f@{"query": "query{ping}"}'
12
[2022-07-06 01:15:53,450] - commands - INFO - cmd : {"query": "query{ping}"}, num. message sent : 2, num. bytes : 40 - message sent : 00000000002200000000000000001f407b227175657279223a202271756572797b70696e677d227d
13
[2022-07-06 01:15:58,455] - commands - INFO - message received : NONE
14
[2022-07-06 01:15:58,456] - commands - ERROR - failed to receive message, sent message {"query": "query{ping}"}
15
got back b''
16
[2022-07-06 01:15:58,456] - commands - WARNING - failed to receive a response after multiple attempts.
17
cmd sent: {"query": "query{ping}"}
18
raw hex: 00000000002200000000000000001f407b227175657279223a202271756572797b70696e677d227d
19
failed to recieve a response!!
20
Command was:
21
b'\x00\x00\x00\x00\x00"\x00\x00\x00\x00\x00\x00\x00\x00\x1f@{"query": "query{ping}"}'
As we can see, there were three attempts at sending the ping message. For each attempt, our log shows that after 5 seconds, Javelin told us there was no response before sending an error message.

Ground station antenna rotation

The next examples will take us through some other tools available in the Javelin toolkit. All of these tests will be done via a local setup, however the methods and functions used will work in a remote operation case as well.
The next example will take users through the use of the antenna rotation control suite. To do this, we will split our screen into 3 sections structured the following way.
This portion of the screen will hold a terminal window. From here, we can run our dummy ground station antenna which can be found in the javelin-main/scripts directory under start_rotctl_dummy.sh.In the final portion of the screen, we can run our set position function. This script forms a continuous loop which takes terminal inputs for the new azimuth and elevation. To exit the loop, simply type "no" when prompted to set a new position. The script for this file has been provided at the end of this tutorial along with the other additional resources.
Underneath the dummy, we can run the monitor position script. This can be found in the javelin-main/rotor_utils/rotctl directory under monitor_position.sh. This script connects to the dummy and returns the ground station's azimuth and elevation at 5 second intervals
When running all of these, starting with the dummy, followed by the position monitor and finally running the position setting loop, the screen should look similar to the following.

Conclusion

Congratulations, this completes the second tutorial. The next tutorial will focus on configuring both Scepter and Javelin to communicate with each other and allow us to form the first link in our engineering workbench.

Additional resources

List of required directories and files for manual creation

  • .../javelin-main/logs/commands/command.log
  • .../javelin-main/logs/control/control.log
  • .../javelin-main/logs/rigctl/rigctl.log
  • .../javelin-main/logs/rotctl/rotctl.log
  • .../javelin-main/logs/kubos_ftp/download
  • .../javelin-main/logs/kubos_ftp/upload

GraphQL command file input format

Below is a script that shows off some commands and provides some code to help users get started.
1
def add_service_ping(fileID, service2ping, timeout=5, retry=3):
2
fileID.write('graphql ')
3
fileID.write('%s ' % service2ping)
4
fileID.write('query{ping} -t %s -r %s\n' % (str(timeout), str(retry)))
5
6
7
def add_delay(fileID, time_of_delay):
8
fileID.write('delay ')
9
fileID.write('%s\n' % str(time_of_delay))
10
11
12
def add_comment(fileID, comment_string):
13
fileID.write('# %s\n' % comment_string)
14
15
16
# Create New Command File or Append old one
17
fid = open('Test_Command.txt', 'w')
18
19
# add header as comment
20
header = 'This file contains examples of commands to send to Javelin'
21
add_comment(fid, header)
22
23
# add ping with default timeout and retries
24
service_to_ping = 'app'
25
add_service_ping(fid, service_to_ping)
26
27
# add a delay
28
delay_time = 2
29
add_delay(fid, delay_time)
30
31
# add ping with custom default and retries
32
time = 1 # ensure both variables are integers
33
retries = 4
34
add_service_ping(fid, service_to_ping, time, retries)
35
36
# Close File
37
fid.close()
This code creates a file named Test_Command.txt which is displayed below:
1
# This file contains examples of commands to send to Javelin
2
graphql app query{ping} -t 5 -r 3
3
delay 2
4
graphql app query{ping} -t 1 -r 4

Javelin installation file

This shell script is also provided in the support code for this tutorial.
1
#!/bin/sh
2
3
# This is a shell script file that will set up Javelin ready for use as per
4
# OSSO Tutorial 2: Javelin Setup and Configuration.
5
6
# To run this script, install the Javelin-main directory from Gitlab and ensure this
7
# script is copied into the root directory. From there, either run this script
8
# through your IDE or in the terminal.
9
10
# Step 1: Make the virtual environment and install the requirements.
11
python3 -m venv venv
12
source venv/bin/activate
13
pip install --upgrade pip
14
pip install -r requirements.txt
15
16
# Step 2: Copy example.tle.txt to Javelin-main and rename as tle.txt
17
# Alternatively, rename the file
18
mv ~/Documents/javelin-main/example.tle.txt ~/Documents/javelin-main/tle.txt
19
20
# Step 3: Make Log directories
21
cd ~/Documents/javelin-main/logs
22
mkdir "commands"
23
cd ~/Documents/javelin-main/logs/commands
24
touch command.log
25
cd ~/Documents/javelin-main/logs
26
mkdir "control"
27
cd ~/Documents/javelin-main/logs/control
28
touch control.log
29
cd ~/Documents/javelin-main/logs
30
mkdir "rigctl"
31
cd ~/Documents/javelin-main/logs/rigctl
32
touch rigctl.log
33
cd ~/Documents/javelin-main/logs
34
mkdir "rotctl"
35
cd ~/Documents/javelin-main/logs/rotctl
36
touch rotctl.log
37
cd ~/Documents/javelin-main/logs
38
mkdir "kubos_ftp"
39
cd ~/Documents/javelin-main/logs/kubos_ftp/
40
mkdir "download"
41
mkdir "upload"
42
43
# Step 4: Make data log directory
44
cd ~/Documents/javelin-main/data/
45
mkdir "beacon"
46
47
# Step 5: Make Groundstation control logs (for rotctl and rigctl). These are
48
# separate from those made in Step 3
49
cd ~/Documents/javelin-main/rig_utils
50
mkdir "logs"
51
cd ~/Documents/javelin-main/rig_utils/logs
52
mkdir "rigctl"
53
cd ~/Documents/javelin-main/rig_utils/logs/rigctl
54
touch rigctl.log
55
cd ~/Documents/javelin-main/rotor_utils
56
mkdir "logs"
57
cd ~/Documents/javelin-main/rotor_utils/logs
58
mkdir "rotctl"
59
cd ~/Documents/javelin-main/rotor_utils/logs/rotctl
60
touch rotctl.log

Ground station rotation setter

Below is the script containing the loop used in the ground station antenna rotation example. This was created using Python 3.9+. The file paths in this will need to be updated to match those on your device.
1
# This script is used to streamline the groundstation rotation control tools
2
3
# Import Packages
4
import os
5
from subprocess import run
6
7
8
def set_rot_pos(azimuth: int, elevation: int):
9
os.chdir("<path_to_javelin>/javelin-main/rotor_utils/")
10
run(["python3", "set_position.py", str(azimuth), str(elevation)])
11
os.chdir("<path_to_orginal_working_directory>")
12
13
14
new_position_check = True
15
while new_position_check:
16
new_azimuth = input('Input new Azimuth (deg): ')
17
new_elevation = input('Input new Elevation (deg): ')
18
set_rot_pos(azimuth=int(new_azimuth), elevation=int(new_elevation))
19
new_position_check = input('Set New Position: ')
20
if new_position_check == "no":
21
new_position_check = False
22
else:
23
new_position_check = True