Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions app/robot_status_bridge/.bashrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# ==================== ROS ==================== #
# ==== Description: ROS environment setup ===== #
# =================== BEGIN =================== #

source_ros_environment() {
if [ "$ROS_DISTRO" = "humble" ]; then
# Custom Alias
alias rosdep-check='rosdep install -i --from-path src --rosdistro humble -y'
alias build='colcon build --symlink-install'

# Source ROS environment
source /opt/ros/humble/setup.bash

# Source workspace environment
# latest_setup_bash: Find the latest setup.bash over user's root directory based on the last modified time
latest_setup_bash=$(find $(pwd) -type f -name "setup.bash" -wholename "*/install/setup.bash" -printf "%T@ %p\n" | sort -nr | awk '{print $2}' | head -n 1)
if [ -n "$latest_setup_bash" ]; then
source $latest_setup_bash
# Source colcon environment
source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash
source /usr/share/colcon_cd/function/colcon_cd.sh
export _colcon_cd_root="${latest_setup_bash%/install/setup.bash}"
else
echo "No setup.bash file found for humble"
fi
elif [ "$ROS_DISTRO" = "noetic" ]; then
source /opt/ros/noetic/setup.bash
# Source workspace environment
if [ -n "$ROS_WS" ]; then
source $ROS_WS/devel/setup.bash
else
echo "ROS_WS variable is not set for noetic"
fi
else
echo "Unsupported ROS_DISTRO: $ROS_DISTRO"
fi
}

# ==================== END ==================== #



# ================= Functions ================= #
# Note: If you want to use the custom function, #
# you need to uncomment the line below. #
# =================== BEGIN =================== #

source_ros_environment

# ==================== END ==================== #
6 changes: 6 additions & 0 deletions app/robot_status_bridge/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

# COMPOSE_BUILDER=bake
COMPOSE_BAKE=true

ROS_DISTRO=humble
# ROS_DOMAIN_ID=25
78 changes: 78 additions & 0 deletions app/robot_status_bridge/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
######################################################################
# - Base stage
# - This stage serves as the base image for the following stages.
######################################################################

ARG ROS_DISTRO=humble
FROM osrf/ros:${ROS_DISTRO}-desktop AS base

LABEL org.opencontainers.image.title="Robot Status Bridge"
LABEL org.opencontainers.image.authors="scx@gapp.nthu.edu.tw"
LABEL org.opencontainers.image.licenses="MIT"

ARG USERNAME=ros
# Use the same UID and GID as the host user
ARG USER_UID=1000
ARG USER_GID=1000

######################################################################
# - User setup stage
# - Create a non-root user with default bash shell.
######################################################################

FROM base AS user-setup

