|
2 weeks ago | |
---|---|---|
.gitignore | 2 weeks ago | |
LICENSE | 2 weeks ago | |
README.md | 2 weeks ago | |
input.py | 2 weeks ago | |
output.py | 2 weeks ago |
README.md
Software Task 2
Transmission Control Protocol (TCP)
Before setting up any connection between the client script input.py
and server script output.py
they need to agree on which port to use. The server script is executed first so it can start listening on the defined port. Then the client script is executed, which then it will connect to the server and start sending data.
Client:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect(IP)
sock.sendall(b'Connected...')
data = sock.recv(BUFFER_SIZE)
Server:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(IP)
sock.listen()
connect, address = sock.accept()
with connect:
Button Input
For controls, pynput was used due to prior experience with it. The client script listens for any key presses:
with keyboard.Listener(
on_press=on_press,
on_release=on_release
) as listener:
listener.join()
If any of the buttons in the array char_keys
or the arrow keys is pressed or released the client script sends that to the server as a binary data over TCP.
char_keys = ['a', 'w', 's', 'd', '0', '1', '2', '3', '4', '5']
...
arrow_keys = [key.left, key.up, key.down, key.right]
The character keyboard buttons a
, w
, s
, d
and the arrow keys control the direction of the rover. The numbers 0
through 5
control the speed of the motors. The escape key Esc
is reserved to quit both client and server scripts. Each button is usually accompanied by a status
variable. The status
variable is a boolean value which is set to 1
when the button is pressed and 0
when the button is released.
Server Interpretation
Upon execution, the server script defines the port and ip needed for a TCP connection. Then 2 classes are created, wheel
and rover
classes. When a rover
object is created it creates 4 wheel
objects. Each wheel object contains 2 attributes, speed
and direction
(a velocity).
class wheel:
def __init__(self, speed, direction):
self.speed = speed
self.direction = direction
class rover:
def __init__(self, wheel_1, wheel_2, wheel_3, wheel_4):
self.wheel_1 = wheel(0, 'f')
self.wheel_2 = wheel(0, 'f')
self.wheel_3 = wheel(0, 'f')
self.wheel_4 = wheel(0, 'f')
After a successful connection has been made, the server listens to any keys pressed or released. The client script filters out any keys that are not used. The server only gets button inputs that control the rover. The server only takes action if the buttons were pressed down not if they where released.
Direction
Pressing either the left
arrow key or a
will set the direction of the first and second wheel
objects to reverse and the third and forth wheel
objects to forward. If the motors were given a non-zero speed the rover should start rotating counter-clockwise (assuming the code controls a physical rover).
if key == 'a' or key == 'left':
curiosity.wheel_1.direction = reverse
curiosity.wheel_2.direction = reverse
curiosity.wheel_3.direction = forward
curiosity.wheel_4.direction = forward
The same process is used when the right
arrow key or d
are pressed, however the directions are inverted. Pressing the up
arrow key or w
changes the direction of all wheel
objects to forward. Again the same process is done for the down
arrow key or s
button but the direction is backwards.
if key == 'w' or key == 'up':
curiosity.wheel_1.direction = forward
curiosity.wheel_2.direction = forward
curiosity.wheel_3.direction = forward
curiosity.wheel_4.direction = forward
if key == 's' or key == 'down':
curiosity.wheel_1.direction = reverse
curiosity.wheel_2.direction = reverse
curiosity.wheel_3.direction = reverse
curiosity.wheel_4.direction = reverse
if key == 'd' or key == 'right':
curiosity.wheel_1.direction = forward
curiosity.wheel_2.direction = forward
curiosity.wheel_3.direction = reverse
curiosity.wheel_4.direction = reverse
Speed
The speed of the rover is controlled by pressing any of the numerical keys from 0
to 5
(5
being the maximum speed and 0
being off). I could not figure how to implement a Pulse Width Modulation (PWM) to control the speed yet.
if key == '0':
speed = 0
if key == '1':
speed = 51
if key == '2':
speed = 102
if key == '3':
speed = 153
if key == '4':
speed = 204
if key == '5':
speed = 255
#! Need to change speed with PWM
After a new speed
as been set, all the wheel
objects speed
value change to that new speed
.
curiosity.wheel_1.speed = speed
curiosity.wheel_2.speed = speed
curiosity.wheel_3.speed = speed
curiosity.wheel_4.speed = speed
Finally, after the rover
object acquires the speed
and direction
of all of its children wheel
objects, it prints it to the terminal.
print("[{0}{1}][{2}{3}][{4}{5}][{6}{7}]".format(curiosity.wheel_1.direction, curiosity.wheel_1.speed, curiosity.wheel_2.direction,
curiosity.wheel_2.speed, curiosity.wheel_3.direction, curiosity.wheel_3.speed, curiosity.wheel_4.direction, curiosity.wheel_4.speed))
Reflection
I have never directly programmed something that deals with a TCP connection and I thought it would be more difficult. There are some parts of the code relating to the TCP connection that I don't fully understand though. The code has a lot of room for improvements and can be shrunk down to a significantly smaller size. At the beginning, I thought of using both button presses and releases to control the rover but then just made the code work on only button presses, making a few parts of the program obsolete (like the on_release
function and all the code that uses the status
variable). I had difficulty implementing PWM into the code, I don't know how to start.