Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Zed X Mini Stereo Camera and setup F15 #168

Merged
merged 72 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
b9aadc4
init
pascalzauberzeug Jul 24, 2024
305452f
Merge branch 'main' into zedxmini
pascalzauberzeug Jul 31, 2024
09b1790
camera works in docker as root
pascalzauberzeug Aug 1, 2024
65ae687
add venv to gitignore
pascalzauberzeug Aug 1, 2024
47a8442
rename workspace for now
pascalzauberzeug Aug 1, 2024
c2984c8
remove camera_test
pascalzauberzeug Aug 1, 2024
c91d4fb
setup docker
pascalzauberzeug Aug 1, 2024
22a4c6b
add zedxmini to sync
pascalzauberzeug Aug 1, 2024
26c0cd2
move camera into seperate directory
pascalzauberzeug Aug 1, 2024
f2ac557
wip: add camera to system
pascalzauberzeug Aug 1, 2024
34d97af
add zedxmini to sync.py
pascalzauberzeug Sep 1, 2024
3fb5ba1
further development
pascalzauberzeug Sep 1, 2024
53f93bf
Merge commit '5c2620d46843a32e4a97ec0cb9854fc6ac7bf6a4' into zedxmini
pascalzauberzeug Sep 1, 2024
f0659ad
wip: integrate stereo cameras
pascalzauberzeug Sep 1, 2024
133fe42
change port
pascalzauberzeug Sep 2, 2024
64db688
add jetpack 6 compatibility for now
pascalzauberzeug Sep 2, 2024
f8ce4ae
fix docker
pascalzauberzeug Sep 2, 2024
32220f3
Merge commit '5e3006e3b0911674118eccf774e00387c4235662' into zedxmini
pascalzauberzeug Sep 2, 2024
2dd82f3
remove unused docker
pascalzauberzeug Sep 2, 2024
ea0dc14
wip: fix sync
pascalzauberzeug Sep 2, 2024
13cda94
Merge commit '61f5b6110806f9358b85773f0e53f7ca590eb2f1' into zedxmini
pascalzauberzeug Sep 2, 2024
685a395
change back to old dockerfile
pascalzauberzeug Sep 2, 2024
c8b24be
remove camera card position for now
pascalzauberzeug Sep 2, 2024
8ce7381
temporarily add a second docker.sh for jp6
pascalzauberzeug Sep 5, 2024
3116ae6
adapt calibration dialog for zedxmini
pascalzauberzeug Sep 5, 2024
3cbe2e1
Merge commit '916d5a29b6f77e6941279c092109ca9e024a164b' into zedxmini
pascalzauberzeug Sep 5, 2024
1ff7154
fix merge
pascalzauberzeug Sep 5, 2024
412eb52
setup persistence and calibration
pascalzauberzeug Sep 6, 2024
2753619
fix camera card
pascalzauberzeug Sep 6, 2024
53a3f3b
get point3d from pointcloud
pascalzauberzeug Sep 6, 2024
39df203
raise fps
pascalzauberzeug Sep 6, 2024
ec957a4
make requests async
pascalzauberzeug Sep 6, 2024
e48b5df
remove get_depth
pascalzauberzeug Sep 6, 2024
0b5f927
Merge commit '05d608932be3496917b976a3d9cc5a8d5a3960cb' into zedxmini
pascalzauberzeug Sep 6, 2024
6798109
fix 3d positions
pascalzauberzeug Sep 6, 2024
0a9a6b5
raise shrink factor
pascalzauberzeug Sep 6, 2024
34fbf0b
view camera image without calibration
pascalzauberzeug Sep 6, 2024
0d0a82b
fix calibration
pascalzauberzeug Sep 6, 2024
8438c06
wip: remove flashlight
pascalzauberzeug Sep 6, 2024
3e788f5
wip: use ZedxminiCameraProvider
pascalzauberzeug Sep 6, 2024
ab07a01
fix 3d plant detection
pascalzauberzeug Sep 6, 2024
d273349
Merge commit '556b2894a1571dc1624457fe69742bddb1f08390' into zedxmini
pascalzauberzeug Sep 6, 2024
55a9477
f15: fix try_reference
pascalzauberzeug Sep 6, 2024
74e7909
f15: correct work_x
pascalzauberzeug Sep 6, 2024
4adc702
f15 wip: disable flashlight
pascalzauberzeug Sep 6, 2024
c3c76d4
remove log from plant locator
pascalzauberzeug Sep 6, 2024
fd54f8b
working D1
Johannes-Thiel Sep 9, 2024
c2c382c
implement work_y
Johannes-Thiel Sep 9, 2024
0cb8b0c
wip: work offset
pascalzauberzeug Sep 9, 2024
b531127
wip: deactivate 3d detection
pascalzauberzeug Sep 9, 2024
a6f8121
only sync zedxmini when parameter is set
pascalzauberzeug Sep 9, 2024
9cf4936
crossglide_demo, f15 flashlight config
LukasBaecker Sep 9, 2024
146be55
deleting timeouts
LukasBaecker Sep 9, 2024
e18cdf3
D1_axis_quick_fix
LukasBaecker Sep 9, 2024
86f89c0
cleanup
pascalzauberzeug Sep 17, 2024
d587844
fix docker compose and sh
pascalzauberzeug Sep 23, 2024
7b09ced
cleanup sync.py
pascalzauberzeug Sep 23, 2024
f84b861
add camera selection
pascalzauberzeug Sep 23, 2024
c3549a6
Merge commit '24ce27ed2f868e4921c8554ca7c0632ead184f17' into zedxmini
pascalzauberzeug Sep 23, 2024
4acf156
docker cleanup
pascalzauberzeug Sep 23, 2024
5f78ea8
plant locator cleanup
pascalzauberzeug Sep 23, 2024
2eb69f1
docker cleanup
pascalzauberzeug Sep 23, 2024
532bff9
cleanup
pascalzauberzeug Sep 23, 2024
b13fffe
Merge commit 'b9af332ca9c5db4a7004e7d60edb05d61e0043c3' into zedxmini
pascalzauberzeug Sep 24, 2024
58a8542
Merge commit '47e5d2064111a6258a2cf3ca4eabc2d85bc4a7e1' into zedxmini
pascalzauberzeug Sep 24, 2024
6538c50
calculate focal length
pascalzauberzeug Sep 24, 2024
9dcde5a
fix return value
pascalzauberzeug Sep 24, 2024
df7082f
get serial number from camera
pascalzauberzeug Sep 24, 2024
78e85e6
rename workspace
pascalzauberzeug Sep 25, 2024
bd26d84
check if zedxmini repo is available
pascalzauberzeug Sep 25, 2024
6124488
add warning to docker.sh if zedxmini not available
pascalzauberzeug Sep 25, 2024
229ff1c
wait until axis is finished referencing
pascalzauberzeug Sep 25, 2024
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
24 changes: 13 additions & 11 deletions config/f15_config_f15/camera.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
configuration = {'parameters': {
'width': 1280,
'height': 720,
'auto_exposure': True,
'fps': 10,
},
configuration = {
'type': 'ZedxminiCamera',
'parameters': {
'width': 1280,
'height': 720,
'auto_exposure': True,
'fps': 10,
},
'crop': {
'left': 60,
'right': 200,
'up': 20,
'down': 0,
}
'left': 60,
'right': 200,
'up': 20,
'down': 0,
}
}
14 changes: 10 additions & 4 deletions config/f15_config_f15/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
'min_position': -0.11,
'max_position': 0.11,
'axis_offset': 0.115,
'reversed_direction': False,
},
'z_axis': {
'version': 'axis_d1',
Expand All @@ -38,9 +39,10 @@
'profile_acceleration': 500000,
'profile_velocity': 40000,
'profile_deceleration': 500000,
'min_position': 0.230,
'max_position': 0,
'axis_offset': 0.01,
'min_position': -0.230,
'max_position': 0.0,
'axis_offset': -0.01,
'reversed_direction': True,
},
'estop': {
'name': 'estop',
Expand All @@ -61,7 +63,11 @@
'status_pin': 13,
},
'flashlight': {
'version': 'none',
'version': 'flashlight_pwm_v2',
'name': 'flashlight',
'on_expander': True,
'front_pin': 12,
'back_pin': 23,
},
'bumper': {
'name': 'bumper',
Expand Down
3 changes: 2 additions & 1 deletion config/f15_config_f15/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
'pitch': 0.033,
'wheel_distance': 0.47,
'antenna_offset': 0.205,
'work_x': 0.0125,
'work_x': -0.06933333,
'work_y': 0.0094166667,
'drill_radius': 0.025,
'tool': 'weed_screw',
}
20 changes: 20 additions & 0 deletions docker-compose.jetson.orin.zedxmini.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: "3.9"
services:
zedxmini:
restart: always
privileged: true
runtime: nvidia
build:
context: ../zedxmini
dockerfile: ../zedxmini/Dockerfile
volumes:
- ../zedxmini:/app
- /dev:/dev
- /tmp:/tmp
- /var/nvidia/nvcam/settings/:/var/nvidia/nvcam/settings
- /etc/systemd/system/zed_x_daemon.service:/etc/systemd/system/zed_x_daemon.service
- /usr/local/zed/resources:/usr/local/zed/resources
ports:
- "8003:8003"
environment:
- TZ=Europe/Amsterdam
8 changes: 8 additions & 0 deletions docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ case $os in
esac
export DOCKER_BUILDKIT=1

