SPLICE: The Programming Language for Extraterrestrial Applications


As previously discussed, Java, C, and C++ are already perfectly capable tools for writing aerospace-grade software, while Rust programming language is an interesting new candidate that can combine the advantages of the previous generation of programming tools while discarding their drawbacks. However, if one wants to create space-based software development platform for a wider audience than ever before, one needs a solution that combines both ease of use with sufficient robustness for mission-critical applications in a demanding environment. Given below is the summary of requirements for such a programming language and proposed implementation for this requirement set, which will be tested on-board ESA OPS-SAT mission: https://www.esa.int/Enabling_Support/Operations/OPS-SAT


  • Suitable for real-time applications. A typical mission for the satellite in space may consist of the performing a set of imaging observations of the ground below, with specific set for exposure values and wavelength filters selection. It needs to precisely timed or otherwise made conditional on other mission parameters (satellite orbital position and attitude orientation) to be performed successfully. 
  • RobustnessReality of space environment often interferes with the above plans: a satellite may be in dangerously low power state, satellite camera may face into the wrong direction or satellite onboard computer can tripped into reboot by a stray particle. Satellite hardware resources can be limited and not every downlink session will allow mission data to be downloaded. Therefore, its runtime environment has to be smart when it comes of task execution and storage of results and data.
  • Data-centricWhen editing and transferring instrument data and telemetry parameters to and from different satellite subsystems and uplink/downlink channels, one need good tools for aggregation, abstraction and marshaling of data, from individual bits to multi-megabyte imagery data. Any satellite instrument or component is expected to have some parameters or variables that can be either read and written to (like imaging camera exposure) or only read from (temperature sensors, very commonly). It would be useful to represent this difference in their declaration syntax and also check the validity of operations done upon them before the execution
  • Portability. The cost of software development for satellite missions comes from the need to qualify the software in the space, that is to run under realistic scenarios onboard the real satellite in space environment conditions. Therefore, it makes sense to compile source code not to target platform directly, but to some intermediate representation that be reused on multiple satellite hardware platforms, following the original Java “write once, run everywhere” promise. 
  • Simplicity. Finally, the last aspect of proposed specification of language is about not what to include into its feature set, but what to exclude from it. Available development tools should allow the developers to interact with the most interesting parts of the satellite – its instruments and instrument-generated data while offloading all the work necessary for satellite survival, such as power management as well as specifics of real-time systems outside of user scope as much as possible. 

Core Design Concepts

Space Programming Language Interpreter & Command Environment or SPLICE is a domain- specific programming language that enables development of software applications tailored for the conditions of space environment. It is explicit at what should be done but does not specify how execution of the program should be done, leaving that to execution runtime. 

Its major programming constructs are tasks and queues, inspired by the real-time operating systems like VxWorks or FreeRTOS that are often used as execution platforms for satellite mission software. Note that other elements of real-time systems, like interrupts or priorities are not exposed directly to users and are managed implicitly, within the language runtime, to reduce the complexity of software development for the users.

Tasks are lists of actions, that are specified to be executed either at given intervals or on certain conditions, specified by the following qualities:

  • How often they are run, either once only or within intervals between repeated execution defined in time range (1 second, 1 minute or 1 hour), only once or as fast as the task scheduler allows. 
  • When they are triggered to run – either unconditionally after fixed time intervals or conditionally bound by external (measured environment parameter value) or internal state (a successful execution of prerequisite task). 
  • What exactly are they doing – command the instruments or perform necessary calculations with the data values received.

Task lifetime is described through a following diagram:

Queues represent the major building I/O block, such instrument command queues, uplink or downlink channels or persistent/temporary data storage, specified by the following:

  • Interface description of the source or the destination of the data flow, specifying property type, command or telecommunication data packet format.
  • Read or write availability, as some queues, for example connected to telemetry sensors can only provide read-only functionality, and some such as ones of communication subsystem can offer both read and write functions.
  • Queues can be either persistent, saving their intermediate state to the persistent storage (such underlying file location) or ephemeral, discarding it between the execution runs.
  • As both ephemeral and persistent memory is a finite resource, queues also need to define maximum number of data elements stored internally and shedding behaviour – what to do when amount of data being written into the queue exceeds its internal storage capabilities. Shedding behaviour can be defined as “newest element gets discarded first” or “oldest element gets discarded first”, depending on the operational needs. 

