From 3685e71b4ebfdf8406e0c9f0829d6d409271a4e3 Mon Sep 17 00:00:00 2001 From: Minahil Raza Date: Tue, 3 Sep 2024 20:21:50 +0000 Subject: [PATCH] Add JAXA Bridge Demo (fixes space-ros#26) --- jaxa_integration/Dockerfile.jaxa_spaceros_cfs | 71 +++++ .../Dockerfile.jaxa_spaceros_listener | 23 ++ jaxa_integration/README.md | 135 +++++++++ jaxa_integration/build.sh | 26 ++ .../cfs_app/sample_talker/CMakeLists.txt | 15 + .../fsw/mission_inc/sample_talker_perfids.h | 7 + .../fsw/platform_inc/sample_talker_msgids.h | 9 + .../fsw/src/RACS2Brdige_std_msgs.pb-c.c | 261 ++++++++++++++++++ .../fsw/src/RACS2Brdige_std_msgs.pb-c.h | 139 ++++++++++ .../sample_talker/fsw/src/racs2_user_msg.h | 22 ++ .../sample_talker/fsw/src/sample_talker.c | 261 ++++++++++++++++++ .../sample_talker/fsw/src/sample_talker.h | 39 +++ .../fsw/src/sample_talker_events.h | 13 + .../sample_talker/fsw/src/sample_talker_msg.h | 36 +++ .../fsw/src/sample_talker_version.h | 9 + jaxa_integration/images/architecture.png | Bin 0 -> 31553 bytes .../RACS2Bridge_std_msgs_pb2.py | 166 +++++++++++ .../jaxa_comm_spaceros/__init__.py | 0 .../jaxa_canadarm_listener.py | 117 ++++++++ .../jaxa_comm_spaceros/jaxa_rover_listener.py | 98 +++++++ .../jaxa_simple_listener.py | 92 ++++++ .../jaxa_comm_spaceros/package.xml | 18 ++ .../resource/jaxa_comm_spaceros | 0 jaxa_integration/jaxa_comm_spaceros/setup.cfg | 4 + jaxa_integration/jaxa_comm_spaceros/setup.py | 28 ++ .../jaxa_comm_spaceros/test/test_copyright.py | 25 ++ .../jaxa_comm_spaceros/test/test_flake8.py | 25 ++ .../jaxa_comm_spaceros/test/test_pep257.py | 23 ++ jaxa_integration/racs2_msg/CMakeLists.txt | 38 +++ .../racs2_msg/msg/RACS2UserMsg.msg | 11 + jaxa_integration/racs2_msg/package.xml | 22 ++ jaxa_integration/run_jaxa_spaceros_cfs.sh | 10 + .../run_jaxa_spaceros_listener.sh | 10 + 33 files changed, 1753 insertions(+) create mode 100644 jaxa_integration/Dockerfile.jaxa_spaceros_cfs create mode 100644 jaxa_integration/Dockerfile.jaxa_spaceros_listener create mode 100644 jaxa_integration/README.md create mode 100755 jaxa_integration/build.sh create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/CMakeLists.txt create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/mission_inc/sample_talker_perfids.h create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/platform_inc/sample_talker_msgids.h create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/RACS2Brdige_std_msgs.pb-c.c create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/RACS2Brdige_std_msgs.pb-c.h create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/racs2_user_msg.h create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker.c create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker.h create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_events.h create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_msg.h create mode 100644 jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_version.h create mode 100644 jaxa_integration/images/architecture.png create mode 100644 jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/RACS2Bridge_std_msgs_pb2.py create mode 100644 jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/__init__.py create mode 100644 jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_canadarm_listener.py create mode 100644 jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_rover_listener.py create mode 100644 jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_simple_listener.py create mode 100644 jaxa_integration/jaxa_comm_spaceros/package.xml create mode 100644 jaxa_integration/jaxa_comm_spaceros/resource/jaxa_comm_spaceros create mode 100644 jaxa_integration/jaxa_comm_spaceros/setup.cfg create mode 100644 jaxa_integration/jaxa_comm_spaceros/setup.py create mode 100644 jaxa_integration/jaxa_comm_spaceros/test/test_copyright.py create mode 100644 jaxa_integration/jaxa_comm_spaceros/test/test_flake8.py create mode 100644 jaxa_integration/jaxa_comm_spaceros/test/test_pep257.py create mode 100644 jaxa_integration/racs2_msg/CMakeLists.txt create mode 100644 jaxa_integration/racs2_msg/msg/RACS2UserMsg.msg create mode 100644 jaxa_integration/racs2_msg/package.xml create mode 100755 jaxa_integration/run_jaxa_spaceros_cfs.sh create mode 100755 jaxa_integration/run_jaxa_spaceros_listener.sh diff --git a/jaxa_integration/Dockerfile.jaxa_spaceros_cfs b/jaxa_integration/Dockerfile.jaxa_spaceros_cfs new file mode 100644 index 00000000..c41b3416 --- /dev/null +++ b/jaxa_integration/Dockerfile.jaxa_spaceros_cfs @@ -0,0 +1,71 @@ +# ----------------------------------------------------------------------------- +# Dockerfile for setting up an environment with Space ROS and cFS +# Author: Minahil Raza +# Date: minahilrz@gmail.com +# ----------------------------------------------------------------------------- + +FROM osrf/space-ros:latest + +# Set environment variables +ENV JAXA_BRIDGE_DIR=/tmp/racs2_bridge +ENV CFS_DIR=${HOME_DIR}/cfs + +# Install dependencies for the ROS - cFS bridge +RUN sudo apt-get install -y libwebsockets-dev protobuf-c-compiler libprotobuf-c-dev python3-pip git \ + && pip3 install protobuf websockets + +# Set working directory and clone the JAXA bridge repository +WORKDIR ${HOME_DIR} +RUN git clone https://github.com/jaxa/racs2_bridge ${JAXA_BRIDGE_DIR} + +# Prepare cFS + +## Clone cFS repository +RUN git clone --recursive -b v6.7.0a https://github.com/nasa/cFS/ ${CFS_DIR} +WORKDIR ${CFS_DIR} +RUN git submodule init \ + && git submodule update + +## Customize cFS to run the bridge +RUN cp cfe/cmake/Makefile.sample Makefile \ + && cp -r cfe/cmake/sample_defs sample_defs \ + && cp -pr ${JAXA_BRIDGE_DIR}/cFS/Bridge/Client_C/apps/racs2_bridge_client ${CFS_DIR}/apps/ + +# Uncomment the following line if you only want the bridge and not the sample app. +# RUN cp -p ${JAXA_BRIDGE_DIR}/cFS/Bridge/Client_C/sample_defs/* ${CFS_DIR}/sample_defs/ + +## Deploy the sample talker application and adjust the startup scripts +RUN cp -pr ${JAXA_BRIDGE_DIR}/Example/Case.1/cFS/sample_defs/* ${CFS_DIR}/sample_defs/ +COPY ./cFS_app_examples/space_robots/cfs_app/sample_talker ${CFS_DIR}/apps/sample_talker + +## Adjust settings for running cFS inside Docker +RUN sed -i -e 's/^#undef OSAL_DEBUG_PERMISSIVE_MODE/#define OSAL_DEBUG_PERMISSIVE_MODE 1/g' sample_defs/default_osconfig.h \ + && sed -i -e 's/^#undef OSAL_DEBUG_DISABLE_TASK_PRIORITIES/#define OSAL_DEBUG_DISABLE_TASK_PRIORITIES 1/g' sample_defs/default_osconfig.h \ + && sed -i -e 's/^wss_uri=.*/wss_uri=127.0.0.1/g' sample_defs/racs2_bridge_config.txt + +## Compile cFS +RUN make SIMULATION=native prep \ + && make \ + && make install + +# Prepare ROS packages + +## Create ROS workspace +WORKDIR ${HOME_DIR} +RUN mkdir -p ros2-project/src + +## Copy bridge and example packages into the workspace +RUN cp -pr ${JAXA_BRIDGE_DIR}/ROS2/Bridge/Server_Python/bridge_py_s ${HOME_DIR}/ros2-project/src/ +COPY ./racs2_msg ${HOME_DIR}/ros2-project/src/racs2_msg + +## Compile and install ROS 2 packages +WORKDIR ${HOME_DIR}/ros2-project +SHELL ["/bin/bash", "-c"] +RUN source ${HOME_DIR}/spaceros/install/setup.bash && colcon build --symlink-install + +## Adjust configuration for the JAXA bridge (IPv4 settings) +RUN sed -i -e 's/wss_uri:.*/wss_uri: "127.0.0.1"/g' ./src/bridge_py_s/config/params.yaml + +# Set the default shell in screen to bash +RUN echo "defshell -bash" > ${HOME_DIR}/.screenrc + diff --git a/jaxa_integration/Dockerfile.jaxa_spaceros_listener b/jaxa_integration/Dockerfile.jaxa_spaceros_listener new file mode 100644 index 00000000..e231fb66 --- /dev/null +++ b/jaxa_integration/Dockerfile.jaxa_spaceros_listener @@ -0,0 +1,23 @@ +FROM osrf/space-ros:latest + +# Define key locations +ENV JAXA_ROS_DIR=${HOME_DIR}/jaxa_comm_ws +ENV JAXA_COMM_DIR=${JAXA_ROS_DIR}/src/jaxa_comm_spaceros +ENV JAXA_MSG_DIR=${JAXA_ROS_DIR}/src/racs2_msg + +# Copy package files for jaxa bridge +RUN mkdir -p $JAXA_COMM_DIR +COPY --chown=${USERNAME}:${USERNAME} ./jaxa_comm_spaceros $JAXA_COMM_DIR +RUN mkdir -p $JAXA_MSG_DIR +COPY --chown=${USERNAME}:${USERNAME} ./racs2_msg $JAXA_MSG_DIR + +# install protobuf +RUN pip install protobuf==3.20.1 + +# Build packages +WORKDIR ${JAXA_ROS_DIR} + +RUN /bin/bash -c 'source ${SPACEROS_DIR}/install/setup.bash \ + && colcon build' + +CMD ["bash"] diff --git a/jaxa_integration/README.md b/jaxa_integration/README.md new file mode 100644 index 00000000..ba0f0bfb --- /dev/null +++ b/jaxa_integration/README.md @@ -0,0 +1,135 @@ +# JAXA RACS2 Bridge Demo + +This demo demonstrates the use of the [RACS2](https://github.com/jaxa/racs2_bridge) (ROS and cFS System 2) Bridge to facilitate communication between {Space ROS](https://github.com/space-ros) and [Core Flight Executives (cFE)](https://github.com/nasa/cFE). The cFE is a core component of NASA-supplied spacecraft software, the [Core Flight System (CFS)](https://github.com/nasa/cFS). + +This code is a part of the following challenge: +- Challenge Name: NASA Space ROS Sim Summer Sprint Challenge +- Team Lead Freelancer Username: minahilrz +- Submission Title: JAXA RACS2 Bridge Demo + +## Directory Overview + +- **jaxa_comm_spaceros**: A ROS2 package for communication over the bridge. This ROS2 package allows spawning listener nodes to receive messages over the RACS2 Bridge. +- **racs2_msg**: A ROS2 package containing message definitions for communication between ROS2 and cFS. +- **cFS_app_examples**: Example apps for cFS. +- **Dockerfile.jaxa_spaceros_cfs**: Dockerfile for building the `jaxa_spaceros_cfs` container. It uses the spaceros image as its base. +- **Dockerfile.jaxa_spaceros_listener**: Dockerfile for building the `jaxa_spaceros_listener` container. It uses the spaceros image as its base. +- **run_jaxa_spaceros_cfs.sh**: Script to run the `jaxa_spaceros_cfs` container. +- **run_jaxa_spaceros_listener.sh**: Script to run the `jaxa_spaceros_listener` container. +- **build.sh**: Script to build two Docker images: `jaxa_spaceros_listener` and `jaxa_spaceros_cfs`. + + +## Dependencies + +To get started, ensure you have Docker Desktop installed on your system. This tutorial uses the Space ROS image, which can either be pulled from a registry or built locally. + +## Build Instructions + +To build the two necessary Docker containers, simply run the provided `build.sh` script: + +```bash +./build.sh +``` + +Once completed, you will have two Docker images: **jaxa_spaceros_listener** and **jaxa_spaceros_cfs**. + +## Usage Instructions +### Terminal 1: Start the cFS Container + +To start the `jaxa_spaceros_cfs` container, run: +```bash +./run_jaxa_spaceros_cfs.sh +``` + +When the bash terminal for the container opens, execute the following commands to start the bridge nodes: +```bash +source install/setup.bash +ros2 run bridge_py_s bridge_py_s_node --ros-args --params-file ./src/bridge_py_s/config/params.yaml +``` + +### Terminal 2: Start the cFE Publisher +Connect to the same `jaxa_spaceros_cfs` container using +```bash +docker exec -it jaxa_spaceros_cfs bash +``` + +Now, run the following commands inside the container to send messages over the bridge: +```bash +cd ../cfs/build/exe/cpu1/ +./core-cpu1 +``` + +### Terminal 3: Start the Listener Node +The `jaxa_comm_spaceros` package provides different examples of listener nodes, including demos of interacting with the Curiosity Rover and Canadarm. + +#### Example 1: Simple Listener Demo +In this example, a simple listener node is spawned which would receive the message and print it. + +First, run the `jaxa_spaceros_listener` container using the following script: +```bash +./run_jaxa_spaceros_listener.sh +``` + +Then, run the following commands inside the container to start the listener node: +```bash +source install/setup.bash +ros2 run jaxa_comm_spaceros jaxa_simple_listener + +``` + +#### Example 2: JAXA Bridge and Curiosity Rover Demo +In this example, the listener node receives numbers as messages from the cFS (commands) over the bridge and performs an action accordingly including moving and stopping the rover, turning the rover, opening and closing the tool arm or the mast. + +You need to build the space_robots image or run the curiosity rover on your own machine prior to running this example by following the instructions in the [demos](https://github.com/space-ros/demos) and [docker](https://github.com/space-ros/docker/tree/main) repos. + +Once you run the demo docker container, launch the demo using: +```bash +ros2 launch mars_rover mars_rover.launch.py +``` + +Then, run the `jaxa_spaceros_listener` container using the following script: +```bash +./run_jaxa_spaceros_listener.sh +``` + +Then, run the following commands inside the container to start the rover listener node: +```bash +source install/setup.bash +ros2 run jaxa_comm_spaceros jaxa_rover_listener + +``` + +#### Example 3: JAXA Bridge and Canadarm Demo +In this example, the listener node receives numbers as messages from the cFS (commands) over the bridge and performs an action accordingly by calling services for the Canadarm. + +Similar to example 2, you need to build the space_robots image or run the Canadarm demo on your own machine prior to running this example. + +Once you run the demo docker container, launch the demo using: +```bash +ros2 launch canadarm canadarm.launch.py +``` + +Then, run the `jaxa_spaceros_listener` container using the following script: +```bash +./run_jaxa_spaceros_listener.sh +``` + +Then, run the following commands inside the container to start the canadarm listener node: +```bash +source install/setup.bash +ros2 run jaxa_comm_spaceros jaxa_canadarm_listener + +``` + +## Architecture +The main design goal was to simulate a real life situation where the listener would be running pn a different machine as compared to the system running the cFS. Therefore, this demo builds and runs two separate containers. The system architecture is provided below. + +![archiecture](images/architecture.png) + +## Using the jaxa_comm_package in other projects +The communication package can be used in any system which has ROS2 or SpaceROS installed. Copy the package files into your own workspace and use colcon to build it. + +## Notes +- When running ROS nodes inside docker containers, all the containers must be over the same network. +- The listener node can be run in the same spaceros container as the bridge and cFS. Two separate containers demonstrate a scenario where different systems are communicating over the RACS2 Bridge. + diff --git a/jaxa_integration/build.sh b/jaxa_integration/build.sh new file mode 100755 index 00000000..6caeb619 --- /dev/null +++ b/jaxa_integration/build.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Define variables +APP1="jaxa_spaceros_cfs" +APP2="jaxa_spaceros_listener" + +# Define Docker image names +IMAGE1="jaxa_spaceros_cfs" +IMAGE2="jaxa_spaceros_listener" + +# Define Dockerfile names +DOCKERFILE1="Dockerfile.${APP1}" +DOCKERFILE2="Dockerfile.${APP2}" + +# Exit script with failure if build fails +set -eo pipefail + +# Build Docker images +echo "Building Docker image for ${APP1}..." +docker build -t $IMAGE1 -f $DOCKERFILE1 . + +echo "Building Docker image for ${APP2}..." +docker build -t $IMAGE2 -f $DOCKERFILE2 . + +echo "Docker images built successfully." + diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/CMakeLists.txt b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/CMakeLists.txt new file mode 100644 index 00000000..4159672e --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.6.4) +project(CFE_SAMPLE_TALKER C) + +include_directories(fsw/mission_inc) +include_directories(fsw/platform_inc) + +aux_source_directory(fsw/src APP_SRC_FILES) + +# Create the app module +add_cfe_app(sample_talker ${APP_SRC_FILES}) + +target_link_libraries(sample_talker + ${PROTOBUF_LIBRARY} + protobuf-c +) \ No newline at end of file diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/mission_inc/sample_talker_perfids.h b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/mission_inc/sample_talker_perfids.h new file mode 100644 index 00000000..5755e4f8 --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/mission_inc/sample_talker_perfids.h @@ -0,0 +1,7 @@ +#ifndef _sample_talker_perfids_h_ +#define _sample_talker_perfids_h_ + + +#define SAMPLE_APP_PERF_ID 91 + +#endif /* _sample_talker_perfids_h_ */ diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/platform_inc/sample_talker_msgids.h b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/platform_inc/sample_talker_msgids.h new file mode 100644 index 00000000..5a6eba35 --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/platform_inc/sample_talker_msgids.h @@ -0,0 +1,9 @@ +#ifndef _sample_talker_msgids_h_ +#define _sample_talker_msgids_h_ + +#define SAMPLE_TALKER_CMD_MID 0x1892 +#define SAMPLE_TALKER_SEND_HK_MID 0x1893 +#define SAMPLE_TALKER_HK_TLM_MID 0x0893 +#define RACS2_BRIDGE_MID 0x1EFE + +#endif /* _sample_talker_msgids_h_ */ diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/RACS2Brdige_std_msgs.pb-c.c b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/RACS2Brdige_std_msgs.pb-c.c new file mode 100644 index 00000000..0512d65c --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/RACS2Brdige_std_msgs.pb-c.c @@ -0,0 +1,261 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: RACS2Brdige_std_msgs.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "RACS2Brdige_std_msgs.pb-c.h" +void racs2_bridge_std_msgs__init + (RACS2BridgeStdMsgs *message) +{ + static const RACS2BridgeStdMsgs init_value = RACS2_BRIDGE_STD_MSGS__INIT; + *message = init_value; +} +size_t racs2_bridge_std_msgs__get_packed_size + (const RACS2BridgeStdMsgs *message) +{ + assert(message->base.descriptor == &racs2_bridge_std_msgs__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t racs2_bridge_std_msgs__pack + (const RACS2BridgeStdMsgs *message, + uint8_t *out) +{ + assert(message->base.descriptor == &racs2_bridge_std_msgs__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t racs2_bridge_std_msgs__pack_to_buffer + (const RACS2BridgeStdMsgs *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &racs2_bridge_std_msgs__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RACS2BridgeStdMsgs * + racs2_bridge_std_msgs__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RACS2BridgeStdMsgs *) + protobuf_c_message_unpack (&racs2_bridge_std_msgs__descriptor, + allocator, len, data); +} +void racs2_bridge_std_msgs__free_unpacked + (RACS2BridgeStdMsgs *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &racs2_bridge_std_msgs__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +static const ProtobufCFieldDescriptor racs2_bridge_std_msgs__field_descriptors[14] = +{ + { + "bool_data", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_BOOL, + offsetof(RACS2BridgeStdMsgs, has_bool_data), + offsetof(RACS2BridgeStdMsgs, bool_data), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "float_data", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_FLOAT, + offsetof(RACS2BridgeStdMsgs, has_float_data), + offsetof(RACS2BridgeStdMsgs, float_data), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "double_data", + 3, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_DOUBLE, + offsetof(RACS2BridgeStdMsgs, has_double_data), + offsetof(RACS2BridgeStdMsgs, double_data), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "int32_data", + 4, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_INT32, + offsetof(RACS2BridgeStdMsgs, has_int32_data), + offsetof(RACS2BridgeStdMsgs, int32_data), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "int64_data", + 5, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_INT64, + offsetof(RACS2BridgeStdMsgs, has_int64_data), + offsetof(RACS2BridgeStdMsgs, int64_data), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "string_data", + 6, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(RACS2BridgeStdMsgs, string_data), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "uint32_data", + 7, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT32, + offsetof(RACS2BridgeStdMsgs, has_uint32_data), + offsetof(RACS2BridgeStdMsgs, uint32_data), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "uint64_data", + 8, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(RACS2BridgeStdMsgs, has_uint64_data), + offsetof(RACS2BridgeStdMsgs, uint64_data), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "float32_array_data", + 9, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_FLOAT, + offsetof(RACS2BridgeStdMsgs, n_float32_array_data), + offsetof(RACS2BridgeStdMsgs, float32_array_data), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "float64_array_data", + 10, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_DOUBLE, + offsetof(RACS2BridgeStdMsgs, n_float64_array_data), + offsetof(RACS2BridgeStdMsgs, float64_array_data), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "int32_array_data", + 11, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_INT32, + offsetof(RACS2BridgeStdMsgs, n_int32_array_data), + offsetof(RACS2BridgeStdMsgs, int32_array_data), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "int64_array_data", + 12, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_INT64, + offsetof(RACS2BridgeStdMsgs, n_int64_array_data), + offsetof(RACS2BridgeStdMsgs, int64_array_data), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "uint32_array_data", + 13, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_UINT32, + offsetof(RACS2BridgeStdMsgs, n_uint32_array_data), + offsetof(RACS2BridgeStdMsgs, uint32_array_data), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "uint64_array_data", + 14, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_UINT64, + offsetof(RACS2BridgeStdMsgs, n_uint64_array_data), + offsetof(RACS2BridgeStdMsgs, uint64_array_data), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned racs2_bridge_std_msgs__field_indices_by_name[] = { + 0, /* field[0] = bool_data */ + 2, /* field[2] = double_data */ + 8, /* field[8] = float32_array_data */ + 9, /* field[9] = float64_array_data */ + 1, /* field[1] = float_data */ + 10, /* field[10] = int32_array_data */ + 3, /* field[3] = int32_data */ + 11, /* field[11] = int64_array_data */ + 4, /* field[4] = int64_data */ + 5, /* field[5] = string_data */ + 12, /* field[12] = uint32_array_data */ + 6, /* field[6] = uint32_data */ + 13, /* field[13] = uint64_array_data */ + 7, /* field[7] = uint64_data */ +}; +static const ProtobufCIntRange racs2_bridge_std_msgs__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 14 } +}; +const ProtobufCMessageDescriptor racs2_bridge_std_msgs__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RACS2Bridge_std_msgs", + "RACS2BridgeStdMsgs", + "RACS2BridgeStdMsgs", + "", + sizeof(RACS2BridgeStdMsgs), + 14, + racs2_bridge_std_msgs__field_descriptors, + racs2_bridge_std_msgs__field_indices_by_name, + 1, racs2_bridge_std_msgs__number_ranges, + (ProtobufCMessageInit) racs2_bridge_std_msgs__init, + NULL,NULL,NULL /* reserved[123] */ +}; diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/RACS2Brdige_std_msgs.pb-c.h b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/RACS2Brdige_std_msgs.pb-c.h new file mode 100644 index 00000000..54a70aa5 --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/RACS2Brdige_std_msgs.pb-c.h @@ -0,0 +1,139 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: RACS2Brdige_std_msgs.proto */ + +#ifndef PROTOBUF_C_RACS2Brdige_5fstd_5fmsgs_2eproto__INCLUDED +#define PROTOBUF_C_RACS2Brdige_5fstd_5fmsgs_2eproto__INCLUDED + +#include + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1000000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1003003 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + + +typedef struct _RACS2BridgeStdMsgs RACS2BridgeStdMsgs; + + +/* --- enums --- */ + + +/* --- messages --- */ + +struct _RACS2BridgeStdMsgs +{ + ProtobufCMessage base; + /* + * -- std_msgs/Bool --------------------------- + */ + protobuf_c_boolean has_bool_data; + protobuf_c_boolean bool_data; + /* + * -- std_msgs/Float32 --------------------------- + */ + protobuf_c_boolean has_float_data; + float float_data; + /* + * -- std_msgs/Float64 --------------------------- + */ + protobuf_c_boolean has_double_data; + double double_data; + /* + * -- std_msgs/Int32 --------------------------- + */ + protobuf_c_boolean has_int32_data; + int32_t int32_data; + /* + * -- std_msgs/Int64 --------------------------- + */ + protobuf_c_boolean has_int64_data; + int64_t int64_data; + /* + * -- std_msgs/String --------------------------- + */ + char *string_data; + /* + * -- std_msgs/Uint32 --------------------------- + */ + protobuf_c_boolean has_uint32_data; + uint32_t uint32_data; + /* + * -- std_msgs/Uint64 --------------------------- + */ + protobuf_c_boolean has_uint64_data; + uint64_t uint64_data; + /* + * -- std_msgs/Float32MultiArray --------------------------- + */ + size_t n_float32_array_data; + float *float32_array_data; + /* + * -- std_msgs/Float64MultiArray --------------------------- + */ + size_t n_float64_array_data; + double *float64_array_data; + /* + * -- std_msgs/Int32MultiArray --------------------------- + */ + size_t n_int32_array_data; + int32_t *int32_array_data; + /* + * -- std_msgs/Int64MultiArray --------------------------- + */ + size_t n_int64_array_data; + int64_t *int64_array_data; + /* + * -- std_msgs/Uint32MultiArray --------------------------- + */ + size_t n_uint32_array_data; + uint32_t *uint32_array_data; + /* + * -- std_msgs/Uint64MultiArray --------------------------- + */ + size_t n_uint64_array_data; + uint64_t *uint64_array_data; +}; +#define RACS2_BRIDGE_STD_MSGS__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&racs2_bridge_std_msgs__descriptor) \ + , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0,NULL, 0,NULL, 0,NULL, 0,NULL, 0,NULL, 0,NULL } + + +/* RACS2BridgeStdMsgs methods */ +void racs2_bridge_std_msgs__init + (RACS2BridgeStdMsgs *message); +size_t racs2_bridge_std_msgs__get_packed_size + (const RACS2BridgeStdMsgs *message); +size_t racs2_bridge_std_msgs__pack + (const RACS2BridgeStdMsgs *message, + uint8_t *out); +size_t racs2_bridge_std_msgs__pack_to_buffer + (const RACS2BridgeStdMsgs *message, + ProtobufCBuffer *buffer); +RACS2BridgeStdMsgs * + racs2_bridge_std_msgs__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void racs2_bridge_std_msgs__free_unpacked + (RACS2BridgeStdMsgs *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*RACS2BridgeStdMsgs_Closure) + (const RACS2BridgeStdMsgs *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCMessageDescriptor racs2_bridge_std_msgs__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_RACS2Brdige_5fstd_5fmsgs_2eproto__INCLUDED */ diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/racs2_user_msg.h b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/racs2_user_msg.h new file mode 100644 index 00000000..d8ad12f1 --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/racs2_user_msg.h @@ -0,0 +1,22 @@ +#ifndef _racs2_user_msg_h_ +#define _racs2_user_msg_h_ + +/* +** Type definition (user data format for racs2 bridge) +*/ +#define ROS2_TOPIC_NAME_LNGTH 32 +#define BODY_DATA_MAX_LNGTH 128 + +typedef struct +{ + uint8 TlmHeader[CFE_SB_TLM_HDR_SIZE]; + char ros2_topic_name[ROS2_TOPIC_NAME_LNGTH]; + uint8 body_data_length; + uint8 body_data[BODY_DATA_MAX_LNGTH]; + +} OS_PACK racs2_user_msg_t ; + +#define RACS2_USER_MSG_LNGTH sizeof ( racs2_user_msg_t ) +#define RACS2_BRIDGE_USER_LISTENER_LNGTH sizeof ( racs2_user_msg_t ) + +#endif /* _racs2_user_msg_h_ */ diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker.c b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker.c new file mode 100644 index 00000000..6c42637c --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker.c @@ -0,0 +1,261 @@ +/* +** Include Files: +*/ +#include "sample_talker.h" +#include "sample_talker_perfids.h" +#include "sample_talker_msgids.h" +#include "sample_talker_msg.h" +#include "racs2_user_msg.h" +#include "sample_talker_events.h" +#include "sample_talker_version.h" +#include "RACS2Brdige_std_msgs.pb-c.h" + +/* +** Global Data +*/ +sample_hk_tlm_t SAMPLE_TALKER_HkTelemetryPkt; +racs2_user_msg_t RACS2_UserMsgPkt; +CFE_SB_PipeId_t SAMPLE_TALKER_CommandPipe; +CFE_SB_MsgPtr_t SAMPLE_TALKER_MsgPtr; + +static CFE_EVS_BinFilter_t SAMPLE_EventFilters[] = { + {SAMPLE_STARTUP_INF_EID, 0x0000}, + {SAMPLE_COMMAND_ERR_EID, 0x0000}, + {SAMPLE_COMMANDNOP_INF_EID, 0x0000}, + {SAMPLE_COMMANDRST_INF_EID, 0x0000}, +}; + +/* +** Name: SAMPLE_TALKER_Main +** +** Purpose: Entry point and main loop of the application. It generates a random +** integer between 0 and 4 and sends it as a message to the ROS2 bridge. +** The process repeats every 5 seconds. +** +*/ +void SAMPLE_TALKER_Main(void) +{ + int32 status; + uint32 RunStatus = CFE_ES_RunStatus_APP_RUN; + int num; + int count = 0; + + OS_printf("SAMPLE_TALKER_Main starts.\n"); + + // Log the performance entry + CFE_ES_PerfLogEntry(SAMPLE_APP_PERF_ID); + + // Initialize the application + SAMPLE_TAKLKER_Init(); + + // Seed the random number generator + srand(time(NULL)); + + /* + ** SAMPLE_TALKER Runloop: Generates a random number and sends messages. + */ + while (CFE_ES_RunLoop(&RunStatus) == true) + { + CFE_ES_PerfLogExit(SAMPLE_APP_PERF_ID); + CFE_ES_PerfLogEntry(SAMPLE_APP_PERF_ID); + + // Generate a random number between 0 and 7 + num = rand() % 8; + + // Set the ROS2 topic name + strcpy(RACS2_UserMsgPkt.ros2_topic_name, "/Recv/RACS2Bridge"); + + // Create the message content + int string_length = 22; + char buf[32]; + sprintf(buf, "Message To ROS2 :%5d", num); + + RACS2BridgeStdMsgs *message = (RACS2BridgeStdMsgs *)malloc(sizeof(RACS2BridgeStdMsgs)); + racs2_bridge_std_msgs__init(message); + + message->string_data = (char *)malloc(string_length); + strncpy(message->string_data, buf, string_length); + + // Serialize the message + int len = racs2_bridge_std_msgs__get_packed_size(message); + void *buffer = malloc(len); + racs2_bridge_std_msgs__pack(message, buffer); + + // Set the body data and length + strncpy(RACS2_UserMsgPkt.body_data, buffer, len); + RACS2_UserMsgPkt.body_data_length = len; + + // Timestamp the message and send it + CFE_SB_TimeStampMsg((CFE_SB_Msg_t *)&RACS2_UserMsgPkt); + status = CFE_SB_SendMsg((CFE_SB_Msg_t *)&RACS2_UserMsgPkt); + + // Check for errors in sending + if (status != CFE_SUCCESS) + { + OS_printf("SAMPLE_TALKER: Error: sending failed. status = 0x%x\n", status); + } + + // Clean up memory + free(buffer); + free(message->string_data); + free(message); + memset(buf, '\0', sizeof(buf)); + + // Wait for 5 seconds before sending the next message + sleep(5); + } + + CFE_ES_ExitApp(RunStatus); +} + +/* +** Name: SAMPLE_TAKLKER_Init +** +** Purpose: Initializes the application by registering it with executive services, +** registering events, resetting counters, and initializing message packets. +** +*/ +void SAMPLE_TAKLKER_Init(void) +{ + // Register the application with Executive services + CFE_ES_RegisterApp(); + + // Register events with event services + CFE_EVS_Register(SAMPLE_EventFilters, + sizeof(SAMPLE_EventFilters) / sizeof(CFE_EVS_BinFilter_t), + CFE_EVS_EventFilter_BINARY); + + // Reset counters + SAMPLE_TALKER_ResetCounters(); + + // Initialize housekeeping and user message packets + CFE_SB_InitMsg(&SAMPLE_TALKER_HkTelemetryPkt, SAMPLE_TALKER_HK_TLM_MID, SAMPLE_APP_HK_TLM_LNGTH, true); + CFE_SB_InitMsg(&RACS2_UserMsgPkt, RACS2_BRIDGE_MID, RACS2_USER_MSG_LNGTH, false); + + // Send startup event + CFE_EVS_SendEvent(SAMPLE_STARTUP_INF_EID, CFE_EVS_EventType_INFORMATION, + "SAMPLE_TALKER App Initialized. Version %d.%d.%d.%d", + SAMPLE_APP_MAJOR_VERSION, + SAMPLE_APP_MINOR_VERSION, + SAMPLE_APP_REVISION, + SAMPLE_APP_MISSION_REV); +} + +/* +** Name: SAMPLE_TALKER_ProcessCommandPacket +** +** Purpose: Processes packets received on the SAMPLE_TALKER command pipe by +** identifying the message ID and directing it to the appropriate handler. +** +*/ +void SAMPLE_TALKER_ProcessCommandPacket(void) +{ + CFE_SB_MsgId_t MsgId; + + MsgId = CFE_SB_GetMsgId(SAMPLE_TALKER_MsgPtr); + + switch (MsgId) + { + case SAMPLE_TALKER_CMD_MID: + SAMPLE_TALKER_ProcessGroundCommand(); + break; + + case SAMPLE_TALKER_SEND_HK_MID: + SAMPLE_TALKER_ReportHousekeeping(); + break; + + default: + SAMPLE_TALKER_HkTelemetryPkt.sample_command_error_count++; + CFE_EVS_SendEvent(SAMPLE_COMMAND_ERR_EID, CFE_EVS_EventType_ERROR, + "SAMPLE_TALKER: invalid command packet,MID = 0x%x", MsgId); + break; + } +} + +/* +** Name: SAMPLE_TALKER_ProcessGroundCommand +** +** Purpose: Processes ground commands such as NOOP and Reset Counters, updating telemetry +** or taking the appropriate action based on the command code. +** +*/ +void SAMPLE_TALKER_ProcessGroundCommand(void) +{ + uint16 CommandCode; + + CommandCode = CFE_SB_GetCmdCode(SAMPLE_TALKER_MsgPtr); + + switch (CommandCode) + { + case SAMPLE_APP_NOOP_CC: + SAMPLE_TALKER_HkTelemetryPkt.sample_command_count++; + CFE_EVS_SendEvent(SAMPLE_COMMANDNOP_INF_EID, CFE_EVS_EventType_INFORMATION, + "SAMPLE_TALKER: NOOP command"); + break; + + case SAMPLE_APP_RESET_COUNTERS_CC: + SAMPLE_TALKER_ResetCounters(); + break; + + default: + break; + } +} + +/* +** Name: SAMPLE_TALKER_ReportHousekeeping +** +** Purpose: Gathers the application's telemetry, packetizes it, and sends it to +** the housekeeping task via the software bus. +** +*/ +void SAMPLE_TALKER_ReportHousekeeping(void) +{ + CFE_SB_TimeStampMsg((CFE_SB_Msg_t *)&SAMPLE_TALKER_HkTelemetryPkt); + CFE_SB_SendMsg((CFE_SB_Msg_t *)&SAMPLE_TALKER_HkTelemetryPkt); +} + +/* +** Name: SAMPLE_TALKER_ResetCounters +** +** Purpose: Resets all global counter variables that are part of the task telemetry. +** +*/ +void SAMPLE_TALKER_ResetCounters(void) +{ + SAMPLE_TALKER_HkTelemetryPkt.sample_command_count = 0; + SAMPLE_TALKER_HkTelemetryPkt.sample_command_error_count = 0; + + CFE_EVS_SendEvent(SAMPLE_COMMANDRST_INF_EID, CFE_EVS_EventType_INFORMATION, + "SAMPLE_TALKER: RESET command"); +} + +/* +** Name: SAMPLE_TALKER_VerifyCmdLength +** +** Purpose: Verifies that the length of a command packet matches the expected length. +** If the lengths do not match, an error event is sent. +** +** Returns: true if lengths match, false otherwise. +** +*/ +bool SAMPLE_TALKER_VerifyCmdLength(CFE_SB_MsgPtr_t msg, uint16 ExpectedLength) +{ + bool result = true; + uint16 ActualLength = CFE_SB_GetTotalMsgLength(msg); + + if (ExpectedLength != ActualLength) + { + CFE_SB_MsgId_t MessageID = CFE_SB_GetMsgId(msg); + uint16 CommandCode = CFE_SB_GetCmdCode(msg); + + CFE_EVS_SendEvent(SAMPLE_LEN_ERR_EID, CFE_EVS_EventType_ERROR, + "Invalid msg length: ID = 0x%X, CC = %d, Len = %d, Expected = %d", + MessageID, CommandCode, ActualLength, ExpectedLength); + result = false; + SAMPLE_TALKER_HkTelemetryPkt.sample_command_error_count++; + } + + return result; +} + diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker.h b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker.h new file mode 100644 index 00000000..ea752ab3 --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker.h @@ -0,0 +1,39 @@ +#ifndef _sample_talker_h_ +#define _sample_talker_h_ + +/* +** Required header files. +*/ +#include "cfe.h" +#include "cfe_error.h" +#include "cfe_evs.h" +#include "cfe_sb.h" +#include "cfe_es.h" + +#include +#include +#include +#include +#include +#include +#include + + +#define SAMPLE_PIPE_DEPTH 32 + +/* +** Local function prototypes. +** +** Note: Except for the entry point (SAMPLE_TALKER_Main), these +** functions are not called from any other source module. +*/ +void SAMPLE_TALKER_Main(void); +void SAMPLE_TAKLKER_Init(void); +void SAMPLE_TALKER_ProcessCommandPacket(void); +void SAMPLE_TALKER_ProcessGroundCommand(void); +void SAMPLE_TALKER_ReportHousekeeping(void); +void SAMPLE_TALKER_ResetCounters(void); + +bool SAMPLE_TALKER_VerifyCmdLength(CFE_SB_MsgPtr_t msg, uint16 ExpectedLength); + +#endif /* _sample_talker_h_ */ diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_events.h b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_events.h new file mode 100644 index 00000000..d068a099 --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_events.h @@ -0,0 +1,13 @@ +#ifndef _sample_talker_events_h_ +#define _sample_talker_events_h_ + + +#define SAMPLE_RESERVED_EID 20 +#define SAMPLE_STARTUP_INF_EID 21 +#define SAMPLE_COMMAND_ERR_EID 22 +#define SAMPLE_COMMANDNOP_INF_EID 23 +#define SAMPLE_COMMANDRST_INF_EID 24 +#define SAMPLE_INVALID_MSGID_ERR_EID 25 +#define SAMPLE_LEN_ERR_EID 26 + +#endif /* _sample_talker_events_h_ */ diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_msg.h b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_msg.h new file mode 100644 index 00000000..8adbe994 --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_msg.h @@ -0,0 +1,36 @@ +#ifndef _sample_talker_msg_h_ +#define _sample_talker_msg_h_ + +/* +** SAMPLE App command codes +*/ +#define SAMPLE_APP_NOOP_CC 0 +#define SAMPLE_APP_RESET_COUNTERS_CC 1 + +/*************************************************************************/ +/* +** Type definition (generic "no arguments" command) +*/ +typedef struct +{ + uint8 CmdHeader[CFE_SB_CMD_HDR_SIZE]; + +} SAMPLE_NoArgsCmd_t; + +/*************************************************************************/ +/* +** Type definition (SAMPLE App housekeeping) +*/ +typedef struct +{ + uint8 TlmHeader[CFE_SB_TLM_HDR_SIZE]; + uint8 sample_command_error_count; + uint8 sample_command_count; + uint8 spare[2]; + +} OS_PACK sample_hk_tlm_t ; + +#define SAMPLE_APP_HK_TLM_LNGTH sizeof ( sample_hk_tlm_t ) +#define SAMPLE_TALKER_LISTENER_LNGTH sizeof ( sample_hk_tlm_t ) + +#endif /* _sample_talker_msg_h_ */ diff --git a/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_version.h b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_version.h new file mode 100644 index 00000000..41115c9d --- /dev/null +++ b/jaxa_integration/cFS_app_examples/space_robots/cfs_app/sample_talker/fsw/src/sample_talker_version.h @@ -0,0 +1,9 @@ +#ifndef _sample_talker_version_h_ +#define _sample_talker_version_h_ + +#define SAMPLE_APP_MAJOR_VERSION 1 +#define SAMPLE_APP_MINOR_VERSION 1 +#define SAMPLE_APP_REVISION 0 +#define SAMPLE_APP_MISSION_REV 0 + +#endif /* _sample_talker_version_h_ */ diff --git a/jaxa_integration/images/architecture.png b/jaxa_integration/images/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..26df58ddb15fd8df59fc3e80b437032119764af1 GIT binary patch literal 31553 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 literal 0 HcmV?d00001 diff --git a/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/RACS2Bridge_std_msgs_pb2.py b/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/RACS2Bridge_std_msgs_pb2.py new file mode 100644 index 00000000..dd567e91 --- /dev/null +++ b/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/RACS2Bridge_std_msgs_pb2.py @@ -0,0 +1,166 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: RACS2Bridge_std_msgs.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='RACS2Bridge_std_msgs.proto', + package='', + syntax='proto2', + serialized_options=None, + serialized_pb=_b('\n\x1aRACS2Bridge_std_msgs.proto\"\xf3\x02\n\x14RACS2Bridge_std_msgs\x12\x11\n\tbool_data\x18\x01 \x01(\x08\x12\x12\n\nfloat_data\x18\x02 \x01(\x02\x12\x13\n\x0b\x64ouble_data\x18\x03 \x01(\x01\x12\x12\n\nint32_data\x18\x04 \x01(\x05\x12\x12\n\nint64_data\x18\x05 \x01(\x03\x12\x13\n\x0bstring_data\x18\x06 \x01(\t\x12\x13\n\x0buint32_data\x18\x07 \x01(\r\x12\x13\n\x0buint64_data\x18\x08 \x01(\x04\x12\x1e\n\x12\x66loat32_array_data\x18\t \x03(\x02\x42\x02\x10\x01\x12\x1e\n\x12\x66loat64_array_data\x18\n \x03(\x01\x42\x02\x10\x01\x12\x1c\n\x10int32_array_data\x18\x0b \x03(\x05\x42\x02\x10\x01\x12\x1c\n\x10int64_array_data\x18\x0c \x03(\x03\x42\x02\x10\x01\x12\x1d\n\x11uint32_array_data\x18\r \x03(\rB\x02\x10\x01\x12\x1d\n\x11uint64_array_data\x18\x0e \x03(\x04\x42\x02\x10\x01') +) + + + + +_RACS2BRIDGE_STD_MSGS = _descriptor.Descriptor( + name='RACS2Bridge_std_msgs', + full_name='RACS2Bridge_std_msgs', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='bool_data', full_name='RACS2Bridge_std_msgs.bool_data', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='float_data', full_name='RACS2Bridge_std_msgs.float_data', index=1, + number=2, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='double_data', full_name='RACS2Bridge_std_msgs.double_data', index=2, + number=3, type=1, cpp_type=5, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='int32_data', full_name='RACS2Bridge_std_msgs.int32_data', index=3, + number=4, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='int64_data', full_name='RACS2Bridge_std_msgs.int64_data', index=4, + number=5, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='string_data', full_name='RACS2Bridge_std_msgs.string_data', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='uint32_data', full_name='RACS2Bridge_std_msgs.uint32_data', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='uint64_data', full_name='RACS2Bridge_std_msgs.uint64_data', index=7, + number=8, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='float32_array_data', full_name='RACS2Bridge_std_msgs.float32_array_data', index=8, + number=9, type=2, cpp_type=6, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=_b('\020\001'), file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='float64_array_data', full_name='RACS2Bridge_std_msgs.float64_array_data', index=9, + number=10, type=1, cpp_type=5, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=_b('\020\001'), file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='int32_array_data', full_name='RACS2Bridge_std_msgs.int32_array_data', index=10, + number=11, type=5, cpp_type=1, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=_b('\020\001'), file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='int64_array_data', full_name='RACS2Bridge_std_msgs.int64_array_data', index=11, + number=12, type=3, cpp_type=2, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=_b('\020\001'), file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='uint32_array_data', full_name='RACS2Bridge_std_msgs.uint32_array_data', index=12, + number=13, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=_b('\020\001'), file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='uint64_array_data', full_name='RACS2Bridge_std_msgs.uint64_array_data', index=13, + number=14, type=4, cpp_type=4, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=_b('\020\001'), file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=31, + serialized_end=402, +) + +DESCRIPTOR.message_types_by_name['RACS2Bridge_std_msgs'] = _RACS2BRIDGE_STD_MSGS +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +RACS2Bridge_std_msgs = _reflection.GeneratedProtocolMessageType('RACS2Bridge_std_msgs', (_message.Message,), dict( + DESCRIPTOR = _RACS2BRIDGE_STD_MSGS, + __module__ = 'RACS2Bridge_std_msgs_pb2' + # @@protoc_insertion_point(class_scope:RACS2Bridge_std_msgs) + )) +_sym_db.RegisterMessage(RACS2Bridge_std_msgs) + + +_RACS2BRIDGE_STD_MSGS.fields_by_name['float32_array_data']._options = None +_RACS2BRIDGE_STD_MSGS.fields_by_name['float64_array_data']._options = None +_RACS2BRIDGE_STD_MSGS.fields_by_name['int32_array_data']._options = None +_RACS2BRIDGE_STD_MSGS.fields_by_name['int64_array_data']._options = None +_RACS2BRIDGE_STD_MSGS.fields_by_name['uint32_array_data']._options = None +_RACS2BRIDGE_STD_MSGS.fields_by_name['uint64_array_data']._options = None +# @@protoc_insertion_point(module_scope) diff --git a/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/__init__.py b/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_canadarm_listener.py b/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_canadarm_listener.py new file mode 100644 index 00000000..e43499a8 --- /dev/null +++ b/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_canadarm_listener.py @@ -0,0 +1,117 @@ +import rclpy +from rclpy.node import Node +from racs2_msg.msg import RACS2UserMsg +from jaxa_comm_spaceros.RACS2Bridge_std_msgs_pb2 import RACS2Bridge_std_msgs +from std_srvs.srv import Empty +import re + +class CanadarmListener(Node): + """ + A ROS 2 subscriber node for controlling the Canadarm. + + This node listens on the '/Recv/RACS2Bridge' topic and processes + incoming `RACS2UserMsg` messages. Based on the message content, + it calls the appropriate ROS 2 services to control the Canadarm. + """ + + def __init__(self): + """Initialize the CanadarmListener node and set up the subscription.""" + super().__init__('canadarm_listener') + + # Create a dictionary of service clients + self.clients_dict = { + 'open_arm': self.create_client(Empty, '/open_arm'), + 'close_arm': self.create_client(Empty, '/close_arm'), + 'random_arm': self.create_client(Empty, '/random_arm') + } + + # Set up subscription + self.subscription = self.create_subscription( + RACS2UserMsg, + '/Recv/RACS2Bridge', + self.listener_callback, + 10 + ) + + def listener_callback(self, msg): + """ + Callback function executed upon receiving a message. + + Args: + msg (RACS2UserMsg): The message received from the subscribed topic. + """ + self.get_logger().info('Received message on /Recv/RACS2Bridge') + + # Initialize the message object + message = RACS2Bridge_std_msgs() + message.ParseFromString(b''.join(msg.body_data)) + + # Check if the parsed message contains string data + if message.HasField("string_data"): + command = int(message.string_data.split()[-1]) + self.get_logger().info(f'Received command: {command}') + # Determine which service to call based on the command + service_name = self.get_service_name(command) + if service_name: + self.get_logger().info(f'Calling service: {service_name}') + self.call_service_async(self.clients_dict[service_name]) + else: + self.get_logger().warning(f'Unknown command: {command}') + + def get_service_name(self, command): + """Return the service name based on the command.""" + service_map = { + 0: 'close_arm', + 1: 'open_arm', + 2: 'random_arm', + } + return service_map.get(command, None) + + def call_service_async(self, client): + """ + Initiates an asynchronous service call and registers a callback to handle the result. + + Args: + client (rclpy.client.Client): The ROS 2 service client to call. + """ + if not client.service_is_ready(): + self.get_logger().info(f'Waiting for service {client.srv_name} to be available...') + client.wait_for_service() + + future = client.call_async(Empty.Request()) + future.add_done_callback(self.service_response_callback) + + def service_response_callback(self, future): + """ + Callback function to handle the result of an asynchronous service call. + + Args: + future (rclpy.future.Future): The future representing the result of the service call. + """ + try: + result = future.result() + self.get_logger().info('Service call successful.') + except Exception as e: + self.get_logger().error(f'Exception during service call: {e}') + + +def main(args=None): + """ + Main function to run the CanadarmListener node. + + Initializes the ROS 2 client library, spins the node, and handles node shutdown. + """ + rclpy.init(args=args) + + # Create and spin the CanadarmListener node + canadarm_listener = CanadarmListener() + rclpy.spin(canadarm_listener) + + # Destroy the node explicitly before shutting down + canadarm_listener.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() + diff --git a/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_rover_listener.py b/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_rover_listener.py new file mode 100644 index 00000000..b57bf5fe --- /dev/null +++ b/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_rover_listener.py @@ -0,0 +1,98 @@ +import rclpy +from rclpy.node import Node +from racs2_msg.msg import RACS2UserMsg +from jaxa_comm_spaceros.RACS2Bridge_std_msgs_pb2 import RACS2Bridge_std_msgs +from std_srvs.srv import Empty + +class JaxaRoverListener(Node): + def __init__(self): + super().__init__('jaxa_rover_listener') + + # Create service clients + self.clients_dict = { + 'move_stop': self.create_client(Empty, '/move_stop'), + 'move_forward': self.create_client(Empty, '/move_forward'), + 'turn_left': self.create_client(Empty, '/turn_left'), + 'turn_right': self.create_client(Empty, '/turn_right'), + 'open_arm': self.create_client(Empty, '/open_arm'), + 'close_arm': self.create_client(Empty, '/close_arm'), + 'mast_open': self.create_client(Empty, '/mast_open'), + 'mast_close': self.create_client(Empty, '/mast_close') + } + + # Set up subscription + self.subscription = self.create_subscription( + RACS2UserMsg, + '/Recv/RACS2Bridge', + self.listener_callback, + 10 + ) + + def listener_callback(self, msg): + self.get_logger().info('Subscribing: [/Recv/RACS2Bridge]') + + # Initialize the message object + message = RACS2Bridge_std_msgs() + message.ParseFromString(b''.join(msg.body_data)) + + if message.HasField("string_data"): + command = int(message.string_data.split()[-1]) + self.get_logger().info(f'Received command: {command}') + + service_name = self.get_service_name(command) + if service_name: + self.get_logger().info(f'Calling service: {service_name}') + self.call_service_async(self.clients_dict[service_name]) + else: + self.get_logger().warning(f'Unknown command: {command}') + + def get_service_name(self, command): + service_map = { + 0: 'move_stop', + 1: 'move_forward', + 2: 'turn_left', + 3: 'turn_right', + 4: 'open_arm', + 5: 'close_arm', + 6: 'mast_open', + 7: 'mast_close' + } + return service_map.get(command, None) + + def call_service_async(self, client): + """ + Initiates an asynchronous service call and registers a callback to handle the result. + + Args: + client (rclpy.client.Client): The ROS 2 service client to call. + """ + if not client.service_is_ready(): + self.get_logger().info(f'Waiting for service {client.service_name} to be available...') + client.wait_for_service() + + future = client.call_async(Empty.Request()) + future.add_done_callback(self.service_response_callback) + + def service_response_callback(self, future): + """ + Callback function to handle the result of an asynchronous service call. + + Args: + future (rclpy.future.Future): The future representing the result of the service call. + """ + try: + result = future.result() + self.get_logger().info('Service call successful.') + except Exception as e: + self.get_logger().error(f'Exception during service call: {e}') + +def main(args=None): + rclpy.init(args=args) + jaxa_rover_listener = JaxaRoverListener() + rclpy.spin(jaxa_rover_listener) + jaxa_rover_listener.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() + diff --git a/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_simple_listener.py b/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_simple_listener.py new file mode 100644 index 00000000..3d8e9291 --- /dev/null +++ b/jaxa_integration/jaxa_comm_spaceros/jaxa_comm_spaceros/jaxa_simple_listener.py @@ -0,0 +1,92 @@ +""" +JAXA Simple Listener Node + +This ROS 2 node subscribes to messages from the JAXA RACS2 bridge and processes +incoming data. + +Author: Minahil Raza +Email: minahilrz@gmail.com + +This script subscribes to the '/Recv/RACS2Bridge' topic, receives messages +of type `RACS2UserMsg`, parses the message content, and logs any string data +that is extracted. + +Usage: + This script is intended to be run within a ROS 2 environment. It should be + included in a ROS 2 package and can be launched using the `ros2 run` command + or through a ROS 2 launch file. + +""" + +import rclpy +from rclpy.node import Node +from racs2_msg.msg import RACS2UserMsg +from jaxa_comm_spaceros.RACS2Bridge_std_msgs_pb2 import RACS2Bridge_std_msgs + + +class JaxaSimpleListener(Node): + """ + A simple ROS 2 subscriber node for receiving and processing messages + from the JAXA RACS2 bridge. + + This node listens on the '/Recv/RACS2Bridge' topic and processes + incoming `RACS2UserMsg` messages. It extracts and logs any string + data contained within the messages. + """ + + def __init__(self): + """Initialize the JaxaSimpleListener node and set up the subscription.""" + super().__init__('jaxa_simple_listener') + self.subscription = self.create_subscription( + RACS2UserMsg, + '/Recv/RACS2Bridge', + self.listener_callback, + 10 + ) + # Prevent unused variable warning + self.subscription + + def listener_callback(self, msg): + """ + Callback function executed upon receiving a message. + + Parses the incoming `RACS2UserMsg` message to extract string data + and logs it. + + Args: + msg (RACS2UserMsg): The message received from the subscribed topic. + """ + self.get_logger().info('Subscribing: [/Recv/RACS2Bridge]') + + # Initialize the message object + message = RACS2Bridge_std_msgs() + + # Parse the incoming message body data + message.ParseFromString(b''.join(msg.body_data)) + + # Check if the parsed message contains string data and log it + if message.HasField("string_data"): + self.get_logger().info(f'Received string data: {message.string_data}') + + +def main(args=None): + """ + Main function to run the JaxaSimpleListener node. + + Initializes the ROS 2 client library, spins the node, and handles node shutdown. + """ + + rclpy.init(args=args) + + # Create and spin the JaxaSimpleListener node + jaxa_simple_listener = JaxaSimpleListener() + rclpy.spin(jaxa_simple_listener) + + # Destroy the node explicitly before shutting down + jaxa_simple_listener.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() + diff --git a/jaxa_integration/jaxa_comm_spaceros/package.xml b/jaxa_integration/jaxa_comm_spaceros/package.xml new file mode 100644 index 00000000..5e9674f0 --- /dev/null +++ b/jaxa_integration/jaxa_comm_spaceros/package.xml @@ -0,0 +1,18 @@ + + + + jaxa_comm_spaceros + 0.0.0 + Ros2 Package for communication between JAXA RACS2 Bridge and SpaceROS + spaceros-user + TODO: License declaration + + ament_copyright + ament_flake8 + ament_pep257 + python3-pytest + + + ament_python + + diff --git a/jaxa_integration/jaxa_comm_spaceros/resource/jaxa_comm_spaceros b/jaxa_integration/jaxa_comm_spaceros/resource/jaxa_comm_spaceros new file mode 100644 index 00000000..e69de29b diff --git a/jaxa_integration/jaxa_comm_spaceros/setup.cfg b/jaxa_integration/jaxa_comm_spaceros/setup.cfg new file mode 100644 index 00000000..7a116707 --- /dev/null +++ b/jaxa_integration/jaxa_comm_spaceros/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/jaxa_comm_spaceros +[install] +install_scripts=$base/lib/jaxa_comm_spaceros diff --git a/jaxa_integration/jaxa_comm_spaceros/setup.py b/jaxa_integration/jaxa_comm_spaceros/setup.py new file mode 100644 index 00000000..e21a51a2 --- /dev/null +++ b/jaxa_integration/jaxa_comm_spaceros/setup.py @@ -0,0 +1,28 @@ +from setuptools import find_packages, setup + +package_name = 'jaxa_comm_spaceros' + +setup( + name=package_name, + version='0.0.0', + packages=find_packages(exclude=['test']), + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='Minahil Raza', + maintainer_email='minahilrz@gmail.com', + description='A package containing ROS nodes for communicating with JAXA cFS bridge', + license='Apache-2.0 license', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'jaxa_simple_listener = jaxa_comm_spaceros.jaxa_simple_listener:main', + 'jaxa_rover_listener = jaxa_comm_spaceros.jaxa_rover_listener:main', + 'jaxa_canadarm_listener = jaxa_comm_spaceros.jaxa_canadarm_listener:main' + ], + }, +) diff --git a/jaxa_integration/jaxa_comm_spaceros/test/test_copyright.py b/jaxa_integration/jaxa_comm_spaceros/test/test_copyright.py new file mode 100644 index 00000000..97a39196 --- /dev/null +++ b/jaxa_integration/jaxa_comm_spaceros/test/test_copyright.py @@ -0,0 +1,25 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_copyright.main import main +import pytest + + +# Remove the `skip` decorator once the source file(s) have a copyright header +@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') +@pytest.mark.copyright +@pytest.mark.linter +def test_copyright(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found errors' diff --git a/jaxa_integration/jaxa_comm_spaceros/test/test_flake8.py b/jaxa_integration/jaxa_comm_spaceros/test/test_flake8.py new file mode 100644 index 00000000..27ee1078 --- /dev/null +++ b/jaxa_integration/jaxa_comm_spaceros/test/test_flake8.py @@ -0,0 +1,25 @@ +# Copyright 2017 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_flake8.main import main_with_errors +import pytest + + +@pytest.mark.flake8 +@pytest.mark.linter +def test_flake8(): + rc, errors = main_with_errors(argv=[]) + assert rc == 0, \ + 'Found %d code style errors / warnings:\n' % len(errors) + \ + '\n'.join(errors) diff --git a/jaxa_integration/jaxa_comm_spaceros/test/test_pep257.py b/jaxa_integration/jaxa_comm_spaceros/test/test_pep257.py new file mode 100644 index 00000000..b234a384 --- /dev/null +++ b/jaxa_integration/jaxa_comm_spaceros/test/test_pep257.py @@ -0,0 +1,23 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_pep257.main import main +import pytest + + +@pytest.mark.linter +@pytest.mark.pep257 +def test_pep257(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found code style errors / warnings' diff --git a/jaxa_integration/racs2_msg/CMakeLists.txt b/jaxa_integration/racs2_msg/CMakeLists.txt new file mode 100644 index 00000000..8c571bc5 --- /dev/null +++ b/jaxa_integration/racs2_msg/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.5) +project(racs2_msg) + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +find_package(rosidl_default_generators REQUIRED) + +rosidl_generate_interfaces(${PROJECT_NAME} + "msg/RACS2UserMsg.msg" +) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # uncomment the line when a copyright and license is not present in all source files + #set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # uncomment the line when this package is not in a git repo + #set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_export_dependencies(rosidl_default_runtime) +ament_package() diff --git a/jaxa_integration/racs2_msg/msg/RACS2UserMsg.msg b/jaxa_integration/racs2_msg/msg/RACS2UserMsg.msg new file mode 100644 index 00000000..f6dc1401 --- /dev/null +++ b/jaxa_integration/racs2_msg/msg/RACS2UserMsg.msg @@ -0,0 +1,11 @@ +# +# User data format for ROS2 app in using RACS2 Bridge +# +# --- Header data --- +uint32 cfs_message_id # Message ID of cFS desitnation app +uint32 body_data_length # Body data size in byte +# --- Body data (serializied data is preffered): array of byte --- +# Note: +# - In Python: "byte" means bytes object +# - In C++ : "byte" means uint8_t type +byte[] body_data \ No newline at end of file diff --git a/jaxa_integration/racs2_msg/package.xml b/jaxa_integration/racs2_msg/package.xml new file mode 100644 index 00000000..26ba35d3 --- /dev/null +++ b/jaxa_integration/racs2_msg/package.xml @@ -0,0 +1,22 @@ + + + + racs2_msg + 0.0.0 + RACS2 bridge message package + jaxa + Apache License 2.0 + + ament_cmake + + ament_lint_auto + ament_lint_common + + rosidl_default_generators + rosidl_default_runtime + rosidl_interface_packages + + + ament_cmake + + diff --git a/jaxa_integration/run_jaxa_spaceros_cfs.sh b/jaxa_integration/run_jaxa_spaceros_cfs.sh new file mode 100755 index 00000000..02d47d58 --- /dev/null +++ b/jaxa_integration/run_jaxa_spaceros_cfs.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + + +CONTAINER_NAME=jaxa_spaceros_cfs +IMG_NAME=jaxa_spaceros_cfs + +# Start the container +docker run --rm -it --name $CONTAINER_NAME --network host \ + -e DISPLAY -e TERM -e QT_X11_NO_MITSHM=1 $IMG_NAME + diff --git a/jaxa_integration/run_jaxa_spaceros_listener.sh b/jaxa_integration/run_jaxa_spaceros_listener.sh new file mode 100755 index 00000000..acca159f --- /dev/null +++ b/jaxa_integration/run_jaxa_spaceros_listener.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + + +CONTAINER_NAME=jaxa_spaceros_listener +IMG_NAME=jaxa_spaceros_listener + +# Start the container +docker run --rm -it --name $CONTAINER_NAME --network host \ + -e DISPLAY -e TERM -e QT_X11_NO_MITSHM=1 $IMG_NAME +