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
4 changes: 2 additions & 2 deletions .github/scripts/check_people_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ def main(model: str, image: str, backends: list[str]) -> int:
try:
import cv2

sys.path.insert(0, 'src/robot_perception')
from robot_perception.detector import OnnxPersonDetector
sys.path.insert(0, 'src/pashupati_perception')
from pashupati_perception.detector import OnnxPersonDetector
except Exception: # noqa: B902 the environment itself is broken: say how
annotate('error', 'imports', traceback.format_exc()[-1500:])
return 1
Expand Down
17 changes: 13 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ env:
ROSDEP_SKIP: >-
livox_ros_driver2 fast_lio legkilo apriltag_draw
PACKAGES: >-
robot_interfaces robot_odometry robot_localization robot_perception robot_navigation
robot_bridge robot_fleet robot_inspection robot_health robot_rviz pashupati robot_sim
pashupati_perception robot_bridge robot_fleet robot_inspection robot_health robot_rviz
pashupati robot_sim

jobs:
scripts:
Expand Down Expand Up @@ -87,6 +87,15 @@ jobs:
shell: bash
steps:
- uses: actions/checkout@v4 # no submodules: they need SSH keys and vendor SDKs
- name: Dharma packages
env:
# the dharma repos are private: a fine-grained token with read access to them
DHARMA_TOKEN: ${{ secrets.DHARMA_TOKEN }}
run: |
apt-get update && apt-get install -y python3-vcstool git
git config --global url."https://x-access-token:${DHARMA_TOKEN}@github.com/".insteadOf \
"git@github.com:"
vcs import src < pashupati.repos
- name: Dependencies
run: |
apt-get update
Expand All @@ -96,7 +105,7 @@ jobs:
- name: Build
run: |
source /opt/ros/humble/setup.bash
colcon build --packages-select $PACKAGES --event-handlers console_cohesion+
colcon build --packages-up-to $PACKAGES --event-handlers console_cohesion+
- name: Test
run: |
source /opt/ros/humble/setup.bash
Expand All @@ -118,7 +127,7 @@ jobs:
source /opt/ros/humble/setup.bash
source install/setup.bash
ros2 launch pashupati robot.launch.py --show-args > /dev/null
ros2 launch robot_odometry odometry.launch.py --show-args > /dev/null
ros2 launch dharma_odometry odometry.launch.py --show-args > /dev/null
ros2 launch robot_sim sim.launch.py --show-args > /dev/null
- name: Test reports
if: always()
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/people-model.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
push:
branches: [dev]
paths:
- src/robot_perception/robot_perception/detector.py
- src/pashupati_perception/pashupati_perception/detector.py
- .github/scripts/check_people_model.py
- .github/workflows/people-model.yml
workflow_dispatch:
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ desktop.ini
.cache/
__MACOSX/

.vscode/settings.json
.vscode/settings.json

# ---- dharma packages (vcs import src < pashupati.repos) ----
src/dharma/
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pure-logic tests also run with plain `pytest` on a laptop.
`OPENBLAS_NUM_THREADS=1`.
- **No per-element Python objects at sensor rate.** rclpy builds one object per element of a
message array (a Livox CustomMsg has ~20k points): read big messages as numpy straight from the
buffer (`PointCloud2.data`, or `raw=True` and the CDR bytes, see `robot_perception/livox_cdr.py`).
buffer (`PointCloud2.data`, or `raw=True` and the CDR bytes, see `pashupati_perception/livox_cdr.py`).
- **Subscribe to heavy topics only while someone uses them** (the teleop camera and cloud).
- **Validate everything from the network** (teleop UDP, NETRA commands, spool files): clamp
numbers, reject non-finite values, keep file paths inside their directory, never raise in a
Expand Down
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ flowchart LR

