diff --git a/Dockerfile.hardware b/Dockerfile.hardware index 8d133b7..c07482c 100644 --- a/Dockerfile.hardware +++ b/Dockerfile.hardware @@ -7,21 +7,20 @@ FROM ubuntu:18.04 AS stm32flash_builder ARG ROS_DISTRO ARG ROSBOT_FW_RELEASE +ARG TARGETARCH SHELL ["/bin/bash", "-c"] # official releases are only for intel archs, so we need to build stm32flash from sources RUN apt-get update && apt-get install -y \ - curl \ - git \ - build-essential \ - cmake && \ - git clone https://github.com/stm32duino/stm32flash.git && \ - cd stm32flash/ && \ - make all + curl RUN echo ros_distro=$ROS_DISTRO firmware_release=$ROSBOT_FW_RELEASE +# Copy firmware binaries +RUN curl -L https://github.com/husarion/stm32flash/releases/download/2023-12-05/stm32flash-$TARGETARCH -o /stm32flash && \ + chmod +x /stm32flash + # Copy firmware binaries RUN curl -L https://github.com/husarion/rosbot_ros2_firmware/releases/download/$ROSBOT_FW_RELEASE/firmware.bin -o /firmware.bin && \ curl -L https://github.com/husarion/rosbot_ros2_firmware/releases/download/$ROSBOT_FW_RELEASE/firmware.hex -o /firmware.hex @@ -129,8 +128,11 @@ COPY --from=ros_builder /ros2_ws /ros2_ws COPY --from=healthcheck_builder /ros2_ws /ros2_ws_healthcheck RUN apt-get update && apt-get install -y \ + python3-pip \ python3-rosdep \ + usbutils \ ros-$ROS_DISTRO-teleop-twist-keyboard && \ + pip3 install pyftdi sh && \ rm -rf /etc/ros/rosdep/sources.list.d/20-default.list && \ rosdep init && \ rosdep update --rosdistro $ROS_DISTRO && \ @@ -145,7 +147,7 @@ RUN apt-get update && apt-get install -y \ # copy firmware built in previous stage and downloaded repository COPY --from=stm32flash_builder /firmware.bin /root/firmware.bin COPY --from=stm32flash_builder /firmware.hex /root/firmware.hex -COPY --from=stm32flash_builder /stm32flash/stm32flash /usr/bin/stm32flash +COPY --from=stm32flash_builder /stm32flash /usr/bin/stm32flash COPY --from=cpu_id_builder /read_cpu_id/.pio/build/olimex_e407/firmware.bin /firmware_read_cpu_id.bin @@ -161,4 +163,5 @@ COPY microros_localhost_only.xml / # copy scripts COPY flash-firmware.py / COPY flash-firmware.py /usr/bin/ +COPY flash-firmware-usb.py /usr/bin/ COPY print-serial-number.py /usr/bin/ diff --git a/demo/namespace/compose.yaml b/demo/namespace/compose.yaml index bba2f94..6435479 100644 --- a/demo/namespace/compose.yaml +++ b/demo/namespace/compose.yaml @@ -20,14 +20,18 @@ services: ipc: host devices: - ${SERIAL_PORT:?err} + - /dev/bus/usb/ + volumes: + - ../../flash-firmware-usb.py:/usr/bin/flash-firmware-usb.py environment: - FASTRTPS_DEFAULT_PROFILES_FILE=/shm-only.xml - command: > - ros2 launch rosbot_bringup combined.launch.py - mecanum:=${MECANUM:-False} - serial_port:=$SERIAL_PORT - serial_baudrate:=576000 - namespace:=robot1 + command: tail -f /dev/null + # command: > + # ros2 launch rosbot_bringup combined.launch.py + # mecanum:=${MECANUM:-False} + # serial_port:=$SERIAL_PORT + # serial_baudrate:=576000 + # namespace:=robot1 ros2router: image: husarnet/ros2router:1.4.0 diff --git a/flash-firmware-usb.py b/flash-firmware-usb.py new file mode 100755 index 0000000..75a606c --- /dev/null +++ b/flash-firmware-usb.py @@ -0,0 +1,109 @@ +#!/usr/bin/python3 + +import sh +import time +import sys +import argparse +from pyftdi.ftdi import Ftdi + +# CBUS0 - BOOT0 +# CBUS1 - RST + +class FirmwareFlasher: + def __init__(self, binary_file, port): + + # ftdi.show_devices() + # self.ftdi = Ftdi.create_from_url('ftdi://ftdi:ft-x:DK0AM0V0/1') + self.device = 'ftdi://ftdi:ft-x:/1' + self.ftdi = Ftdi() + + self.binary_file = binary_file + self.max_approach_no = 3 + self.port = port + + def enter_bootloader_mode(self): + + self.ftdi.open_from_url(url=self.device) + self.ftdi.set_cbus_direction(0b11,0b11) # set CBUS0 and CBUS1 to output + time.sleep(0.1) + self.ftdi.set_cbus_gpio(0b11) #set CBUS0 to 1 and RST to 1 + time.sleep(0.1) + self.ftdi.set_cbus_gpio(0b01) #set CBUS0 to 1 and RST to 0 + time.sleep(0.1) + # self.ftdi.set_cbus_direction(0b11,0b00) # set CBUS0 and CBUS1 to input + time.sleep(0.1) + self.ftdi.close() + + def exit_bootloader_mode(self): + + self.ftdi.open_from_url(url=self.device) + self.ftdi.set_cbus_direction(0b11,0b11) # set CBUS0 and CBUS1 to output + time.sleep(0.1) + self.ftdi.set_cbus_gpio(0b10) #set CBUS0 to 1 and RST to 1 + time.sleep(0.1) + self.ftdi.set_cbus_gpio(0b00) #set CBUS0 to 1 and RST to 0 + time.sleep(0.1) + # self.ftdi.set_cbus_direction(0b11,0b00) # set CBUS0 and CBUS1 to input + time.sleep(0.1) + self.ftdi.close() + + def try_flash_operation(self, operation_name, flash_command, flash_args): + for i in range(self.max_approach_no): + try: + self.enter_bootloader_mode() + sh.usbreset("0403:6015") + flash_command(self.port, *flash_args, _out=sys.stdout) + self.exit_bootloader_mode() + 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): + # Disable the flash write-protection + self.try_flash_operation("Write-UnProtection", sh.stm32flash, ["-u"]) + + # Disable the flash read-protection + self.try_flash_operation("Read-UnProtection", sh.stm32flash, ["-k"]) + + # Flashing the firmware + # /usr/bin/stm32flash /dev/ttyUSB0 -v -w /root/firmware.bin -b 115200 + flash_args = ["-v", "-w", self.binary_file, "-b", "115200"] + self.try_flash_operation("Flashing", sh.stm32flash, flash_args) + + + sh.usbreset("0403:6015") + + +def main(): + + parser = argparse.ArgumentParser( + description='Flashing the firmware on STM32 microcontroller in ROSbot XL') + + parser.add_argument( + "-f", + "--file", + nargs='?', + default="/root/firmware.bin", + help="Path to a firmware file. Default: /root/firmware.bin") + parser.add_argument( + "-p", + "--port", + nargs='?', + default="/dev/ttyUSB0", + help="Path to serial connection. Default: /dev/ttyUSB0") + + binary_file = parser.parse_args().file + port = parser.parse_args().port + + flasher = FirmwareFlasher(binary_file, port) + flasher.flash_firmware() + print("Done.") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/flash-firmware.py b/flash-firmware.py index 89bb0eb..27c0f1b 100755 --- a/flash-firmware.py +++ b/flash-firmware.py @@ -12,7 +12,7 @@ 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}") @@ -57,44 +57,31 @@ def exit_bootloader_mode(self): self.reset_pin.write(False) time.sleep(0.2) - def flash_firmware(self): - self.enter_bootloader_mode() - - # Disable the flash write-protection + def try_flash_operation(self, operation_name, flash_command, flash_args): for i in range(self.max_approach_no): try: - sh.stm32flash(self.port, "-u", _out=sys.stdout) + flash_command(self.port, *flash_args, _out=sys.stdout) time.sleep(0.2) break - except Exception: - print("Write-UnProtection error! Trying again.") - pass + except Exception as e: + print(f"{operation_name} error! Trying again.") + print(f"Error: {e}") + print("---------------------------------------") else: - print("WARNING! Disabling the flash Write-Protection went wrong.") + print(f"WARNING! {operation_name} went wrong.") + + def flash_firmware(self): + self.enter_bootloader_mode() + + # Disable the flash write-protection + self.try_flash_operation("Write-UnProtection", sh.stm32flash, ["-u"]) # Disable the flash read-protection - for i in range(self.max_approach_no): - try: - sh.stm32flash(self.port, "-k", _out=sys.stdout) - time.sleep(0.2) - break - except Exception: - print("Read-UnProtection error! Trying again.") - pass - else: - print("WARNING! Disabling the flash Read-Protection went wrong.") + self.try_flash_operation("Read-UnProtection", sh.stm32flash, ["-k"]) # Flashing the firmware - for i in range(self.max_approach_no): - try: - sh.stm32flash(self.port, "-v", w=self.binary_file, b="115200", _out=sys.stdout) - time.sleep(0.2) - break - except Exception: - print("Flashing error! Trying again.") - pass - else: - print("ERROR! Flashing the firmware went wrong. Try again.") + flash_args = ["-v", "-w", self.binary_file, "-b", "115200"] + self.try_flash_operation("Flashing", sh.stm32flash, flash_args) self.exit_bootloader_mode()