if [ -d /usr/local/zed ]; then
if [ -d ../zedxmini ]; then
compose_args="$compose_args -f docker-compose.jetson.orin.zedxmini.yml"
else
echo -e "\033[33mWARNING:\033[0m Zed X Mini not found. https://github.com/zauberzeug/zedxmini"
fi
fi

cmd=$1
cmd_args=${@:2}
set -x
Expand Down
3 changes: 3 additions & 0 deletions field_friend.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
},
{
"path": "../rosys"
},
{
"path": "../zedxmini"
}
],
"settings": {},
Expand Down
5 changes: 3 additions & 2 deletions field_friend/automations/implements/weeding_implement.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ async def deactivate(self):
self.kpi_provider.increment_weeding_kpi('rows_weeded')

async def start_workflow(self) -> None:
# TODO: only sleep when moving
await rosys.sleep(2) # wait for robot to stand still
if not self._has_plants_to_handle():
return
Expand Down Expand Up @@ -154,8 +155,8 @@ def _has_plants_to_handle(self) -> bool:
safe_weed_position = Point3d.from_point(Point3d.projection(weed_position).polar(
offset, Point3d.projection(crop_position).direction(weed_position)))
upcoming_weed_positions[weed] = safe_weed_position
self.log.info(f'Moved weed {weed} from {weed_position} to {safe_weed_position} ' +
f'by {offset} to safe {crop} at {crop_position}')
# self.log.info(f'Moved weed {weed} from {weed_position} to {safe_weed_position} ' +
# f'by {offset} to safe {crop} at {crop_position}')