| Package | Role |
|---|---|
| [`robot_interfaces`](src/robot_interfaces) | messages and services |
| [`robot_odometry`](src/robot_odometry) | LiDAR-inertial odometry (FAST-LIO2 or Leg-KILO), stillness gate, odometry monitor, route recording |
| [`robot_localization`](src/robot_localization) | FAST-LIO frame bridge, `map→odom` from AprilTags / RViz, tag recording |
| [`robot_perception`](src/robot_perception) | LiDAR sectors, AprilTag, person detection (YOLO11n ONNX) |
| [`robot_navigation`](src/robot_navigation) | route processing, 5 controllers, 4 avoidance algorithms, final approach, safety |
| [`dharma_interfaces`](src/dharma_interfaces) | messages and services |
| [`dharma_odometry`](src/dharma_odometry) | LiDAR-inertial odometry (FAST-LIO2 or Leg-KILO), stillness gate, odometry monitor, route recording |
| [`dharma_localization`](src/dharma_localization) | FAST-LIO frame bridge, `map→odom` from AprilTags / RViz, tag recording |
| [`pashupati_perception`](src/pashupati_perception) | LiDAR sectors, AprilTag, person detection (YOLO11n ONNX) |
| [`dharma_navigation`](src/dharma_navigation) | route processing, 5 controllers, 4 avoidance algorithms, final approach, safety |
| [`robot_bridge`](src/robot_bridge) | AUTO / REMOTE control mux, UDP teleop gateway ([protocol](src/robot_bridge/PROTOCOL.md)), WebRTC video |
| [`robot_fleet`](src/robot_fleet) | NETRA uplink: telemetry, events, crowd, anomalies, routes ([API](src/robot_fleet/API.md)) |
| [`robot_inspection`](src/robot_inspection) | VLM inspection (Ollama): continuous, interval queue or stop points, own finding types |
Expand Down Expand Up @@ -255,7 +255,7 @@ pnode robot_bridge teleop_udp_node bridge_params.yaml # one node, as robot.lau
**Start**), or by hand:

```bash
ros2 service call /navigation/load_path robot_interfaces/srv/LoadPath "{waypoints_file: '/home/robot/dev/Pashupati/map/<date>/<time>_path.csv'}"
ros2 service call /navigation/load_path dharma_interfaces/srv/LoadPath "{waypoints_file: '/home/robot/dev/Pashupati/map/<date>/<time>_path.csv'}"
ros2 service call /navigation/start_nav std_srvs/srv/SetBool "{data: true}"
```

Expand Down Expand Up @@ -312,11 +312,11 @@ the tuned values with **Save YAML**.
| Service | Type | Node |
|---|---|---|
| `/route/record` | `std_srvs/SetBool` | route_recorder_node |
| `/route/mark_stop_point` | `robot_interfaces/MarkStopPoint` | route_recorder_node |
| `/route/mark_stop_point` | `dharma_interfaces/MarkStopPoint` | route_recorder_node |
| `/localization/start`, `/localization/record_tags` | `std_srvs/Trigger` | localization_node |
| `/navigation/load_path` | `robot_interfaces/LoadPath` | path_loader_node |
| `/navigation/load_path` | `dharma_interfaces/LoadPath` | path_loader_node |
| `/navigation/start_nav`, `/navigation/pause` | `std_srvs/SetBool` | path_follower_node |
| `/bridge/set_mode` | `robot_interfaces/SetMode` | control_mux_node |
| `/bridge/set_mode` | `dharma_interfaces/SetMode` | control_mux_node |
| `/bridge/estop` | `std_srvs/SetBool` (`true` engages, `false` releases) | control_mux_node |
| `/anomaly_detector_node/check_now` | `std_srvs/Trigger` | anomaly_detector_node |
| `/<robot_ns>/<command>` | `std_srvs/Trigger` | robot driver ([contract](src/xtras/README.md)) |
Expand All @@ -337,11 +337,11 @@ the tuned values with **Save YAML**.
| `/odometry/status` | `std_msgs/String` (latched) | odometry_monitor_node |
| `/odometry/restarted` | `std_msgs/Empty` | odometry_monitor_node |
| `/localization/status` | `std_msgs/String` (latched) | localization_node |
| `/navigation/waypoints` | `robot_interfaces/WaypointPath` (latched) | path_loader_node |
| `/navigation/status`, `/navigation/mission_status`, `/navigation/stop_point_event` | robot_interfaces | path_follower_node |
| `/navigation/waypoints` | `dharma_interfaces/WaypointPath` (latched) | path_loader_node |
| `/navigation/status`, `/navigation/mission_status`, `/navigation/stop_point_event` | dharma_interfaces | path_follower_node |
| `/navigation/markers`, `/navigation/route_markers`, `/navigation/avoidance_markers` | `MarkerArray` | navigation |
| `/perception/sector_scan` | `robot_interfaces/SectorScan` | lidar_sector_node |
| `/perception/safety_scan` | `robot_interfaces/SectorScan` (360°, all blocked when the LiDAR is blind) | lidar_sector_node |
| `/perception/sector_scan` | `dharma_interfaces/SectorScan` | lidar_sector_node |
| `/perception/safety_scan` | `dharma_interfaces/SectorScan` (360°, all blocked when the LiDAR is blind) | lidar_sector_node |
| `/perception/people`, `/perception/people_status` | `geometry_msgs/PoseArray`, `std_msgs/String` (JSON, latched) | person_detector_node |
| `/anomaly_detector/result`, `/anomaly_detector/status` | `std_msgs/String` (JSON; status latched) | anomaly_detector_node |
| `/health/status` | `std_msgs/String` (JSON, latched) | health_monitor_node |
Expand Down
8 changes: 4 additions & 4 deletions docs/pdf/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@

