- Muchas notas - Fran Acién

20240307 - OBC - Workshop 1 - Building and sending telemetry

The objective of this guide is to:

  • Power on the OBC
  • Login to the OBC
  • Create simulated telemetry
  • Send telemetry to the COMMS
  • Receive simulated telemetry

Power the OBC

Over the connectors or over the EPS subsystem.

Make sure it is running the last image of the OBC.

Login to the OBC

Login: root Password: root

Simulated telemetry generation

The next script is under /home/obc/scripts/01_sim_telemetry_gen.py:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""

This example will create a dummy packet with telemetry using CCSDS

"""

#%% Import libraries

import time
import can

from construct import BitStruct, BitsInteger, Padding, Struct, Float32l

from construct import Int16ul, Int8ul


#%% Define structures of CCSDS packet

# Define primary header of CCSDS
CCSDS_PRIM_HEADER = BitStruct(
  "version" / BitsInteger(3),
  "type" / BitsInteger(1),
  "sec_header_flag" / BitsInteger(1),
  "proc_id" / BitsInteger(11),
  "seq_flags" / BitsInteger(2),
  "seq_cnt" / BitsInteger(14),
  "length" / BitsInteger(16)
  )

# Define a dummy sensor data
SENSOR_DATA = Struct(
  "temp" / Float32l,
  "preassure" / Float32l,
  "altitude" / Float32l,
  "humidity" / Float32l
)

# Define our sample CCSDS packet
CCSDS_SAMPLE_PACKET = Struct(
  "header" / CCSDS_PRIM_HEADER,
  "data" / SENSOR_DATA
  )

#%% Populate the packet with some data

ccsds_prim_header_dict = dict(
  version = 0b1,
  type = 0b0,
  sec_header_flag = 0b0,
  proc_id = 0b1,
  seq_flags = 0b11,
  seq_cnt = 0b0,
  length = SENSOR_DATA.sizeof() + CCSDS_PRIM_HEADER.sizeof() - 1  # Length is calculated based on the lenght of the packet
  )

sensor_data_dict = dict(
  temp = 22.05,
  preassure = 101.2,
  altitude = 666,
  humidity = 98.125
  )

# Build the telemetry packet

sensor_data = SENSOR_DATA.build(sensor_data_dict)
ccsds_packet= CCSDS_SAMPLE_PACKET.build(dict(
  header = ccsds_prim_header_dict,
  data = sensor_data_dict
  ))

#%% Print the hex value of the packet

print("Sending CCSDS packet with the content: {}".format(ccsds_packet.hex()))


#%% We need to create a CFP packet in which we encapsule the CCSDS packet

# First define the CFP structures

CAN_CFP_ID = BitStruct(
  Padding(3),
  # Padding of 3 bits to be multiple of 8, 
  # discarted when adding to can message
  "source" / BitsInteger(5),
  "destination" / BitsInteger(5),
  "type" / BitsInteger(1),
  "remain" / BitsInteger(8),
  "id" / BitsInteger(10)
  )

#%%

# Create a function to send CFP packets

CAN_MAX_LENGTH = 8  # Max number of bytes in a message of CAN

CFP_BEGIN = 0b0
CFP_MORE = 0b1

# CFP Some variables

SOURCE = 0
DESTINATION = 1 # COMMS
ID = 63 # Sample id

# Define CAN bus

bustype = 'socketcan'
channel = 'can0'

bus = can.Bus(channel=channel, interface=bustype)

def send_CCSDS(ccsds_packet):
  # Create a message and send it using CFP
  num_packets = (len(ccsds_packet) - 1) // CAN_MAX_LENGTH + 1
  remain = num_packets - 1

  # Send the first frame
  cfp_id_dict = dict(
    source = SOURCE,
    destination = DESTINATION,
    type = CFP_BEGIN, # BEGIN
    remain = remain,
    id = ID # Sample identifier
    )

  cfp_id = CAN_CFP_ID.build(cfp_id_dict)

  start = 0 # We start at 0
  end = min(start + CAN_MAX_LENGTH, len(ccsds_packet))
  print("Sending from {} to {}, remain {}".format(start, end, remain))

  # Send first packet
  msg = can.Message(arbitration_id=int.from_bytes(cfp_id, 'big'), data=ccsds_packet[start:end], is_extended_id=True)
  bus.send(msg)

  while(remain > 0):
    remain -= 1 # We are sending a new one
    
    # Send the first frame
    cfp_id_dict = dict(
      source = SOURCE,
      destination = DESTINATION,
      type = CFP_MORE, # BEGIN
      remain = remain,
      id = ID # Sample identifier
      )

    cfp_id = CAN_CFP_ID.build(cfp_id_dict)

    start = end
    end = min(start + CAN_MAX_LENGTH, len(ccsds_packet))
    print("Sending from {} to {}, remain {}".format(start, end, remain))

    # Send first packet
    msg = can.Message(arbitration_id=int.from_bytes(cfp_id, 'big'), data=ccsds_packet[start:end], is_extended_id=True)
    bus.send(msg)
  bus.shutdown() # Close bus

#%% 

# Send our packet over CAN with CFP

send_CCSDS(ccsds_packet)

After connecting the uCAN the output should be something like:

$ candump can0
can0  0008083F   [8]  20 01 C0 00 00 15 66 66
can0  000C043F   [8]  B0 41 66 66 CA 42 00 80
can0  000C003F   [6]  26 44 00 40 C4 42

Connect the COMMS

The destination of our CAN packet is the COMM subsystem, which its unique task is to relay all the incoming information over LoRa.

The steps are:

  • Connect the comms
  • Connect the Ground LoRa Receiver

The LoRa receiver act as a relay from LoRa to UART, so it can be received by the computer. Connect to the serial and the output should look something like this:

�ff�Aff�B�&D@�B::+1.*sc

We receive the information. But is in binary we are not able to understand it :/