Go to file
array-in-a-matrix d1e95b4891 init 2023-03-18 02:09:34 -04:00
.gitignore init 2023-03-18 02:09:34 -04:00
LICENSE init 2023-03-18 02:09:34 -04:00
README.md init 2023-03-18 02:09:34 -04:00
input.py init 2023-03-18 02:09:34 -04:00
output.py init 2023-03-18 02:09:34 -04:00

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.