Multiple tasks can be grouped into groups and queues into instruments, for better program structure and user convenience. To ensure deterministic behaviour, loops and control flow constructs are provided only at the task level, simplifying the logic of program execution.

4. SPLICE Syntax Examples

Let’s now have a look at the proposed syntax through some SPLICE program examples. Most of the syntax examples below should be self-explanatory for any software developer exposed to the commonly used programming languages. Most of syntax constructs are borrowed from C-derived languages, including Python, Rust and C++.

/* Comments are the same as in C-derived languages, both for single and multiline types */

/* Types declaration use Rust-like syntax */

//32-bit signed integer
var an_integer:i32

//8-bit unsigned integer
var unsigned_int:u8;
//single-precision float
var a_float:f32;    

/* variables can be initialized at declaration, for cardinal types initialization is optional though */
var initialized_integer:i32 = 0; 

/* strings are always allocated statically and has to be always initialized at declaration */
var a_string:string=”a string value”; 
/* constants declaration examples */
//floating point example
const PI:f32 = 3.14;

//integer constant
const TASK_OK:i32 = 0;

//and a string one
const INFO:string = “a string constant”;

/* Custom type declarations */

//complex types can be assembled from built-in ones
type TPacket {
      header: u32;
      data_a: f32;
      data_b: f32;
      data_c: f32;
//type declarations can use nested complex types 
type TCommand {
      uid: i32;
      command: string;
      data: TPacket;

//variables of complex types can be declared as well
var packet:TPacket;

// ..and initialized, when necessary or desired so
// but for some of the fields initialization can be optional
var packet:TCommand = {
      command: ”Command string”,
      data: {
// constants can be of custom type as well
const TEST_PACKET:TPacket = {
      header:0, data_a:0.0, data_b: 0.0, data_c:0.0

/* Instrument declarations – semantically they are interfaces */
//a simple instrument example – GPS receiver
inst gps 
      //”prop” keyword indicates read-only value
      prop lat:f32;
      prop lon:f32;
      prop alt:f32;
      //can be turned on/off from user programs
      var powered:bool;

/* UHF transceiver instrument example. Note the use of queues, as being in a ground station view is required to send or receive any data */
inst uhf_comms
      //NOT safe to turn it off
      prop powered:bool;      
      queue downlink {
            size: 100;
            type: TPacket;
            // shedding modifer, as explained above
            shed: “last”;
            // access modifier: “push” is write-only
            accs: push;
      queue uplink {
            size: 100;
            type: TPacket;
            //access modifier: “pull” is read-only
            accs: pull;     
/* another example – taken from actual satellite mission */
inst camera 
      var exposure:f32;
      var gainR:f32; 
      var gainB:f32; 
      var gainG:f32;
      //can be turned on or off safely
      var powered:bool;
      prop imageCount:u32;
      queue commands
            size: 10;
            type: TCommand;
            accs: push; 
            shed: “last”; 
/* task and groups declarations examples: in the most basic case, a list of actions to be executed under certain conditions and with specific execution frequency. groups are collections of tasks, where all tasks has visibility of each other execution results and local data in read-only mode*/ 
group task_group_1  
       task task_1 { 
              //tasks can have their own variables and constants
              data {
                     var lat:f32=32.21;
                     var lon:f32=120.1;
                     const ADCS_MODE_NADIR = 5;
                     var target_mode: TADCSMode = {
                            mode_id: ADCS_MODE_NADIR,               
                            duration: 300s
              /* frequency of execution, can be "once",
              “always” or time value in seconds */ 
              freq: “once”;    
              /* prerequisite section, statements below 
              has to be true to allow execution */ 
              preq {
                     gps.lat == lat;
                     gps.long == lon;

              /* executive section - the actual actions 
              and logic of the task. Task execution result is 
              saved after task execution and updated after each 
              run, so it can be used for other tasks as 
              prerequisite */
              exec {
                    //pushing a command to subsystem queue
                    return TASK_OK;
       /* one task can read another task data (from the 
       same group), but not write to. Variables, constants 
       or queues can be used for data transfer between tasks */       
       task task_2 { 
              data {
                const NX:i32=task_1.ADCS_MODE_NADIR;
                var gainR:f32=1.0; 
                var gainB:f32=0.5;
                var gainG:f32=0.5; 
                var exp:f32=0.1; 
                var cam_commd:TCommand; 
              /* time literals have prefix as “s”,”m”,”h” and so        
              on, depending on mission needs */ 
              freq: 60s;    
              /* task execution result can be a prerequisite too,        
              in addition to conditional expression */           
              preq {
                     adcs.mode == NX;                  
                     task_1.result == TASK_OK;
              /* There can be no loops or conditional 
              expressions in the execution section – just a list
              of statements */
              exec {
                     cam_commd.uid =1;              
                     cam_commd.command = “RAW”;                
                     cam_commd.data_a = gainR;                                   
                     cam_commd.data_b = gainB;
                     cam_commd.data_c = gainG;   
                     /* instruments can be controlled through 
                     command queues or by directly editing their                   
                     parameters */
                     camera.exposure =0.2;                    
                     /* task context, including local data is 
                     saved between runs, allowing complex                      
                     execution logic */
                     gainR = gainR + 1.0; 
                     gainB = gainB + 0.5; 
                     gainG = gainG + 0.1;
                     return TASK_OK;

Progress To Date

At the moment, the current implementation of SPLICE only exists as intermediate representation in VM bytecode and simple assembly language, with most of high-level syntax is not yet fully defined and many planned features still undergoing internal discussion. 

Undoubtedly, as we gain experience through orbital operations later in 2020 and learn more from both successes and mistakes, both specifications and implementation will evolve and improve, adding more features to allow more interesting applications. Going forward into our next satellite mission, we plan to implement a fully featured software development kit, including high-level compiler and satellite ground simulator as well as allowing deployment of user programs onboard our own crowd-flyable mission – NOVA, to be launched later this year. Keep in touch with us on social media  to follow our progress and send us feedback and comments!

New Year Greetings from Exodus Orbitals!

Our journey this year has been dramatic and eventful, and we finish 2019 on an upward trajectory. As the NewSpace industry gains momentum, 2020 promises to deliver even more technological breakthroughs from both large and small players.

Exodus Orbitals is on track to develop one such breakthrough – an entirely new approach for satellite software applications. Our solution will allow a much wider community to actively participate in space exploration. We are proud of our progress to date and we want to thank everyone who has helped us on our journey.

Happy New Year 2020!

NOVA Mission: Risk Mitigation, Part II

Beyond the standard technical risks for space exploration missions, there is also a financial challenge. Space is a capital-intensive domain, with satellite, launcher, and ground infrastructure factoring in to the total bill. For a small start-up, any unforeseen disaster can potentially bankrupt the company, so one has to prepare for that kind of scenario. In short, one must maximise odds of mission success, while minimising the total cost of the mission.

Let’s review what actions can be taken:

Satellite Design and Manufacture – In-house or Outsourced?

Even with a small team, it is possible to build a CubeSat; it has already been attempted multiple times. However, the odds of building a CubeSat and it operating successfully on a first try is not that great. By looking at the history of CubeSats [our podcast link] built by various teams, the odds of success are ~50%. Many nanosatellite teams succeeded only on later missions. Fortunately, there are now nanosatellite vendors with a proven track record, that can build a CubeSat to order, giving the customer a significantly better chance of making it past the deployment phase successfully on a first attempt. Exodus Orbitals will take this route, opting to review proposals from various vendors to select the one with the best offer. In-house construction may save a company money in the short-term, but our view is that such gains are not worth the risk of mission failure.

Launcher Selection – New or Existing Providers?

As with the small satellite industry, there is now a boom in the launcher market, with hundreds of companies now competing to bring their own solutions to fruition. Right now, the only such company that has succeeded is RocketLab, but by 2020 the market should see many more companies gaining orbital capability. Being the pilot customer on a new launcher extremely risky; a successful first mission here is an exception, not the rule. New launch providers frequently offer a considerable discount on the launch price, but again our view on this matter is that the risk is simply too high.

Ground Infrastructure – Rented or Fully-Owned?

A fully-owned ground station setup can provide a lot of value for multiple missions, but there is a large upfront expense. For satellites operating on amateur radio frequencies, one can rely on the many volunteers across the globe to obtain downlink telemetry. However, for commercial activities, a ground-station is absolutely required for both the uplink and downlink data. Fortunately, there are now “ground station-as-a service” companies, offering their facilities for both purposes on a pay-per-use model, reducing the initial costs required. This is what we plan to use, and we are already in talks with a number of these vendors in preparation for our first mission.

NOVA Mission: Risk Mitigation, Part I

Space missions of all kinds have been lost because of software errors, including those engineered by experienced teams from the largest space agencies in the world; well-funded interplanetary probes such as ESA’s Schiaparelli and NASA’s Mars Climate Orbiter are but two examples.

Much smaller teams with intentions of launching a CubeSat will have to deal with the same degree of space environment challenges, plus many additional risks originating from allowing an amateur user to run code on a satellite’s onboard computer.  Therefore, it is important to describe what risks we are going to face, and the preventive measures we are going to take to optimise the odds of mission success. They can be roughly grouped into mission risks and business risks. Firstly, we will talk about mission-specific risks and their mitigation. 

Mission Risks

Running code written by people without extensive prior experience in space software development is the largest challenge we face in developing a mission of this kind, in addition to the usual risks that come with CubeSat development.

…and Possible Countermeasures

The core concept of our solution is the implementation of multiple layers of software and hardware guards as well as operational procedures, forming a defence-in-depth strategy to reduce the risk of premature mission termination.

  • First and foremost, the design of our satellite in general, on-board data handling, and the commands subsystem will follow current practices in nanosatellite design and construction. We plan to utilize flight-proven parts from existing nanosatellite vendors to reduce any unforeseen risks and leverage the reliability of flight heritage solutions.
  • Secondly, our onboard data-handling and command system will be split into primary and secondary partitions, where the primary partition will act as a supervisor with priority in commanding the satellite subsystems and can override user code execution on the secondary partition. The mission software and operating system on the primary will be selected or designed by our team and will not be accessible or overwritable by our satellite users.
  • Thirdly, a degree of flight envelope protection will be implemented for the mission software – runtime environment on host operating systems will provide safety checks and threshold limits for potentially dangerous user command sequences.

As the primary operational precaution, before any user code will run in space, it has to pass the comprehensive test procedures on the ground, from basic sanity checks to predictive analysis of the satellite behaviour using “digital twin”, synced with the real satellite using real-time telemetry. In the case of mission-critical emergencies the secondary on-board computer running misbehaving user code will be powered-off, either through command from the ground station or by autonomous decision-making of the primary on-board computer.

Technical solutions are not the only actions we should be using. There is no substitute for experience, and the moment we will be able to secure sufficient funding to start our mission design, we will be hiring people with experience in nanosatellite mission design and operation: system engineers, electrical and mechanical engineers, software developers and orbital mechanics experts. A lot of necessary answers will be obtained during our collaboration with ESA’s OPS-SAT mission, to be launched in just a few days, on December 17, 2019, so we will not be operating in the blind when the time comes for our own mission in late 2020.

In our next update we will describe the potential business risks and our approach to minimise them. 

NOVA Mission Goals

The primary goal of our mission, NOVA, is to radically lower the entry barrier for parties and people interested in conducting their own research and projects in space.

Currently, it requires an incredible amount of time and effort to deploy and operate any kind of instrument in space, even on the smallest possible satellite, and the mission payload is accessible to the few, not the many.

NOVA will create numerous opportunities for both companies and individuals alike, opening up the doors to space for people that previously could not afford access to this type of technology. 

What we can offer in the long run is a “satellite-as-a-service” system, with our space and ground infrastructure becoming a revolutionary new development platform. NOVA is a proof of concept, that if successful, will become a precursor to an untold number of missions with diverse payload types and features available for customers to utilise.

Examples of potential instruments include:

  • AIS and ADS-B receivers
  • Laser and SDR transceivers for IoT connectivity
  • Earth observation cameras
  • Astronomical observation cameras
  • Particle detectors

Universities will be able to grant their students access to a software development platform that operates in the space environment, giving them direct experience with real satellite hardware and satellite operations. The system could also be used as a qualification and test platform for high-risk/high-impact projects from existing aerospace businesses.

These are but a few examples.

NOVA will unlock an almost endless list of possibilities that we are excited to anticipate.