Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

54 emulate remote controller #63

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d57829b
feat(emulate remote controller): add emulator node
Harry0288 Nov 28, 2024
a3b52c8
feat(emulate remote controller): add key functionality
Harry0288 Nov 28, 2024
4d26270
feat(emulate remote controller): add movement acceleration functionality
Harry0288 Nov 28, 2024
ebb8b61
feat(emulate remote controller): add double half key functionalities
Harry0288 Dec 5, 2024
f9a639f
fix(emulate remote controller): suppress key output
Harry0288 Dec 5, 2024
b02c79c
fix(emulate remote controller): fix value to float
Harry0288 Dec 5, 2024
5782aa7
feat(emulate remote controller): add tests
Harry0288 Dec 6, 2024
d9598c4
feat(emulate remote controller): use teleop
Harry0288 Dec 7, 2024
f1f51c1
feat(emulate remote controller): add test emulator
Harry0288 Dec 7, 2024
8919031
feat(emulate remote controller): add default behaviour
Harry0288 Dec 7, 2024
44fe84c
fix(emulate remote controller): change test emulator path
Harry0288 Dec 8, 2024
6df6399
fix(emulate remote controller): fix timer and boost functionality
Harry0288 Dec 8, 2024
ce1cc62
fix(emulate remote controller): fix test for emulator
Harry0288 Dec 8, 2024
3edad15
fix(emulate remote controller): fix timer and exit condition
Harry0288 Dec 10, 2024
b20fcac
feat(emulate remote controller): add node for default trajectory
Harry0288 Dec 10, 2024
326bb00
feat(emulate remote controller): add entrypoints for emulator
Harry0288 Dec 10, 2024
a8eec70
feat(emulate remote controller): delete emulator monitor
Harry0288 Dec 13, 2024
65e5098
feat(emulate remote controller): replace emulator monitor with tempor…
Harry0288 Dec 13, 2024
4039f1e
fix(emulate remote controller): fix stylistic errors
Harry0288 Dec 13, 2024
d03b85b
fix(emulate remote controller): fix colcon test error
Harry0288 Dec 13, 2024
dcc4558
fix(emulate remote controller): delete emulator monitor
Harry0288 Dec 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions reseq_ros2/reseq_ros2/emulator_monitor.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that we need this kind of node?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleted

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import rclpy
from rclpy.node import Node
from reseq_interfaces.msg import Remote

class EmulatorMonitor(Node):
def __init__(self):
super().__init__("emulator_monitor")
self.subscription = self.create_subscription(Remote,'/remote',self.monitor_callback,10)
self.get_logger().info("EmulatorMonitor node started")
self.msg = None

def monitor_callback(self, msg):
# self.get_logger().info(f"Received: {msg}")
self.msg = msg

def main(args = None):
rclpy.init(args = args)
try:
emulator_monitor = EmulatorMonitor()
rclpy.spin(emulator_monitor)
except Exception as err:
print("Error while starting EmulatorMonitor node: " + str(err))
rclpy.shutdown()
else:
emulator_monitor.destroy_node()
rclpy.shutdown()

if __name__ == "__main__":
main()
183 changes: 183 additions & 0 deletions reseq_ros2/reseq_ros2/emulator_remote_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import rclpy
from reseq_interfaces.msg import Remote
from rclpy.node import Node
import sys, select, termios, tty

# retrieve settings from file descriptor (stdin)
settings = termios.tcgetattr(sys.stdin)

class EmulatorRemoteController(Node):
def __init__(self):
super().__init__("emulator_remote_controller")
# create teleop_twist_keyboard node
self.emulator = rclpy.create_node("teleop_twist_keyboard")
self.publisher = self.create_publisher(Remote, '/remote',10)
self.get_logger().info("EmulatorRemoteController node started")
# create timer to start the function
self.timer = self.create_timer(0.08, self.readLoop)
self.has_to_exit = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exit is handled using an exception, this is not used. That is not to say that the exception is preferable (it is not) but inn any case this variable is unused

# values should be already automatically be set to 0
self.previousKey = ' ' # initialise to a random value
self.previousValue = 0.0
self.increment = 0.1
# self.states = {"Normal": self.normal_value, "Double": self.normal_value*2, "Half": self.normal_value/2}
self.defaultMessage = Remote()
self.defaultMessage.right.x = 0.0
self.defaultMessage.right.y = 0.0
self.defaultMessage.right.z = 0.0
self.defaultMessage.left.x = 0.0
self.defaultMessage.left.y = 0.0
self.defaultMessage.left.z = 0.0
Comment on lines +36 to +41
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this is needed? (especially given your comment). Why are you inserting un-needed lines of code, do you believe that these improve readability?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moreover I don't think this would ever be needed (you can simply call Remote())


def readKey(self):
tty.setraw(sys.stdin.fileno())
# add timeout, so select.select() will wait for that time and then it will return
# it returns three lists one for each of the three parameters
readyToRead, _,_ = select.select([sys.stdin], [], [], 0.08)
if readyToRead:
key = sys.stdin.read(1)
else:
# use default key
key = ' '
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
return key

