diff --git a/.github/workflows/build-docker-image-gazebo.yaml b/.github/workflows/build-docker-image-gazebo.yaml index f7efaf3..f8c579f 100644 --- a/.github/workflows/build-docker-image-gazebo.yaml +++ b/.github/workflows/build-docker-image-gazebo.yaml @@ -6,7 +6,7 @@ on: # - 'ros1' pull_request: types: [closed] - + jobs: build: runs-on: ubuntu-20.04 @@ -14,7 +14,6 @@ jobs: fail-fast: false matrix: include: - - ros-distro: melodic - ros-distro: noetic steps: @@ -23,19 +22,19 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v1 - + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 with: version: latest - + - name: Login to Docker Registry uses: docker/login-action@v1 with: registry: docker.io username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - + - name: Build and push (production) if: github.ref_name == 'ros1' uses: docker/build-push-action@v2 @@ -62,4 +61,4 @@ jobs: ROS_DISTRO=${{ matrix.ros-distro }} tags: husarion/rosbot:${{ matrix.ros-distro }}-simulation-${{ github.head_ref || github.ref_name }} cache-from: type=registry,ref=husarion/rosbot:${{ matrix.ros-distro }}-simulation-${{ github.head_ref || github.ref_name }} - cache-to: type=inline \ No newline at end of file + cache-to: type=inline diff --git a/.github/workflows/build-docker-image-hardware.yaml b/.github/workflows/build-docker-image-hardware.yaml index 0f70958..5891688 100644 --- a/.github/workflows/build-docker-image-hardware.yaml +++ b/.github/workflows/build-docker-image-hardware.yaml @@ -7,7 +7,7 @@ on: workflow_dispatch: pull_request: types: [closed] - + jobs: build: runs-on: ubuntu-20.04 @@ -16,12 +16,10 @@ jobs: matrix: include: - ros-distro: melodic - ros-noetic-msgs: 0 - rosbot-fw-release: 0.16.1 + rosbot-fw-release: 0.16.2 platforms: "linux/amd64, linux/arm64, linux/arm/v7" - ros-distro: noetic - ros-noetic-msgs: 1 - rosbot-fw-release: 0.16.1 + rosbot-fw-release: 0.16.2 platforms: "linux/amd64, linux/arm64" steps: @@ -30,19 +28,19 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v1 - + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 with: version: latest - + - name: Login to Docker Registry uses: docker/login-action@v1 with: registry: docker.io username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - + - name: Build and push (production) if: github.ref_name == 'ros1' uses: docker/build-push-action@v2 @@ -53,9 +51,8 @@ jobs: push: true build-args: | ROS_DISTRO=${{ matrix.ros-distro }} - ROS_NOETIC_MSGS=${{ matrix.ros-noetic-msgs }} ROSBOT_FW_RELEASE=${{ matrix.rosbot-fw-release }} - tags: husarion/rosbot:${{ matrix.ros-distro }} + tags: husarion/rosbot:${{ matrix.ros-distro }} cache-from: type=registry,ref=husarion/rosbot:${{ matrix.ros-distro }} cache-to: type=inline @@ -69,8 +66,7 @@ jobs: push: true build-args: | ROS_DISTRO=${{ matrix.ros-distro }} - ROS_NOETIC_MSGS=${{ matrix.ros-noetic-msgs }} ROSBOT_FW_RELEASE=${{ matrix.rosbot-fw-release }} tags: husarion/rosbot:${{ matrix.ros-distro }}-${{ github.head_ref || github.ref_name }} cache-from: type=registry,ref=husarion/rosbot:${{ matrix.ros-distro }}-${{ github.head_ref || github.ref_name }} - cache-to: type=inline \ No newline at end of file + cache-to: type=inline diff --git a/Dockerfile.hardware b/Dockerfile.hardware index 688c33c..98b11ae 100644 --- a/Dockerfile.hardware +++ b/Dockerfile.hardware @@ -1,80 +1,7 @@ - -ARG ROS_DISTRO=melodic - -## ============================ STM32FLASH ================================= -# stm32flash needs an older version of glibc (2.28), which is why ubuntu 18.04 was used -FROM ubuntu:18.04 AS stm32flash_builder - -# official releases are only for intel archs, so we need to build stm32flash from sources -RUN apt-get update && apt-get install -y \ - git \ - build-essential && \ - git clone https://github.com/stm32duino/stm32flash.git && \ - cd stm32flash/ && \ - make all - -## =========================== STM32 firmware=============================== -# FROM --platform=linux/amd64 ubuntu:18.04 as stm32_firmware_builder -# TODO: wget from releases instead -FROM --platform=linux/amd64 ubuntu:20.04 AS stm32_firmware_builder - -ARG ROSBOT_FW_RELEASE=0.16.1 -ARG ROS_NOETIC_MSGS=0 - -SHELL ["/bin/bash", "-c"] - -# ENV PIO_VERSION="5.1.0" -RUN apt update && apt install -y \ - python3 \ - python3-pip \ - git \ - wget \ - tree - -# https://docs.platformio.org/en/latest/core/installation.html#system-requirements -# RUN pip3 install -U platformio==${PIO_VERSION} -RUN pip3 install -U platformio - -RUN git clone https://github.com/husarion/rosbot-stm32-firmware.git --branch ${ROSBOT_FW_RELEASE} && \ - mkdir -p ~/.platformio/packages/framework-mbed/features/ && \ - cp rosbot-stm32-firmware/.mbedignore ~/.platformio/packages/framework-mbed/features/.mbedignore - -WORKDIR /rosbot-stm32-firmware - -RUN git submodule update --init --recursive - -# RUN wget https://github.com/husarion/rosbot-stm32-firmware/archive/refs/tags/${ROSBOT_FW_RELEASE}.tar.gz && \ -# tar -xf *.tar.gz && \ -# mv rosbot-stm32-firmware* rosbot-stm32-firmware && \ -# mkdir -p ~/.platformio/packages/framework-mbed/features/ && \ -# cp rosbot-stm32-firmware/.mbedignore ~/.platformio/packages/framework-mbed/features/.mbedignore - -WORKDIR /rosbot-stm32-firmware - -RUN export LC_ALL=C.UTF-8 && \ - export LANG=C.UTF-8 && \ - pio project init -e core2_diff -O \ - "build_flags= \ - -I\$PROJECTSRC_DIR/TARGET_CORE2 \ - -DPIO_FRAMEWORK_MBED_RTOS_PRESENT \ - -DPIO_FRAMEWORK_EVENT_QUEUE_PRESENT \ - -DMBED_BUILD_PROFILE_RELEASE \ - -DJOINT_STATES_ENABLE=1 \ - -DROS_NOETIC_MSGS=${ROS_NOETIC_MSGS} \ - -DKINEMATIC_TYPE=0" && \ - pio project init -e core2_mec -O \ - "build_flags= \ - -I\$PROJECTSRC_DIR/TARGET_CORE2 \ - -DPIO_FRAMEWORK_MBED_RTOS_PRESENT \ - -DPIO_FRAMEWORK_EVENT_QUEUE_PRESENT \ - -DMBED_BUILD_PROFILE_RELEASE \ - -DJOINT_STATES_ENABLE=1 \ - -DROS_NOETIC_MSGS=${ROS_NOETIC_MSGS} \ - -DKINEMATIC_TYPE=1" && \ - pio run +ARG ROS_DISTRO=noetic +ARG ROSBOT_FW_RELEASE=0.16.2 ## =========================== ROS package builder =============================== - FROM ros:$ROS_DISTRO-ros-core AS pkg-builder SHELL ["/bin/bash", "-c"] @@ -82,7 +9,7 @@ SHELL ["/bin/bash", "-c"] RUN apt update && apt install -y \ git \ python3-pip \ - ros-$ROS_DISTRO-rosserial-python \ + ros-$ROS_DISTRO-rosserial-python \ ros-$ROS_DISTRO-rosserial-server \ ros-$ROS_DISTRO-rosserial-client \ ros-$ROS_DISTRO-rosserial-msgs \ @@ -105,21 +32,25 @@ WORKDIR /ros_ws # clone robot github repositories RUN mkdir -p src && \ git clone https://github.com/husarion/rosbot_ros.git --branch=melodic src/rosbot_ros && \ - git clone https://github.com/husarion/rosbot_ekf.git --branch=master src/rosbot_ekf + git clone https://github.com/husarion/rosbot_ekf.git --branch=master src/rosbot_ekf # build ROS workspace RUN source /opt/ros/$ROS_DISTRO/setup.bash && \ catkin_make -DCATKIN_ENABLE_TESTING=0 -DCMAKE_BUILD_TYPE=Release -## =========================== ROS image =============================== -FROM ros:$ROS_DISTRO-ros-core +## =========================== Final Stage =============================== +FROM ros:$ROS_DISTRO-ros-core + +ARG ROSBOT_FW_RELEASE SHELL ["/bin/bash", "-c"] RUN apt update && apt install -y \ + curl \ python3-pip \ - ros-$ROS_DISTRO-rosserial-python \ + stm32flash \ + ros-$ROS_DISTRO-rosserial-python \ ros-$ROS_DISTRO-rosserial-server \ ros-$ROS_DISTRO-rosserial-client \ ros-$ROS_DISTRO-rosserial-msgs \ @@ -140,10 +71,10 @@ RUN apt update && apt install -y \ # copy ROS package from previous step COPY --from=pkg-builder /ros_ws /ros_ws -# copy firmware built in previous stage -COPY --from=stm32_firmware_builder /rosbot-stm32-firmware/.pio/build/core2_diff/firmware.bin /root/firmware_diff.bin -COPY --from=stm32_firmware_builder /rosbot-stm32-firmware/.pio/build/core2_mec/firmware.bin /root/firmware_mecanum.bin -COPY --from=stm32flash_builder /stm32flash/stm32flash /usr/bin/stm32flash +# copy firmware built +RUN cd /root && \ + curl -L https://github.com/husarion/rosbot-stm32-firmware/releases/download/$ROSBOT_FW_RELEASE/firmware_diff.bin -o firmware_diff.bin && \ + curl -L https://github.com/husarion/rosbot-stm32-firmware/releases/download/$ROSBOT_FW_RELEASE/firmware_mec.bin -o firmware_mecanum.bin # copy scripts COPY ./flash-firmware.py / @@ -156,4 +87,4 @@ RUN echo ". /opt/ros/$ROS_DISTRO/setup.bash" >> ~/.bashrc && \ echo ". /ros_ws/devel/setup.bash" >> ~/.profile ENTRYPOINT ["/ros_entrypoint.sh"] -CMD ["bash"] \ No newline at end of file +CMD ["bash"] diff --git a/Dockerfile.simulation b/Dockerfile.simulation index 4521832..fb2da18 100644 --- a/Dockerfile.simulation +++ b/Dockerfile.simulation @@ -1,4 +1,4 @@ -ARG ROS_DISTRO=melodic +ARG ROS_DISTRO=noetic FROM osrf/ros:$ROS_DISTRO-desktop @@ -34,4 +34,4 @@ RUN apt-get update && \ # replace entrypoint ENTRYPOINT ["/ros_ws/ros_entrypoint.sh"] -CMD ["bash"] \ No newline at end of file +CMD ["bash"] diff --git a/flash-firmware.py b/flash-firmware.py index 60304d0..efe106e 100755 --- a/flash-firmware.py +++ b/flash-firmware.py @@ -1,38 +1,50 @@ #!/usr/bin/python3 -import sh +# Copyright 2023 Husarion +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sh import time import sys import argparse from periphery import GPIO -class FirmwareFlasher: +class FirmwareFlasher: def __init__(self, sys_arch, binary_file): - self.binary_file = binary_file self.sys_arch = sys_arch - self.max_approach_no = 5 + self.max_approach_no = 3 print(f"System architecture: {self.sys_arch}") - if self.sys_arch.stdout == b'armv7l\n': + if self.sys_arch == "armv7l\n": # Setups ThinkerBoard pins print("Device: ThinkerBoard\n") self.port = "/dev/ttyS1" boot0_pin_no = 164 reset_pin_no = 184 - - elif self.sys_arch.stdout == b'x86_64\n': + elif self.sys_arch == "x86_64\n": # Setups UpBoard pins print("Device: UpBoard\n") self.port = "/dev/ttyS4" boot0_pin_no = 17 reset_pin_no = 18 - - elif self.sys_arch.stdout == b'aarch64\n': + + elif self.sys_arch == "aarch64\n": # Setups RPi pins print("Device: RPi\n") self.port = "/dev/ttyAMA0" @@ -45,79 +57,68 @@ def __init__(self, sys_arch, binary_file): self.boot0_pin = GPIO(boot0_pin_no, "out") self.reset_pin = GPIO(reset_pin_no, "out") - def enter_bootloader_mode(self): - self.boot0_pin.write(True) self.reset_pin.write(True) time.sleep(0.2) self.reset_pin.write(False) time.sleep(0.2) - def exit_bootloader_mode(self): - self.boot0_pin.write(False) self.reset_pin.write(True) time.sleep(0.2) self.reset_pin.write(False) time.sleep(0.2) + def try_flash_operation(self, operation_name, flash_command, flash_args): + for i in range(self.max_approach_no): + try: + flash_command(self.port, *flash_args, _out=sys.stdout) + time.sleep(0.2) + break + except Exception as e: + print(f"{operation_name} error! Trying again.") + print(f"Error: {e}") + print("---------------------------------------") + else: + print(f"WARNING! {operation_name} went wrong.") def flash_firmware(self): - self.enter_bootloader_mode() - # Flashing the firmware - succes_no = 0 - for i in range(self.max_approach_no): - try: - if succes_no == 0: - # Disable the flash write-protection - sh.stm32flash(self.port, "-u", _out=sys.stdout) - time.sleep(0.2) - succes_no += 1 - - if succes_no == 1: - # Disable the flash read-protection - sh.stm32flash(self.port, "-k", _out=sys.stdout) - time.sleep(0.2) - succes_no += 1 - - if succes_no == 2: - # Flashing the firmware - sh.stm32flash(self.port, "-v", w=self.binary_file, b="115200", _out=sys.stdout) - time.sleep(0.2) - break - except: - pass + # Disable the flash write-protection + self.try_flash_operation("Write-UnProtection", sh.stm32flash, ["-u"]) - else: - print('ERROR! Something goes wrong. Try again.') + # Disable the flash read-protection + self.try_flash_operation("Read-UnProtection", sh.stm32flash, ["-k"]) + # Flashing the firmware + flash_args = ["-v", "-w", self.binary_file, "-b", "115200"] + self.try_flash_operation("Flashing", sh.stm32flash, flash_args) self.exit_bootloader_mode() - def main(): - parser = argparse.ArgumentParser( - description='Flashing the firmware on STM32 microcontroller in ROSbot') - + description="Flashing the firmware on STM32 microcontroller in ROSbot" + ) + parser.add_argument( - "file", - nargs='?', - default="/root/firmware_diff.bin", - help="Path to a firmware file. Default = /root/firmware_diff.bin") - - binary_file = parser.parse_args().file - sys_arch = sh.uname('-m') + "file", + nargs="?", + default="/root/firmware_diff.bin", + help="Path to a firmware file. Default = /root/firmware.bin", + ) + + binary_file = parser.parse_args().file + sys_arch = sh.uname("-m") flasher = FirmwareFlasher(sys_arch, binary_file) flasher.flash_firmware() - print("Done.") + print("Done!") if __name__ == "__main__": - main() \ No newline at end of file + main()