buttons.py
  1  #!/usr/bin/env python3
  2  ################################################################################
  3  # Copyright 2022 FZI Research Center for Information Technology
  4  #
  5  # Redistribution and use in source and binary forms, with or without
  6  # modification, are permitted provided that the following conditions are met:
  7  #
  8  # 1. Redistributions of source code must retain the above copyright notice,
  9  # this list of conditions and the following disclaimer.
 10  #
 11  # 2. Redistributions in binary form must reproduce the above copyright notice,
 12  # this list of conditions and the following disclaimer in the documentation
 13  # and/or other materials provided with the distribution.
 14  #
 15  # 3. Neither the name of the copyright holder nor the names of its
 16  # contributors may be used to endorse or promote products derived from this
 17  # software without specific prior written permission.
 18  #
 19  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 20  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 21  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 22  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 23  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 24  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 25  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 26  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 27  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 28  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 29  # POSSIBILITY OF SUCH DAMAGE.
 30  ################################################################################
 31  
 32  # -----------------------------------------------------------------------------
 33  # \file    buttons.py
 34  #
 35  # \author  Stefan Scherzinger <scherzin@fzi.de>
 36  # \date    2022/11/09
 37  #
 38  # -----------------------------------------------------------------------------
 39  
 40  import rclpy
 41  from rclpy.node import Node
 42  from sensor_msgs.msg import Joy
 43  import subprocess
 44  import numpy as np
 45  import sys
 46  import time
 47  
 48  
 49  class buttons(Node):
 50      """React to button events"""
 51  
 52      def __init__(self):
 53          super().__init__("spacenav_buttons")
 54  
 55          self.repeat_same_button = self.declare_parameter(
 56              "repeat_same_button", False
 57          ).value
 58          self.button_sleep = self.declare_parameter("button_sleep", 0.1).value
 59          self.button_cmds = self.declare_parameter("button_cmds", [""]).value
 60          self.cmd_dirs = self.declare_parameter("cmd_dirs", [""]).value
 61          self.last_button_cmds = None
 62  
 63          self.joystick_topic = self.declare_parameter("joystick_topic", "").value
 64          self.sub = self.create_subscription(
 65              Joy, self.joystick_topic, self.event_callback, 1
 66          )
 67  
 68      def event_callback(self, data):
 69          # Have some buttons been repeatedly pressed?
 70          if self.last_button_cmds and any(
 71              np.bitwise_and(data.buttons, self.last_button_cmds)
 72          ):
 73              return
 74          for idx, val in enumerate(data.buttons):
 75              if val == 1:
 76                  exec_dir = self.cmd_dirs[idx]
 77                  if not exec_dir:  # Empty string
 78                      exec_dir = None
 79                  subprocess.Popen(
 80                      self.button_cmds[idx],
 81                      stdin=subprocess.PIPE,
 82                      cwd=exec_dir,
 83                      shell=True,
 84                  )
 85                  # Prevent pressing the same buttons in a row
 86                  if not self.repeat_same_button:
 87                      self.last_button_cmds = data.buttons
 88                  time.sleep(self.button_sleep)
 89  
 90  
 91  def main(args=None):
 92      rclpy.init(args=args)
 93  
 94      node = buttons()
 95      rclpy.spin(node)
 96      rclpy.shutdown()
 97  
 98  
 99  if __name__ == "__main__":
100      try:
101          main()
102      except KeyboardInterrupt:
103          sys.exit(0)
104      except Exception as e:
105          print(e)
106          sys.exit(1)