diff --git a/.github/workflows/continuous-deployment.yml b/.github/workflows/continuous-deployment.yml new file mode 100644 index 0000000..1d876b5 --- /dev/null +++ b/.github/workflows/continuous-deployment.yml @@ -0,0 +1,55 @@ +name: Continuous Deployment and push to PyPI + +on: + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4.1.7 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5.1.0 + with: + python-version: 3.12 + + - name: Install requirements + run: | + python -m pip install --upgrade pip + pip install -r src/requirements.txt + + - name: Create Tag + shell: bash + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + TAG=$(git describe --tags $(git rev-list --tags --max-count=1)) + NEW_TAG=$(echo $TAG | awk -F. -v OFS=. '{$NF++; print}') + git tag -a $NEW_TAG -m "Release version $NEW_TAG" + sed -i "s/version='.*',/version='${NEW_TAG}',/" setup.py + git commit -am "Bump version to ${NEW_TAG}" + git push origin $NEW_TAG + echo "NEW_TAG=$NEW_TAG" >> $GITHUB_ENV + + - name: Create Release + uses: softprops/action-gh-release@v2.0.5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + tag_name: ${{ env.NEW_TAG }} + generate_release_notes: true + + - name: Build package + run: python -m build + + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..689e50f --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include LICENSE +include README.md \ No newline at end of file diff --git a/README.md b/README.md index e61104c..e8310ba 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,33 @@ -# ABB-EGM-Python +# ABBRobotEGM -A Python library for interfacing with ABB robots using Externally Guided Motion (EGM). This library provides real-time streaming communication with ABB robots at rates up to 250Hz using UDP. +![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg) + +`ABBRobotEGM` is a Python library for interfacing with ABB robots using Externally Guided Motion (EGM). This library provides real-time streaming communication with ABB robots at rates up to 250Hz using UDP. It's based on the official ABB EGM [documentation](https://github.com/FLo-ABB/ABB-EGM-Python/blob/main/doc/3HAC073318%20AM%20Externally%20Guided%20Motion%20RW7-en.pdf) and examples, and it's designed to be easy to use and to integrate with other systems. ## Prerequisites - Python 3.x - ABB RobotWare 7.X (should work with 6.X with few modifications) - ABB Robot with EGM option (3124-1 Externally Guided Motion) -- The following Python packages: - ```txt - numpy - protobuf - ``` -## Documentation -Please refer to the [documentation](ttps://github.com/FLo-ABB/ABB-EGM-Python/blob/main/doc/3HAC073318%20AM%20Externally%20Guided%20Motion%20RW7-en.pdfh) for detailed information on EGM option. -## Installation +## Installation 🚀 + +### Using pip 🐍 -1. Clone the repository +To install the library using pip, run the following command: -2. Install dependencies: -```sh -pip install -r requirements.txt +```bash +pip install ABBRobotEGM ``` +### Manual Installation 📦 + +To use this library in your project, first download the repository and place the `ABBRobotEGM` folder in your project's directory. You can then import the `EGM` class from this library to use it in your project. + ## Simple Examples -The library includes several examples demonstrating different EGM functionalities. Inside each python example file, you can find the relative **RAPID** code that should be running on the robot controller. +The repository includes several examples demonstrating different EGM functionalities. Inside each python example file, you can find the relative **RAPID** code that should be running on the robot controller. ### Guidance Mode @@ -41,10 +41,52 @@ example_pose_guidance.py - Makes the robot move in a circular pattern ### Streaming Mode #### 1. Joint Streaming -example_joint_stream.py - Streams robot joint positions +example_joint_stream.py - Streams robot joint positions : +```python +from ABBRobotEGM import EGM + +def main() -> None: + """ + Example showing how to stream the robot's position. + Be sure the robot is running before running this script. + """ + with EGM() as egm: + while True: + success, state = egm.receive_from_robot() + if not success: + print("Failed to receive from robot") + break + print(f"{state.clock[1]}, {state.joint_angles[0]}, {state.joint_angles[1]}, {state.joint_angles[2]}, {state.joint_angles[3]}, {state.joint_angles[4]}, {state.joint_angles[5]}") + + +if __name__ == "__main__": + main() + +``` + #### 2. Cartesian Streaming example_pos_stream.py - Streams robot cartesian position +```python +from ABBRobotEGM import EGM + +def main() -> None: + """ + Example showing how to stream the robot's position. + Be sure the robot is running before running this script. + """ + with EGM() as egm: + while True: + success, state = egm.receive_from_robot() + if not success: + print("Failed to receive from robot") + break + print(f"{state.clock[1]}, {state.cartesian.pos.x}, {state.cartesian.pos.y}, {state.cartesian.pos.z}") + + +if __name__ == "__main__": + main() +``` ### 3. Data Exchange example_table.py - Demonstrates exchanging data arrays with the robot @@ -54,7 +96,7 @@ Example of a more complex scenario where the robot is scanning a surface giving https://github.com/user-attachments/assets/03f151de-e098-4255-ac46-7dff42231071 -## Features +## Features 🚀 - Real-time communication at up to 250Hz - Joint position control @@ -66,10 +108,7 @@ https://github.com/user-attachments/assets/03f151de-e098-4255-ac46-7dff42231071 - Force measurement reading - Comprehensive robot state feedback -## License - -Licensed under the Apache License, Version 2.0. See LICENSE file for details. -## Contributing +## Contributing 🤝 Contributions are welcome! Please feel free to submit pull requests. diff --git a/abb_egm/_egm_protobuf/__init__.py b/abb_egm/_egm_protobuf/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/scenario_scan/python/example_complex.py b/examples/complex/scenario_scan/python/example_complex.py similarity index 98% rename from scenario_scan/python/example_complex.py rename to examples/complex/scenario_scan/python/example_complex.py index 30b4839..6fd0d20 100644 --- a/scenario_scan/python/example_complex.py +++ b/examples/complex/scenario_scan/python/example_complex.py @@ -1,4 +1,4 @@ -from abb_egm.egm import EGM +from ABBRobotEGM import EGM import matplotlib.pyplot as plt import numpy as np import time diff --git a/examples/complex/scenario_scan/requirements.txt b/examples/complex/scenario_scan/requirements.txt new file mode 100644 index 0000000..8248f97 --- /dev/null +++ b/examples/complex/scenario_scan/requirements.txt @@ -0,0 +1,2 @@ +matplotlib +numpy \ No newline at end of file diff --git a/scenario_scan/rspag/Project16.rspag b/examples/complex/scenario_scan/rspag/Project16.rspag similarity index 100% rename from scenario_scan/rspag/Project16.rspag rename to examples/complex/scenario_scan/rspag/Project16.rspag diff --git a/examples/requirements.txt b/examples/requirements.txt new file mode 100644 index 0000000..02fef85 --- /dev/null +++ b/examples/requirements.txt @@ -0,0 +1 @@ +ABBRobotEGM \ No newline at end of file diff --git a/example_table.py b/examples/simple/example_table.py similarity index 98% rename from example_table.py rename to examples/simple/example_table.py index f600fd4..d931ecd 100644 --- a/example_table.py +++ b/examples/simple/example_table.py @@ -1,4 +1,4 @@ -from abb_egm.egm import EGM +from ABBRobotEGM import EGM import numpy as np # Robot Module # diff --git a/example_joint_guidance.py b/examples/simple/guidance/example_joint_guidance.py similarity index 98% rename from example_joint_guidance.py rename to examples/simple/guidance/example_joint_guidance.py index 7482614..13424d6 100644 --- a/example_joint_guidance.py +++ b/examples/simple/guidance/example_joint_guidance.py @@ -1,4 +1,4 @@ -from abb_egm.egm import EGM +from ABBRobotEGM import EGM import numpy as np # Robot Module # diff --git a/example_pose_guidance.py b/examples/simple/guidance/example_pose_guidance.py similarity index 99% rename from example_pose_guidance.py rename to examples/simple/guidance/example_pose_guidance.py index 2ddffd2..9dfbc00 100644 --- a/example_pose_guidance.py +++ b/examples/simple/guidance/example_pose_guidance.py @@ -1,4 +1,4 @@ -from abb_egm.egm import EGM +from ABBRobotEGM import EGM import numpy as np # Robot Module # diff --git a/example_joint_stream.py b/examples/simple/stream/example_joint_stream.py similarity index 97% rename from example_joint_stream.py rename to examples/simple/stream/example_joint_stream.py index 4f1397f..94b6954 100644 --- a/example_joint_stream.py +++ b/examples/simple/stream/example_joint_stream.py @@ -1,4 +1,4 @@ -from abb_egm.egm import EGM +from ABBRobotEGM import EGM # Robot Module # # MODULE MainModule diff --git a/example_pos_stream.py b/examples/simple/stream/example_pos_stream.py similarity index 97% rename from example_pos_stream.py rename to examples/simple/stream/example_pos_stream.py index 74cb01f..1cdb93b 100644 --- a/example_pos_stream.py +++ b/examples/simple/stream/example_pos_stream.py @@ -1,4 +1,4 @@ -from abb_egm.egm import EGM +from ABBRobotEGM import EGM # MODULE MainModule # VAR egmident egmID1; diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 49dc6a9..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -numpy -protobuf -matplotlib \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..f7dae45 --- /dev/null +++ b/setup.py @@ -0,0 +1,24 @@ +from setuptools import setup, find_packages + +setup( + name='ABBRobotEGM', + version='1.0.0', + description='A Python library for real-time control and data streaming of ABB robots using EGM protocol, enabling high-frequency (250Hz) communication through UDP for industrial automation applications.', + long_description=open('README.md', encoding='utf-8').read(), + long_description_content_type='text/markdown', + author='Florian LOBERT', + url='https://github.com/FLo-ABB/ABB-EGM-Python', + packages=find_packages(where='src'), + package_dir={'': 'src'}, + classifiers=[ + 'Programming Language :: Python :: 3', + 'License :: OSI Approved :: Apache Software License', # Fixed classifier + 'Operating System :: OS Independent', + 'Intended Audience :: Developers', + ], + python_requires='>=3.6', # Specify minimum Python version + install_requires=[ + 'numpy', + 'protobuf', + ], +) diff --git a/src/ABBRobotEGM/__init__.py b/src/ABBRobotEGM/__init__.py new file mode 100644 index 0000000..5321e2e --- /dev/null +++ b/src/ABBRobotEGM/__init__.py @@ -0,0 +1 @@ +from .egm import EGM diff --git a/abb_egm/__init__.py b/src/ABBRobotEGM/_egm_protobuf/__init__.py similarity index 100% rename from abb_egm/__init__.py rename to src/ABBRobotEGM/_egm_protobuf/__init__.py diff --git a/abb_egm/_egm_protobuf/egm_pb2.py b/src/ABBRobotEGM/_egm_protobuf/egm_pb2.py similarity index 100% rename from abb_egm/_egm_protobuf/egm_pb2.py rename to src/ABBRobotEGM/_egm_protobuf/egm_pb2.py diff --git a/abb_egm/abb_data.py b/src/ABBRobotEGM/abb_data.py similarity index 100% rename from abb_egm/abb_data.py rename to src/ABBRobotEGM/abb_data.py diff --git a/abb_egm/egm.py b/src/ABBRobotEGM/egm.py similarity index 99% rename from abb_egm/egm.py rename to src/ABBRobotEGM/egm.py index a329214..837d684 100644 --- a/abb_egm/egm.py +++ b/src/ABBRobotEGM/egm.py @@ -17,7 +17,7 @@ import numpy as np import errno from typing import Tuple, NamedTuple, Any, Optional -from abb_egm._egm_protobuf import egm_pb2 +from ABBRobotEGM._egm_protobuf import egm_pb2 from .abb_data import Pos, Orientation, Euler, Pose # Constants diff --git a/src/requirements.txt b/src/requirements.txt new file mode 100644 index 0000000..224be9a --- /dev/null +++ b/src/requirements.txt @@ -0,0 +1,4 @@ +numpy +protobuf +setuptools +build \ No newline at end of file