# Sort the upcoming positions so nearest comes first
sorted_weeds = dict(sorted(upcoming_weed_positions.items(), key=lambda item: item[1].x))
Expand Down
2 changes: 2 additions & 0 deletions field_friend/automations/navigation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .navigation import Navigation, WorkflowException
from .row_on_field_navigation import RowsOnFieldNavigation
from .straight_line_navigation import StraightLineNavigation
from .crossglide_demo_navigation import CrossglideDemoNavigation

__all__ = [
'Navigation',
Expand All @@ -14,4 +15,5 @@
'FollowCropsNavigation',
'CoverageNavigation',
'ABLineNavigation',
'CrossglideDemoNavigation',
]
79 changes: 79 additions & 0 deletions field_friend/automations/navigation/crossglide_demo_navigation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from typing import TYPE_CHECKING, Any

import numpy as np
import rosys

from ...automations.implements.implement import Implement
from .navigation import Navigation

if TYPE_CHECKING:
from system import System


class WorkflowException(Exception):
pass


class CrossglideDemoNavigation(Navigation):

def __init__(self, system: 'System', tool: Implement) -> None:
super().__init__(system, tool)
self.MAX_STRETCH_DISTANCE: float = 5.0
self.detector = system.detector
self.name = 'Crossglide Demo'
self.origin: rosys.geometry.Point
self.target: rosys.geometry.Point

async def prepare(self) -> bool:
await super().prepare()
self.log.info(f'Activating {self.implement.name}...')
await self.implement.activate()
return True

async def start(self) -> None:
try:
await self.implement.stop_workflow()
if not await self.implement.prepare():
self.log.error('Tool-Preparation failed')
return
if not await self.prepare():
self.log.error('Preparation failed')
return
if isinstance(self.driver.wheels, rosys.hardware.WheelsSimulation) and not rosys.is_test:
self.create_simulation()
self.log.info('Navigation started')
while not self._should_finish():
self.implement.next_punch_y_position = np.random.uniform(-0.11, 0.1)
await self.implement.start_workflow()
except WorkflowException as e:
self.kpi_provider.increment_weeding_kpi('automation_stopped')
self.log.error(f'WorkflowException: {e}')
finally:
self.kpi_provider.increment_weeding_kpi('weeding_completed')
await self.implement.finish()
await self.finish()
await self.driver.wheels.stop()