def handleKey(self, key, message = Remote()):
# make lower case
key = key.lower()
if key == 'w':
# print("forward")
if (key == self.previousKey):
message.left.y = min(1.0,self.previousValue * (self.increment+1))
self.previousValue = min(1.0,self.previousValue * (self.increment+1))
else:
message.left.y = self.increment
self.previousValue = self.increment
self.previousKey = key
self.publisher.publish(message)
elif key == 's':
# print("backward")
if (key == self.previousKey):
message.left.y = -min(1.0,-self.previousValue * (self.increment+1))
self.previousValue = -min(1.0,-self.previousValue * (self.increment+1))
else:
message.left.y = -self.increment
self.previousValue = -self.increment
self.previousKey = key
self.publisher.publish(message)
elif key == 'a':
# print("left")
if (key == self.previousKey):
message.left.x = -min(1.0,-self.previousValue * (self.increment+1))
self.previousValue = -min(1.0,-self.previousValue * (self.increment+1))
else:
message.left.x = -self.increment
self.previousValue = -self.increment
self.previousKey = key
self.publisher.publish(message)
elif key == 'd':
# print("right")
if (key == self.previousKey):
message.left.x = min(1.0,self.previousValue * (self.increment+1))
self.previousValue = min(1.0,self.previousValue * (self.increment+1))
else:
message.left.x = self.increment
self.previousValue = self.increment
self.previousKey = key
self.publisher.publish(message)
elif key == 'q':
# print("CCW")
if (key == self.previousKey):
message.left.z = -min(1.0,-self.previousValue * (self.increment+1))
self.previousValue = -min(1.0,-self.previousValue * (self.increment+1))
else:
message.left.z = -self.increment
self.previousValue = -self.increment
self.previousKey = key
self.publisher.publish(message)
elif key == 'e':
# print("CW")
if (key == self.previousKey):
message.left.z = min(1.0,self.previousValue * (self.increment+1))
self.previousValue = min(1.0,self.previousValue * (self.increment+1))
else:
message.left.z = self.increment
self.previousValue = self.increment
self.previousKey = key
self.publisher.publish(message)
# Start cmd_vel commands
elif key == 'i':
# print("forward")
if (key == self.previousKey):
message.right.y = min(1.0,self.previousValue * (self.increment+1))
self.previousValue = min(1.0,self.previousValue * (self.increment+1))
else:
message.right.y = self.increment
self.previousValue = self.increment
self.previousKey = key
self.publisher.publish(message)
elif key == 'k':
# print("backward")
if (key == self.previousKey):
message.right.y = -min(1.0,-self.previousValue * (self.increment+1))
self.previousValue = -min(1.0,-self.previousValue * (self.increment+1))
else:
message.right.y = -self.increment
self.previousValue = -self.increment
self.previousKey = key
self.publisher.publish(message)
elif key == 'l':
# print("right")
if (key == self.previousKey):
message.right.x = min(1.0,self.previousValue * (self.increment+1))
self.previousValue = min(1.0,self.previousValue * (self.increment+1))
else:
message.right.x = self.increment
self.previousValue = self.increment
self.previousKey = key
self.publisher.publish(message)
elif key == 'j':
# print("left")
if (key == self.previousKey):
message.right.x = -min(1.0,-self.previousValue * (self.increment+1))
self.previousValue = -min(1.0,-self.previousValue * (self.increment+1))
else:
message.right.x = -self.increment
self.previousValue = -self.increment
self.previousKey = key
self.publisher.publish(message)
# if b pressed, make cmd_vel movements faster
elif key == 'b':
self.increment /= 2
elif key == 'h':
self.increment *= 2
elif key == 'z':
raise Exception("Exit requested")
else:
# pass to default
self.publisher.publish(self.defaultMessage)
return self.has_to_exit

def readLoop(self):
message = Remote()
key = self.readKey()
if self.handleKey(key, message):
# destroy node
self.emulator.destroy_node()
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
Comment on lines +175 to +178
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above


def main(args = None):
rclpy.init(args = args)
try:
emulator_remote_controller = EmulatorRemoteController()
except Exception as err:
print("Error while starting EmulatorRemoteController node: " + str(err))
raise err
else:
rclpy.spin(emulator_remote_controller)
emulator_remote_controller.emulator.destroy_node()
emulator_remote_controller.destroy_node()
rclpy.shutdown()

if __name__ == "__main__":
main()
41 changes: 41 additions & 0 deletions reseq_ros2/reseq_ros2/emulator_trajectory.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a fixed trajectory, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not ideal. At this point, if we have a fixed trajectory, let's just use a pre-recorded rosbag. What do you think?

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import rclpy
from reseq_interfaces.msg import Remote
from rclpy.node import Node

class EmulatorTrajectory(Node):
def __init__(self):
super().__init__("emulator_trajectory")
self.publisher = self.create_publisher(Remote, '/remote',10)
self.get_logger().info("EmulatorTrajectory node started")
self.timer = self.create_timer(0.08, self.readLoop)
self.circleMessage = Remote()
self.circleMessage.right.x = 0.1
self.circleMessage.right.y = 0.1
self.circleMessage.right.z = 0.1
self.circleMessage.left.x = 0.1
self.circleMessage.left.y = 0.1
self.circleMessage.left.z = 0.1
self.stop_emulator_timer = self.create_timer(60.0, self.stopEmulator)
self.has_to_exit = False

def readLoop(self):
self.publisher.publish(self.circleMessage)

def stopEmulator(self):
raise Exception("Exit requested")

def main(args = None):
rclpy.init(args = args)
try:
emulator_trajectory = EmulatorTrajectory()
except Exception as err:
print("Error while starting EmulatorTrajectory node: " + str(err))
raise err
else:
rclpy.spin(emulator_trajectory)
emulator_trajectory.emulator.destroy_node()
emulator_trajectory.destroy_node()
rclpy.shutdown()

if __name__ == "__main__":
main()
3 changes: 3 additions & 0 deletions reseq_ros2/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
'scaler = reseq_ros2.scaler:main',
'joint_publisher = reseq_ros2.joint_publisher:main',
'fake_robot_feedback = reseq_ros2.fake_robot_feedback:main',
'emulator_monitor = reseq_ros2.emulator_monitor:main',
'emulator_remote_controller = reseq_ros2.emulator_remote_controller:main',
'emulator_trajectory = reseq_ros2.emulator_trajectory:main',
],
},
)
Loading
Loading