# Config files of the parameter reference, in reading order: (package, file, what it covers)
PARAMETER_FILES = [
('robot_navigation', 'navigation_params.yaml', 'route following, avoidance, stops'),
('pashupati', 'navigation_params.yaml', 'route following, avoidance, stops'),
('robot_bridge', 'bridge_params.yaml', 'control mux, protective field, handheld, video'),
('robot_perception', 'perception_params.yaml', 'LiDAR sectors, people, AprilTags'),
('robot_localization', 'localization_params.yaml', 'map frame from AprilTags'),
('pashupati', 'perception_params.yaml', 'LiDAR sectors, people, AprilTags'),
('pashupati', 'localization_params.yaml', 'map frame from AprilTags'),
('robot_inspection', 'inspection_params.yaml', 'AI inspection'),
('robot_odometry', 'odometry_params.yaml', 'odometry start, monitor, route recording'),
('pashupati', 'odometry_params.yaml', 'odometry start, monitor, route recording'),
('robot_health', 'health_params.yaml', 'health monitor'),
('robot_fleet', 'fleet_params.yaml', 'NETRA uplink'),
]
Expand Down
22 changes: 22 additions & 0 deletions pashupati.repos
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Dharma packages Pashupati runs on: vcs import src < pashupati.repos
repositories:
dharma/dharma_interfaces:
type: git
url: git@github.com:DarmawanRobotics/dharma_interfaces.git
version: dev
dharma/dharma_odometry:
type: git
url: git@github.com:DarmawanRobotics/dharma_odometry.git
version: dev
dharma/dharma_localization:
type: git
url: git@github.com:DarmawanRobotics/dharma_localization.git
version: dev
dharma/dharma_navigation:
type: git
url: git@github.com:DarmawanRobotics/dharma_navigation.git
version: dev
dharma/dharma_perception:
type: git
url: git@github.com:DarmawanRobotics/dharma_perception.git
version: dev
25 changes: 22 additions & 3 deletions script/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# script/setup.sh install livox build # install only these
# script/setup.sh install all # every component, including ros and service
#
# Components: ros tools submodules livox robot legkilo rosdep realsense webrtc ollama people_model
# Components: ros tools submodules dharma livox robot legkilo rosdep realsense webrtc ollama people_model
# build config service network
# Settings come from the environment, then from /etc/pashupati/pashupati.env (ROBOT_SETUP,
# ROBOT_IP, PEOPLE, INSPECTION, ...): no need to source it first.
Expand Down Expand Up @@ -64,9 +64,9 @@ BUILD_STAMP="$ROOT/install/.pashupati_build"
UVC_BLACKLIST=/etc/modprobe.d/blacklist-uvcvideo-realsense.conf
REALSENSE_BLACKLIST_UVC="${REALSENSE_BLACKLIST_UVC:-$([[ "$(uname -m)" == aarch64 ]] && echo 1 || echo 0)}"

