Skip to content

Commit

Permalink
feat: Export Capella
Browse files Browse the repository at this point in the history
  • Loading branch information
huyenngn committed Jan 10, 2024
1 parent b026a02 commit 1ddb920
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 69 deletions.
27 changes: 18 additions & 9 deletions capella_ros_tools/modules/capella/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,27 @@ def get_enums(self, package: t.Any) -> list[EnumDef]:
"""Get enums in Capella model."""
enums = []
for enum in package.enumerations:
values = []
for literal in enum.owned_literals:
try:
type_name = literal.value.type.name
literal_value = literal.value.value
except AttributeError:
type_name = ""
literal_value = ""

values.append(
EnumValue(
type_name,
literal.name,
literal_value,
literal.description,
)
)
enums.append(
EnumDef(
enum.name,
[
EnumValue(
literal.value.type.name,
literal.name,
literal.value.value,
literal.description,
)
for literal in enum.owned_literals
],
values,
enum.description,
)
)
Expand Down
7 changes: 4 additions & 3 deletions capella_ros_tools/scripts/capella2msg.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,14 @@ def _add_package(self, current_root: t.Any) -> MessagePkgDef:
[
ConstantDef(
BaseTypeDef(
CAPELLA_TYPE_TO_MSG[value.type]
CAPELLA_TYPE_TO_MSG.get(value.type)
or "uint8"
),
value.name,
str(value.value),
value.value or str(i),
value.description.split("\n"),
)
for value in enum.values
for i, value in enumerate(enum.values)
],
[],
)
Expand Down
13 changes: 6 additions & 7 deletions docs/source/examples/Export capella.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,28 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import capellambse\n",
"from capella_ros_tools.scripts import capella2msg\n",
"from pathlib import Path"
]
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"msg_path = Path(\"data/coffee_msgs\")\n",
"capella_path = capellambse.filehandler.get_filehandler(\"git+https://github.com/DSD-DBS/coffee-machine\")\n",
"msg_path = Path(\"data/test\")\n",
"capella_path = Path(\"data/melody_model_60\")\n",
"layer = \"la\""
]
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 3,
"metadata": {},
"outputs": [
{
Expand All @@ -49,7 +48,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
Expand Down
122 changes: 122 additions & 0 deletions docs/source/examples/Parse capella.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Parse Capella"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from capella_ros_tools.modules.capella.parser import CapellaModel\n",
"from pathlib import Path"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Cannot load PVMT extension: ValueError: Provided model does not have a PropertyValuePkg\n",
"Property values are not available in this model\n"
]
}
],
"source": [
"model = CapellaModel(Path(\"data/melody_model_60\"), \"la\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'Wand Objects'}"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.get_packages(model.data)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[ClassDef(name='Wand', properties=[ClassProperty(type_name='String', type_pkg_name=None, name='owner', min_card='1', max_card='1', description=''), ClassProperty(type_name='Wand Core', type_pkg_name=None, name='core', min_card='1', max_card='1', description=''), ClassProperty(type_name='Wand Wood', type_pkg_name=None, name='wood', min_card='1', max_card='1', description='')], description=''),\n",
" ClassDef(name='Class 2', properties=[], description='')]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.get_classes(model.data)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[EnumDef(name='Wand Core', values=[EnumValue(type='', name='Unicorn Hair', value='', description=''), EnumValue(type='', name='Dragon Heartstring', value='', description=''), EnumValue(type='', name='Pheonix Feather', value='', description=''), EnumValue(type='', name='Thestral Tail-Hair', value='', description='')], description=''),\n",
" EnumDef(name='Wand Wood', values=[EnumValue(type='', name='Apple', value='', description=''), EnumValue(type='', name='Cedar', value='', description=''), EnumValue(type='', name='Ebony', value='', description=''), EnumValue(type='', name='Elder', value='', description=''), EnumValue(type='', name='Holly', value='', description='')], description='')]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.get_enums(model.data)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".capella_venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
2 changes: 2 additions & 0 deletions docs/source/examples/Parse capella.ipynb.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Copyright DB InfraGO AG and contributors
# SPDX-License-Identifier: CC0-1.0
52 changes: 3 additions & 49 deletions docs/source/examples/Parse messages.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"source": [
"from capella_ros_tools.modules.messages.parser import MessageDef\n",
"from pathlib import Path\n",
"from IPython.display import display\n"
"from IPython.display import display"
]
},
{
Expand Down Expand Up @@ -72,56 +72,10 @@
{
"data": {
"text/html": [
"<h1>CameraInfo</h1><p># This message defines meta information for a camera. It should be in a<br># camera namespace on topic \"camera_info\" and accompanied by up to five<br># image topics named:<br>#<br># image_raw - raw data from the camera driver, possibly Bayer encoded<br># image - monochrome, distorted<br># image_color - color, distorted<br># image_rect - monochrome, rectified<br># image_rect_color - color, rectified<br>#<br># The image_pipeline contains packages (image_proc, stereo_image_proc)<br># for producing the four processed image topics from image_raw and<br># camera_info. The meaning of the camera parameters are described in<br># detail at http://www.ros.org/wiki/image_pipeline/CameraInfo.<br>#<br># The image_geometry package provides a user-friendly interface to<br># common operations using this meta information. If you want to, e.g.,<br># project a 3d point into image coordinates, we strongly recommend<br># using image_geometry.<br>#<br># If the camera is uncalibrated, the matrices D, K, R, P should be left<br># zeroed out. In particular, clients may assume that K[0] == 0.0<br># indicates an uncalibrated camera.<br>#######################################################################<br># Image acquisition info #<br>#######################################################################<br>#######################################################################<br># Calibration Parameters #<br>#######################################################################<br># These are fixed during camera calibration. Their values will be the #<br># same in all messages until the camera is recalibrated. Note that #<br># self-calibrating systems may \"recalibrate\" frequently. #<br># #<br># The internal parameters can be used to warp a raw (distorted) image #<br># to: #<br># 1. An undistorted image (requires D and K) #<br># 2. A rectified image (requires D, K, R) #<br># The projection matrix P projects 3D points into the rectified image.#<br>#######################################################################<br>#######################################################################<br># Operational Parameters #<br>#######################################################################<br># These define the image region actually captured by the camera #<br># driver. Although they affect the geometry of the output image, they #<br># may be changed freely without recalibrating the camera. #<br>#######################################################################</p><h2>Fields</h2><ol><li>std_msgs/Header header<br># Time of image acquisition, camera coordinate frame ID<br># Header timestamp should be acquisition time of image<br># Header frame_id should be optical frame of camera<br># origin of frame should be optical center of camera<br># +x should point to the right in the image<br># +y should point down in the image<br># +z should point into the plane of the image</li><li>uint32 height<br># The image dimensions with which the camera was calibrated.<br># Normally this will be the full camera resolution in pixels.</li><li>uint32 width<br># The image dimensions with which the camera was calibrated.<br># Normally this will be the full camera resolution in pixels.</li><li>string distortion_model<br># The distortion model used. Supported models are listed in<br># sensor_msgs/distortion_models.hpp. For most cameras, \"plumb_bob\" - a<br># simple model of radial and tangential distortion - is sufficent.</li><li>float64[] d<br># The distortion parameters, size depending on the distortion model.<br># For \"plumb_bob\", the 5 parameters are: (k1, k2, t1, t2, k3).</li><li>float64[9] k<br># Intrinsic camera matrix for the raw (distorted) images.<br># [fx 0 cx]<br># K = [ 0 fy cy]<br># [ 0 0 1]<br># Projects 3D points in the camera coordinate frame to 2D pixel<br># coordinates using the focal lengths (fx, fy) and principal point<br># (cx, cy).<br># 3x3 row-major matrix</li><li>float64[9] r<br># Rectification matrix (stereo cameras only)<br># A rotation matrix aligning the camera coordinate system to the ideal<br># stereo image plane so that epipolar lines in both stereo images are<br># parallel.<br># 3x3 row-major matrix</li><li>float64[12] p<br># Projection/camera matrix<br># [fx' 0 cx' Tx]<br># P = [ 0 fy' cy' Ty]<br># [ 0 0 1 0]<br># By convention, this matrix specifies the intrinsic (camera) matrix<br># of the processed (rectified) image. That is, the left 3x3 portion<br># is the normal camera intrinsic matrix for the rectified image.<br># It projects 3D points in the camera coordinate frame to 2D pixel<br># coordinates using the focal lengths (fx', fy') and principal point<br># (cx', cy') - these may differ from the values in K.<br># For monocular cameras, Tx = Ty = 0. Normally, monocular cameras will<br># also have R = the identity and P[1:3,1:3] = K.<br># For a stereo pair, the fourth column [Tx Ty 0]' is related to the<br># position of the optical center of the second camera in the first<br># camera's frame. We assume Tz = 0 so both cameras are in the same<br># stereo image plane. The first camera always has Tx = Ty = 0. For<br># the right (second) camera of a horizontal stereo pair, Ty = 0 and<br># Tx = -fx' * B, where B is the baseline between the cameras.<br># Given a 3D point [X Y Z]', the projection (x, y) of the point onto<br># the rectified image is given by:<br># [u v w]' = P * [X Y Z 1]'<br># x = u / w<br># y = v / w<br># This holds for both images of a stereo pair.<br># 3x4 row-major matrix</li><li>uint32 binning_x<br># Binning refers here to any camera setting which combines rectangular<br># neighborhoods of pixels into larger \"super-pixels.\" It reduces the<br># resolution of the output image to<br># (width / binning_x) x (height / binning_y).<br># The default values binning_x = binning_y = 0 is considered the same<br># as binning_x = binning_y = 1 (no subsampling).</li><li>uint32 binning_y<br># Binning refers here to any camera setting which combines rectangular<br># neighborhoods of pixels into larger \"super-pixels.\" It reduces the<br># resolution of the output image to<br># (width / binning_x) x (height / binning_y).<br># The default values binning_x = binning_y = 0 is considered the same<br># as binning_x = binning_y = 1 (no subsampling).</li><li>RegionOfInterest roi<br># Region of interest (subwindow of full camera resolution), given in<br># full resolution (unbinned) image coordinates. A particular ROI<br># always denotes the same window of pixels on the camera sensor,<br># regardless of binning settings.<br># The default setting of roi (all values 0) is considered the same as<br># full resolution (roi.width = width, roi.height = height).</li></ol><h2>Enums</h2><ol></ol>"
"<h1>PointCloud2</h1><p># Copyright DB InfraGO AG and contributors<br># SPDX-License-Identifier: CC0-1.0<br>#<br># This message holds a collection of N-dimensional points, which may<br># contain additional information such as normals, intensity, etc. The<br># point data is stored as a binary blob, its layout described by the<br># contents of the \"fields\" array.<br>#<br># The point cloud data may be organized 2d (image-like) or 1d (unordered).<br># Point clouds organized as 2d images may be produced by camera depth sensors<br># such as stereo or time-of-flight.</p><h2>Fields</h2><ol><li>std_msgs/Header header<br># Time of sensor data acquisition, and the coordinate frame ID (for 3d points).</li><li>uint32 height<br># 2D structure of the point cloud. If the cloud is unordered, height is<br># 1 and width is the length of the point cloud.</li><li>uint32 width<br># 2D structure of the point cloud. If the cloud is unordered, height is<br># 1 and width is the length of the point cloud.</li><li>PointField[] fields<br># Describes the channels and their layout in the binary data blob.</li><li>bool is_bigendian<br># Is this data bigendian?</li><li>uint32 point_step<br># Length of a point in bytes</li><li>uint32 row_step<br># Length of a row in bytes</li><li>uint8[] data<br># Actual point data, size is (row_step*height)</li><li>bool is_dense<br># True if there are no invalid points</li></ol><h2>Enums</h2><ol></ol>"
],
"text/plain": [
"<capella_ros_tools.modules.messages.parser.MessageDef at 0x7f3594025570>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"msgs = MessageDef.from_msg_file(Path(\"data/example_msgs/CameraInfo.msg\"))\n",
"display(msgs)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<h1>DiagnosticStatus</h1><p># This message holds the status of an individual component of the robot.</p><h2>Fields</h2><ol><li>DiagnosticStatusLevel level<br># Level of operation enumerated above.</li><li>string name<br># A description of the test/component reporting.</li><li>string message<br># A description of the status.</li><li>string hardware_id<br># A hardware unique string.</li><li>KeyValue[] values<br># An array of values associated with the status.</li></ol><h2>Enums</h2><ol><li><b>DiagnosticStatusLevel</b><br># Possible levels of operations.<ul><li>byte OK = 0<br></li><li>byte WARN = 1<br></li><li>byte ERROR = 2<br></li><li>byte STALE = 3<br></li></ul></li></ol>"
],
"text/plain": [
"<capella_ros_tools.modules.messages.parser.MessageDef at 0x7f358c664fd0>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"msgs = MessageDef.from_msg_file(Path(\"data/example_msgs/DiagnosticStatus.msg\"))\n",
"display(msgs)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<h1>PointCloud2</h1><p># This message holds a collection of N-dimensional points, which may<br># contain additional information such as normals, intensity, etc. The<br># point data is stored as a binary blob, its layout described by the<br># contents of the \"fields\" array.<br>#<br># The point cloud data may be organized 2d (image-like) or 1d (unordered).<br># Point clouds organized as 2d images may be produced by camera depth sensors<br># such as stereo or time-of-flight.</p><h2>Fields</h2><ol><li>std_msgs/Header header<br># Time of sensor data acquisition, and the coordinate frame ID (for 3d points).</li><li>uint32 height<br># 2D structure of the point cloud. If the cloud is unordered, height is<br># 1 and width is the length of the point cloud.</li><li>uint32 width<br># 2D structure of the point cloud. If the cloud is unordered, height is<br># 1 and width is the length of the point cloud.</li><li>PointField[] fields<br># Describes the channels and their layout in the binary data blob.</li><li>bool is_bigendian<br># Is this data bigendian?</li><li>uint32 point_step<br># Length of a point in bytes</li><li>uint32 row_step<br># Length of a row in bytes</li><li>uint8[] data<br># Actual point data, size is (row_step*height)</li><li>bool is_dense<br># True if there are no invalid points</li></ol><h2>Enums</h2><ol></ol>"
],
"text/plain": [
"<capella_ros_tools.modules.messages.parser.MessageDef at 0x7f358c32beb0>"
"<capella_ros_tools.modules.messages.parser.MessageDef at 0x7fb964d20460>"
]
},
"metadata": {},
Expand Down
7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,14 @@ Documentation = "https://dsd-dbs.github.io/capella-ros-tools"
[project.optional-dependencies]
docs = [
"furo",
"sphinx",
"ipython",
"nbsphinx",
"sphinx-copybutton",
"tomli; python_version<'3.11'",
"jinja2",
"pyyaml>=6.0",
"sphinx!=7.2.0,!=7.2.1,!=7.2.2",
"sphinx-argparse-cli",
]

test = [
Expand Down

0 comments on commit 1ddb920

Please sign in to comment.