From c21ad06c14bea9630bf9b539bf28b1aa6cb92245 Mon Sep 17 00:00:00 2001 From: Danny Staple Date: Mon, 21 Mar 2022 18:57:25 +0000 Subject: [PATCH] Start wtih the same live graph module. Along with library dependancies. --- .../1-encoder-to-counts-speed/pio_encoder.py | 82 +++++++++++++++++++ ch-11/1-encoder-to-counts-speed/robot.py | 52 ++++++++++++ ch-11/1-encoder-to-counts-speed/robot_wifi.py | 25 ++++++ ch-11/pc-live-graph/live_graph.py | 53 ++++++++++++ ch-11/pc-live-graph/requirements.txt | 2 + 5 files changed, 214 insertions(+) create mode 100644 ch-11/1-encoder-to-counts-speed/pio_encoder.py create mode 100755 ch-11/1-encoder-to-counts-speed/robot.py create mode 100644 ch-11/1-encoder-to-counts-speed/robot_wifi.py create mode 100644 ch-11/pc-live-graph/live_graph.py create mode 100644 ch-11/pc-live-graph/requirements.txt diff --git a/ch-11/1-encoder-to-counts-speed/pio_encoder.py b/ch-11/1-encoder-to-counts-speed/pio_encoder.py new file mode 100644 index 0000000..3d61050 --- /dev/null +++ b/ch-11/1-encoder-to-counts-speed/pio_encoder.py @@ -0,0 +1,82 @@ +import rp2pio +import adafruit_pioasm +import array + +program = """ +; use the osr for count +; input pins c1 c2 + + set y, 0 ; clear y + mov osr, y ; and clear osr +read: + ; x will be the old value + ; y the new values + mov x, y ; store old Y in x + in null, 32 ; Clear ISR - using y + in pins, 2 ; read two pins into y + mov y, isr + jmp x!=y, different ; Jump if its different + jmp read ; otherwise loop back to read + +different: + ; x has old value, y has new. + ; extract the upper bit of X. + in x, 31 ; get bit 31 - old p1 (remember which direction it came in) + in null, 31 ; keep only 1 bit + mov x, isr ; put this back in x + jmp !x, c1_old_zero + +c1_old_not_zero: + jmp pin, count_up + jmp count_down + +c1_old_zero: + jmp pin, count_down + ; fall through +count_up: + ; for a clockwise move - we'll add 1 by inverting + mov x, ~ osr ; store inverted OSR on x + jmp x--, fake ; use jump to take off 1 +fake: + mov x, ~ x ; invert back + jmp send +count_down: + ; for a clockwise move, just take one off + mov x, osr ; store osr in x + jmp x--, send ; dec and send +send: + ; send x. + mov isr, x ; send it + push noblock ; put ISR into input FIFO + mov osr, x ; put X back in OSR + jmp read ; loop back +""" + +assembled = adafruit_pioasm.assemble(program) + + +class QuadratureEncoder: + def __init__(self, first_pin, second_pin, reversed=False): + """Encoder with 2 pins. Must use sequential pins on the board""" + self.sm = rp2pio.StateMachine( + assembled, + frequency=0, + first_in_pin=first_pin, + jmp_pin=second_pin, + in_pin_count=2, + ) + self.reversed = reversed + self._buffer = array.array("i", [0]) + self.previous_reading = 0 + + def read(self): + while self.sm.in_waiting: + self.sm.readinto(self._buffer) + if self.reversed: + return -self._buffer[0] + else: + return self._buffer[0] + + def get_speed(self, delta_time): + distance = self.read() + speed = distance / delta_time diff --git a/ch-11/1-encoder-to-counts-speed/robot.py b/ch-11/1-encoder-to-counts-speed/robot.py new file mode 100755 index 0000000..a564a9b --- /dev/null +++ b/ch-11/1-encoder-to-counts-speed/robot.py @@ -0,0 +1,52 @@ +import board +import pwmio +import pio_encoder +import busio +import adafruit_vl53l1x + + +motor_A1 = pwmio.PWMOut(board.GP17) +motor_A2 = pwmio.PWMOut(board.GP16) +motor_B1 = pwmio.PWMOut(board.GP18) +motor_B2 = pwmio.PWMOut(board.GP19) + +right_motor = motor_A1, motor_A2 +left_motor = motor_B1, motor_B2 + +right_encoder = pio_encoder.QuadratureEncoder(board.GP20, board.GP21, reversed=True) +left_encoder = pio_encoder.QuadratureEncoder(board.GP26, board.GP27) + +i2c0 = busio.I2C(sda=board.GP0, scl=board.GP1) +i2c1 = busio.I2C(sda=board.GP2, scl=board.GP3) + +right_distance = adafruit_vl53l1x.VL53L1X(i2c0) +left_distance = adafruit_vl53l1x.VL53L1X(i2c1) + + +def stop(): + motor_A1.duty_cycle = 0 + motor_A2.duty_cycle = 0 + motor_B1.duty_cycle = 0 + motor_B2.duty_cycle = 0 + + +def set_speed(motor, speed): + # Swap motor pins if we reverse the speed + if speed < 0: + direction = motor[1], motor[0] + speed = -speed + else: + direction = motor + speed = min(speed, 1) # limit to 1.0 + max_speed = 2 ** 16 - 1 + + direction[0].duty_cycle = int(max_speed * speed) + direction[1].duty_cycle = 0 + + +def set_left(speed): + set_speed(left_motor, speed) + + +def set_right(speed): + set_speed(right_motor, speed) diff --git a/ch-11/1-encoder-to-counts-speed/robot_wifi.py b/ch-11/1-encoder-to-counts-speed/robot_wifi.py new file mode 100644 index 0000000..7093914 --- /dev/null +++ b/ch-11/1-encoder-to-counts-speed/robot_wifi.py @@ -0,0 +1,25 @@ +import board +import busio +from digitalio import DigitalInOut +from adafruit_esp32spi import adafruit_esp32spi +from adafruit_esp32spi import adafruit_esp32spi_wifimanager + +try: + from secrets import secrets +except ImportError: + print("WiFi secrets are kept in secrets.py, please add them there!") + raise + + +def connect_to_wifi(): + esp32_cs = DigitalInOut(board.GP10) + esp32_ready = DigitalInOut(board.GP9) + esp32_reset = DigitalInOut(board.GP8) + + spi = busio.SPI(board.GP14, MOSI=board.GP11, MISO=board.GP12) + esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) + esp.reset() + wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets) + wifi.connect() + + return wifi, esp diff --git a/ch-11/pc-live-graph/live_graph.py b/ch-11/pc-live-graph/live_graph.py new file mode 100644 index 0000000..f034d74 --- /dev/null +++ b/ch-11/pc-live-graph/live_graph.py @@ -0,0 +1,53 @@ +""" Turn JSON data stream into graphs""" +import requests + +import matplotlib.pyplot as plt +from matplotlib.animation import FuncAnimation + +url = "http://192.168.1.128" + + +class AnimatedGraph: + def __init__(self): + self.fields = {} + self.samples = 100 + self.reset() + + def reset(self): + for field in self.fields: + self.fields[field] = [] + + def make_frame(self, frame): + try: + response = requests.get(url, timeout=1) + except requests.exceptions.RequestException: + print("Waiting...") + return + print(f"Content: {response.content}") + print(f"status: {response.status_code}") + + item = response.json() + + if 'time' in self.fields and item["time"] < self.fields['time'][-1]: + self.reset() + for field in item: + if field not in self.fields: + self.fields[field] = [] + self.fields[field].append(item[field]) + + if len(self.fields['time'] ) > self.samples: + for field in self.fields: + self.fields[field] = self.fields[field][-self.samples:] + + plt.cla() # clear axes. + # plot the items + for field in self.fields: + if field != "time": + plt.plot("time", field, data=self.fields) + + plt.legend(loc="upper right") + +# Create the animation. gcf - get current figure. random_stream - callback func. +animation = FuncAnimation(plt.gcf(), AnimatedGraph().make_frame, interval=200) +plt.tight_layout() +plt.show() diff --git a/ch-11/pc-live-graph/requirements.txt b/ch-11/pc-live-graph/requirements.txt new file mode 100644 index 0000000..66ed226 --- /dev/null +++ b/ch-11/pc-live-graph/requirements.txt @@ -0,0 +1,2 @@ +matplotlib +requests