async def finish(self) -> None:
await super().finish()
await self.implement.deactivate()

async def _drive(self, distance: float) -> None:
pass

def _should_finish(self) -> bool:
return False

def create_simulation(self):
pass
# TODO: implement create_simulation

def settings_ui(self) -> None:
super().settings_ui()

def backup(self) -> dict:
return super().backup() | {
}

def restore(self, data: dict[str, Any]) -> None:
super().restore(data)
18 changes: 17 additions & 1 deletion field_friend/automations/plant_locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
import aiohttp
import rosys
from nicegui import ui
from rosys.geometry import Point3d
from rosys.vision import Autoupload

from ..vision import CalibratableUsbCamera
from ..vision.zedxmini_camera import StereoCamera
from .plant import Plant

WEED_CATEGORY_NAME = ['coin', 'weed', 'big_weed', 'weedy_area', ]
Expand Down Expand Up @@ -100,7 +103,20 @@ async def _detect_plants(self) -> None:
if d.cx < dead_zone or d.cx > new_image.size.width - dead_zone or d.cy < dead_zone:
continue
image_point = rosys.geometry.Point(x=d.cx, y=d.cy)
world_point_3d = camera.calibration.project_from_image(image_point)
world_point_3d: rosys.geometry.Point3d | None = None
if isinstance(camera, StereoCamera):
world_point_3d = camera.calibration.project_from_image(image_point)
# TODO: 3d detection
# camera_point_3d: Point3d | None = await camera.get_point(
# int(d.cx), int(d.cy))
# if camera_point_3d is None:
# self.log.error('could not get a depth value for detection')
# continue
# camera.calibration.extrinsics = camera.calibration.extrinsics.as_frame(
# 'zedxmini').in_frame(self.odometer.prediction_frame)
# world_point_3d = camera_point_3d.in_frame(camera.calibration.extrinsics).resolve()
else:
world_point_3d = camera.calibration.project_from_image(image_point)
if world_point_3d is None:
self.log.error('could not generate world point of detection, calibration error')
continue
Expand Down
5 changes: 3 additions & 2 deletions field_friend/automations/puncher.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ async def punch(self,
turns: float = 2.0,
with_open_tornado: bool = False,
) -> None:
y += self.field_friend.WORK_Y
self.log.info(f'Punching at {y} with depth {depth}...')
rest_position = 'reference'
if self.field_friend.y_axis is None or self.field_friend.z_axis is None:
Expand All @@ -78,7 +79,7 @@ async def punch(self,
rosys.notify('homing failed!', type='negative')
self.log.error('homing failed!')
raise PuncherException('homing failed')
await rosys.sleep(0.5)
# await rosys.sleep(0.5)
if isinstance(self.field_friend.y_axis, ChainAxis):
if not self.field_friend.y_axis.min_position <= y <= self.field_friend.y_axis.max_position:
rosys.notify('y position out of range', type='negative')
Expand Down Expand Up @@ -120,7 +121,7 @@ async def clear_view(self) -> None:
await self.field_friend.y_axis.return_to_reference()
return
elif isinstance(self.field_friend.y_axis, Axis):
if isinstance(self.field_friend.z_axis,Axis):
if isinstance(self.field_friend.z_axis, Axis):
if self.field_friend.z_axis.position != 0:
await self.field_friend.z_axis.return_to_reference()
y = self.field_friend.y_axis.min_position if self.field_friend.y_axis.position <= 0 else self.field_friend.y_axis.max_position
Expand Down
4 changes: 2 additions & 2 deletions field_friend/hardware/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ async def try_reference(self) -> bool:
return True

def compute_steps(self, position: float) -> int:
"""Compute the number of steps to move the y axis to the given position.
"""Compute the number of steps to move the axis to the given position.

The position is given in meters.
"""
return int((position + self.axis_offset) * self.steps_per_m) * (-1 if self.reversed_direction else 1)

def compute_position(self, steps: int) -> float:
return steps / self.steps_per_m - self.axis_offset * (-1 if self.reversed_direction else 1)
return steps / self.steps_per_m * (-1 if self.reversed_direction else 1) - self.axis_offset

@property
def position(self) -> float:
Expand Down
Loading
Loading