RUN groupadd --gid $USER_GID $USERNAME \
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
&& apt-get update \
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME \
&& rm -rf /var/lib/apt/lists/*

######################################################################
# - Tools Installation stage
# - Install common tools for development.
######################################################################

FROM user-setup AS tools

RUN apt-get update && apt-get install -y \
tree \
vim \
wget \
unzip \
python3-pip \
bash-completion \
wireless-tools \
ros-humble-rmw-cyclonedds-cpp \
ros-humble-foxglove-bridge

RUN apt-get update && apt-get dist-upgrade -y \
&& apt-get autoremove -y \
&& apt-get autoclean -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*

######################################################################
# - Final stage
# - Install the main packages and set the entrypoint.
######################################################################

FROM tools AS final

# Set up the user environment
ENV TZ=Asia/Taipei
ENV SHELL=/bin/bash
USER $USERNAME
WORKDIR /robot_status_br

# Set up bashrc
COPY .bashrc /home/$USERNAME/.bashrc.conf
RUN cat /home/$USERNAME/.bashrc.conf >> /home/$USERNAME/.bashrc

# Set up python environment
# RUN pip install --upgrade pip
# RUN pip install --no-cache-dir

CMD ["/bin/bash"]
38 changes: 38 additions & 0 deletions app/robot_status_bridge/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
services:
voice_nav:
build:
context: .
dockerfile: Dockerfile
target: final
args:
ROS_DISTRO: ${ROS_DISTRO}
USERNAME: ros
image: scx/robot-status-bridge:${ROS_DISTRO}
container_name: robot-status-bridge
stdin_open: true
tty: true
privileged: true
network_mode: "host"
restart: unless-stopped

working_dir: /home/ros

environment:
- DISPLAY=${DISPLAY}
- ROS_DOMAIN_ID=${ROS_DOMAIN_ID}
- RMW_IMPLEMENTATION=rmw_cyclonedds_cpp

volumes:
- ./entrypoint.sh:/entrypoint.sh
# Mount app resources into container.
- ./robot_status_br/:/home/ros/robot_status_br/ # ros2 workspace
- /sys/class:/sys/class:ro # for system status monitoring

# Mount local timezone into container.
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
# Mount X11 server
- /tmp/.X11-unix:/tmp/.X11-unix

entrypoint: ["/bin/bash", "-c", "/entrypoint.sh"]
command: ["/bin/bash"]
13 changes: 13 additions & 0 deletions app/robot_status_bridge/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

cd ~/robot_status_br
# . /opt/ros/humble/setup.sh && colcon build --symlink-install

source ~/robot_status_br/install/setup.bash
ros2 run robot_status_monitor robot_status_node

while true; do
sleep 60
done

exec "$@"
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.8)
project(battery_monitor)

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(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

# add executable
add_executable(battery_publisher src/battery_publisher.cpp)
ament_target_dependencies(battery_publisher rclcpp std_msgs)
add_executable(battery_subscriber src/battery_subscriber.cpp)
ament_target_dependencies(battery_subscriber rclcpp std_msgs)

# install executable
install(TARGETS battery_publisher battery_subscriber
DESTINATION lib/${PROJECT_NAME})

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()

ament_package()
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<package format="3">
<name>battery_monitor</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="ros@todo.todo">ros</maintainer>
<license>TODO: License declaration</license>

<buildtool_depend>ament_cmake</buildtool_depend>

<depend>rclcpp</depend>
<depend>std_msgs</depend>

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

<export>
<build_type>ament_cmake</build_type>
</export>
</package>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/float32.hpp"
#include <fstream>
#include <string>

class BatteryMonitor : public rclcpp::Node {
public:
BatteryMonitor() : Node("battery_monitor") {
publisher_ = this->create_publisher<std_msgs::msg::Float32>("battery_percentage", 10);
timer_ = this->create_wall_timer(std::chrono::seconds(10), std::bind(&BatteryMonitor::publish_battery_status, this));
}

private:
void publish_battery_status() {
float battery_percentage = get_battery_percentage();
if (battery_percentage < 0.0) {
RCLCPP_WARN(this->get_logger(), "Failed to read battery percentage!");
return;
}

auto msg = std_msgs::msg::Float32();
msg.data = battery_percentage;
publisher_->publish(msg);

RCLCPP_INFO(this->get_logger(), "Published Battery Percentage: %.2f%%", battery_percentage);
}

float get_battery_percentage() {

std::ifstream file("/sys/class/power_supply/BAT0/capacity");
if (!file.is_open()) {
file.open("/sys/class/power_supply/BAT1/capacity");
}
if (!file.is_open()) {
return -1.0;
}

std::string line;
std::getline(file, line);
file.close();

try {
return std::stof(line);
} catch (...) {
return -1.0;
}
}

rclcpp::Publisher<std_msgs::msg::Float32>::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char** argv) {
rclcpp::init(argc, argv);
auto node = std::make_shared<BatteryMonitor>();
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/float32.hpp"

class BatterySubscriber : public rclcpp::Node {
public:
BatterySubscriber() : Node("battery_subscriber") {
subscription_ = this->create_subscription<std_msgs::msg::Float32>(
"battery_percentage", 10, std::bind(&BatterySubscriber::topic_callback, this, std::placeholders::_1));
}

private:
void topic_callback(const std_msgs::msg::Float32::SharedPtr msg) {
RCLCPP_INFO(this->get_logger(), "Received Battery Percentage: %.2f%%", msg->data);
}

rclcpp::Subscription<std_msgs::msg::Float32>::SharedPtr subscription_;
};

int main(int argc, char** argv) {
rclcpp::init(argc, argv);
auto node = std::make_shared<BatterySubscriber>();
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
cmake_minimum_required(VERSION 3.5)
project(robot_status_monitor)

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)

# Set msg files
set(msg_files
"msg/RobotStatus.msg"
)

# Generate ROS 2 interfaces (msg)
rosidl_generate_interfaces(${PROJECT_NAME}
${msg_files}
DEPENDENCIES std_msgs
)

# Set include directories
include_directories(${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_cpp)

add_executable(robot_status_publisher src/robot_status_publisher.cpp)
ament_target_dependencies(robot_status_publisher rclcpp std_msgs)
add_executable(robot_status_subscriber src/robot_status_subscriber.cpp)
ament_target_dependencies(robot_status_subscriber rclcpp std_msgs)

rosidl_get_typesupport_target(cpp_typesupport_target ${PROJECT_NAME} rosidl_typesupport_cpp)
target_link_libraries(robot_status_publisher ${cpp_typesupport_target})
target_link_libraries(robot_status_subscriber ${cpp_typesupport_target})

install(TARGETS
robot_status_publisher
robot_status_subscriber
DESTINATION lib/${PROJECT_NAME}
)

ament_package()
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
int32 battery_percentage
bool charging
float32 cpu_usage
float32 cpu_temperature
float32 ram_usage
int32 wifi_signal_strength
bool wifi_connected
string wifi_ssid
int32 disk_usage
string robot_ip
float32 uptime
Loading