ALL=(ros tools submodules livox robot legkilo rosdep realsense webrtc ollama people_model build
ALL=(ros tools submodules dharma livox robot legkilo rosdep realsense webrtc ollama people_model build
config service network)
DEFAULT_INSTALL=(tools submodules livox robot legkilo rosdep realsense webrtc ollama build config)
DEFAULT_INSTALL=(tools submodules dharma livox robot legkilo rosdep realsense webrtc ollama build config)

SUDO=$([[ "$(id -u)" -eq 0 ]] && echo "" || echo "sudo")
IN_DOCKER=$([[ -f /.dockerenv ]] && echo 1 || echo 0)
Expand Down Expand Up @@ -147,6 +147,25 @@ install_submodules() {
submodule update --init --recursive
}

check_dharma() {
local missing=() name
for name in $(awk '/^ dharma\// {sub(":", ""); print $1}' "$ROOT/pashupati.repos"); do
[[ -f "$ROOT/src/$name/README.md" ]] || missing+=("$name")
done
[[ ${#missing[@]} -eq 0 ]] && echo "src/dharma: all checked out" && return 0
echo "not checked out: ${missing[*]}"; return 1
}
install_dharma() {
command -v vcs >/dev/null || apt_install python3-vcstool
if ! vcs import --skip-existing "$ROOT/src" < "$ROOT/pashupati.repos"; then
log "SSH clone failed, retrying the dharma packages over HTTPS"
GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=url.https://github.com/.insteadOf \
GIT_CONFIG_VALUE_0=git@github.com: \
vcs import --skip-existing "$ROOT/src" < "$ROOT/pashupati.repos"
fi
vcs pull "$ROOT/src/dharma"
}

check_livox() {
[[ -f /usr/local/lib/liblivox_lidar_sdk_shared.so ]] \
&& echo "/usr/local/lib/liblivox_lidar_sdk_shared.so" && return 0
Expand Down
12 changes: 8 additions & 4 deletions script/start_tmux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,13 @@ else
tmux send-keys -t "$SESSION:robot.0" "# ROBOT_BRINGUP unset: start the robot driver here" C-m
fi
sleep 3
run robot.1 "ros2 launch robot_odometry odometry.launch.py method:=$ODOMETRY save_map:=$SAVE_MAP \
localization:=true tags_config_file:=$TAGS leg_odom_topic:=/$ROBOT_NS/odom"
run robot.2 "ros2 launch robot_perception perception.launch.py people:=$PEOPLE"
CONFIG="\$(ros2 pkg prefix pashupati)/share/pashupati/config"
run robot.1 "ros2 launch dharma_odometry odometry.launch.py method:=$ODOMETRY save_map:=$SAVE_MAP \
localization:=true tags_config_file:=$TAGS leg_odom_topic:=/$ROBOT_NS/odom \
params_file:=$CONFIG/odometry_params.yaml fast_lio_params_file:=$CONFIG/fast_lio.yaml"
PERCEPTION="ros2 launch dharma_perception perception.launch.py visitors:=false params_file:=$CONFIG/perception_params.yaml"
[[ "$PEOPLE" == "true" ]] && PERCEPTION+=" & ros2 launch pashupati_perception people.launch.py"
run robot.2 "$PERCEPTION"
if [[ "$RVIZ" == "1" ]]; then
run robot.3 "ros2 run rviz2 rviz2 -d \$(ros2 pkg prefix robot_rviz)/share/robot_rviz/rviz/robot.rviz \
--ros-args -r battery:=/$ROBOT_NS/battery -r cmd_vel:=/$ROBOT_NS/cmd_vel \
Expand All @@ -77,7 +81,7 @@ tmux select-layout -t "$SESSION:robot" tiled
tmux new-window -t "$SESSION" -n nav
tmux split-window -v -t "$SESSION:nav"
if [[ "$MODE" == "patrol" ]]; then
run nav.0 "ros2 launch robot_navigation navigation.launch.py waypoints_file:=$ROUTE \
run nav.0 "ros2 launch dharma_navigation navigation.launch.py params_file:=$CONFIG/navigation_params.yaml waypoints_file:=$ROUTE \
cmd_vel_topic:=/bridge/nav_cmd_vel battery_topic:=/$ROBOT_NS/battery"
fi
tmux split-window -h -t "$SESSION:nav.0"
Expand Down
2 changes: 1 addition & 1 deletion src/pashupati/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ provide.
| `robot_ns` | `$ROBOT_NS` or `robot` | robot driver namespace (`/robot/cmd_vel`, `/robot/odom`, ...) |
| `robot_bringup` | `$ROBOT_BRINGUP` | robot package `<package>[/<file>.launch.py]`, started with `namespace:=<robot_ns>`; empty: the robot runs elsewhere (simulator, vendor service) |
| `mode` | `$MODE` or `patrol` | `teach` keeps the map (FAST-LIO PCD / Leg-KILO backend, RAM grows); `mapping` still works |
| `odometry` | `$ODOMETRY` or `fast_lio` | `fast_lio`, `leg_kilo` or `external` (simulator) ([robot_odometry](../robot_odometry)) |
| `odometry` | `$ODOMETRY` or `fast_lio` | `fast_lio`, `leg_kilo` or `external` (simulator) ([dharma_odometry](../dharma_odometry)) |
| `route` | `$ROUTE` | route CSV; empty reloads the last route loaded through `navigation/load_path` |
| `tags` | `$TAGS` | AprilTag map poses (JSON), created by `localization/record_tags` |
| `cc_url`, `cc_token` | `$CC_URL`, `$CC_TOKEN` | NETRA command center |
Expand Down
29 changes: 17 additions & 12 deletions src/pashupati/launch/robot.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ def node(package, executable, defaults, overrides=None, remappings=None, **kwarg
**kwargs,
)

nav = share('robot_navigation', 'config', 'navigation_params.yaml')
perception = share('robot_perception', 'config', 'perception_params.yaml')
nav = share('pashupati', 'config', 'navigation_params.yaml')
perception = share('pashupati', 'config', 'perception_params.yaml')
bridge = share('robot_bridge', 'config', 'bridge_params.yaml')
version = package_version(share('pashupati', 'package.xml'))
git = os.environ.get('PASHUPATI_GIT', 'unknown')
Expand All @@ -185,28 +185,33 @@ def node(package, executable, defaults, overrides=None, remappings=None, **kwarg
actions.append(mediamtx)
actions.append(
IncludeLaunchDescription(
PythonLaunchDescriptionSource(share('robot_odometry', 'launch', 'odometry.launch.py')),
PythonLaunchDescriptionSource(
share('dharma_odometry', 'launch', 'odometry.launch.py')
),
launch_arguments={
'method': odometry,
'save_map': str(mode == 'teach'),
'respawn': 'true',
'record': 'true',
'leg_odom_topic': topic('odom'),
'site_config': site[0] if site else '',
'params_file': share('pashupati', 'config', 'odometry_params.yaml'),
'fast_lio_params_file': share('pashupati', 'config', 'fast_lio.yaml'),
'leg_kilo_config_file': share('pashupati', 'config', 'leg_kilo.yaml'),
}.items(),
)
)
actions += [
node(
'robot_localization',
'dharma_localization',
'localization_node',
[share('robot_localization', 'config', 'localization_params.yaml')],
[share('pashupati', 'config', 'localization_params.yaml')],
{'tags_config_file': arg('tags')},
),
node('robot_perception', 'lidar_sector_node', [perception]),
node('dharma_perception', 'lidar_sector_node', [perception]),
# the tag detector sees the camera at rate_hz only: localization needs a few poses/s
node(
'robot_perception',
'dharma_perception',
'image_throttle_node',
[perception],
name='apriltag_throttle',
Expand All @@ -231,16 +236,16 @@ def node(package, executable, defaults, overrides=None, remappings=None, **kwarg
respawn_delay=3.0,
output='screen',
),
node('robot_navigation', 'path_loader_node', [nav], {'waypoints_file': arg('route')}),
node('robot_navigation', 'obstacle_avoidance_node', [nav]),
node('dharma_navigation', 'path_loader_node', [nav], {'waypoints_file': arg('route')}),
node('dharma_navigation', 'obstacle_avoidance_node', [nav]),
node(
'robot_navigation',
'dharma_navigation',
'path_follower_node',
[nav],
remappings=[('cmd_vel', '/bridge/nav_cmd_vel'), ('battery', topic('battery'))],
),
node(
'robot_bridge',
'dharma_control',
'control_mux_node',
[bridge],
remappings=[('cmd_vel', topic('cmd_vel'))],
Expand Down Expand Up @@ -277,7 +282,7 @@ def node(package, executable, defaults, overrides=None, remappings=None, **kwarg
else:
actions.append(LogInfo(msg='NETRA uplink off: no cc_url (CC_URL)'))
if truthy(arg('people')):
actions.append(node('robot_perception', 'person_detector_node', [perception]))
actions.append(node('pashupati_perception', 'person_detector_node', [perception]))
if truthy(arg('inspection')):
actions.append(
node(
Expand Down
10 changes: 6 additions & 4 deletions src/pashupati/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
<exec_depend>launch_ros</exec_depend>
<exec_depend>python3-yaml</exec_depend>
<exec_depend>apriltag_ros</exec_depend>
<exec_depend>robot_odometry</exec_depend>
<exec_depend>robot_localization</exec_depend>
<exec_depend>robot_perception</exec_depend>
<exec_depend>robot_navigation</exec_depend>
<exec_depend>dharma_odometry</exec_depend>
<exec_depend>dharma_localization</exec_depend>
<exec_depend>dharma_perception</exec_depend>
<exec_depend>pashupati_perception</exec_depend>
<exec_depend>dharma_control</exec_depend>
<exec_depend>dharma_navigation</exec_depend>
<exec_depend>robot_bridge</exec_depend>
<exec_depend>robot_fleet</exec_depend>
<exec_depend>robot_inspection</exec_depend>
Expand Down
Loading
Loading