diff --git a/content/posts/automated-poker-table/index.md b/content/posts/automated-poker-table/index.md
index 382e25e..c3cf5f2 100644
--- a/content/posts/automated-poker-table/index.md
+++ b/content/posts/automated-poker-table/index.md
@@ -43,6 +43,7 @@ The Arduino Nano handles I/O control for the 4 button panels which enable player
+
\ No newline at end of file
diff --git a/content/posts/chess-robot/index.md b/content/posts/chess-robot/index.md
index 845e4d6..49d2de3 100644
--- a/content/posts/chess-robot/index.md
+++ b/content/posts/chess-robot/index.md
@@ -50,258 +50,4 @@ Resetting a chess board after a game is such a simple task for humans it is ofte
The blue squares outlining the main board are reserved for captured pieces (and the extra queen). Whenever a capture occurs, the robot places the captured piece into the corresponding square.
-When solving for an optimal path using a state-space exploration with A*, the space rapidly expands and is infeasible to solve. Our approach was to use a greedy algorithm minimizing axes movement.
-
-```python
-from math import sqrt
-from CapturedPieceManagement import CapturedPieceManagement
-import chess
-import Arduino
-
-whiteSetup = [
- list("RNBQQBNR"),
- list("PPPPPPPP"),
-]
-blackSetup = [
- ["r", "p"],
- ["n", "p"],
- ["b", "p"],
- ["q", "p"],
- ["q", "p"],
- ["b", "p"],
- ["n", "p"],
- ["r", "p"],
-]
-
-
-def calculateMoveDistance(m):
- if m[0] == "board":
- return chess.square_distance(m[1], m[2])
- if m[0] == "white":
- return 2 - m[2] + chess.square_distance(chess.square(m[1], 7), m[3])
- if m[0] == "black":
- if m[1] == -1:
- return 1 + chess.square_distance(chess.square(0, m[2]), m[3])
- else:
- return 1 + chess.square_distance(chess.square(7, m[2]), m[3])
-
-
-def getSuccessors(fen, white, black):
- successors = []
- b: chess.Board = chess.Board(fen)
- empty_squares = [x for x in chess.SQUARES if b.piece_at(x) is None]
- for i in range(64):
- p = b.piece_at(i)
- if p is not None and init_board.piece_at(i) != p:
- min_dist = 100
- min_square = None
- for j in empty_squares:
- if init_board.piece_at(j) == p:
- d = sqrt((chess.square_file(i) - chess.square_file(j))**2 +
- (chess.square_rank(i) - chess.square_rank(j))**2)
- if d <= min_dist:
- min_dist = d
- min_square = j
- if min_square is not None:
- new_board = b.copy()
- new_board.set_piece_at(min_square, p)
- new_board.remove_piece_at(i)
- successors.append(((new_board.fen(), white, black),
- ("board", i, min_square), min_dist))
- # White takens
- for x in range(8):
- for y in range(2):
- min_dist = 100
- min_square = None
- if x == 3 and y == 0:
- continue
- if white[y, x] == 1:
- p = whiteSetup[y][x]
- for e in empty_squares:
- if str(init_board.piece_at(e)) == p:
- d = calculateMoveDistance(("white", x, y, e))
- if d <= min_dist:
- min_dist = d
- min_square = e
- if min_square is not None:
- new_board = b.copy()
- new_board.set_piece_at(min_square,
- init_board.piece_at(min_square))
- newWhite = white.copy()
- newWhite[y, x] = 0
- successors.append(((new_board.fen(), newWhite, black),
- ("white", x, y, min_square), min_dist))
- # Black takens
- for x in [-1, 1]:
- for y in range(8):
- min_dist = 100
- min_square = None
- if x == -1 and y == 3:
- continue
- if x == -1:
- blackCoord = 0
- else:
- blackCoord = 1
- if black[y, blackCoord] == 1:
- p = blackSetup[y][blackCoord]
- for e in empty_squares:
- # print(e, init_board.piece_at(e))
- if str(init_board.piece_at(e)) == p:
- d = calculateMoveDistance(("black", x, y, e))
- if d <= min_dist:
- min_dist = d
- min_square = e
- if min_square is not None:
- new_board = b.copy()
- new_board.set_piece_at(min_square,
- init_board.piece_at(min_square))
- newBlack = black.copy()
- newBlack[y, x] = 0
- successors.append(((new_board.fen(), white, newBlack),
- ("black", x, y, min_square), min_dist))
-
- return successors
-
-
-startingFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"
-
-
-def findPathGreedy(fen, captured: CapturedPieceManagement):
- currentSquare = 56
- currentFen = fen
- w = captured.white
- b = captured.black
- moves = []
- while (currentFen.split(" ")[0] != startingFen):
- print("Fen: " + currentFen)
- print("White: " + str(w))
- print("Black: " + str(b))
- possibleMoves = getSuccessors(currentFen, w, b)
- bestCost = 100
- if len(possibleMoves) == 0:
- return False
- for m in possibleMoves:
- if m[1][0] == "board":
- dstToStart = chess.square_distance(m[1][1], currentSquare)
- if m[1][0] == "white":
- dstToStart = calculateMoveDistance(
- ("white", m[1][1], m[1][2], m[1][3]))
- if m[1][0] == "black":
- dstToStart = calculateMoveDistance(
- ("black", m[1][1], m[1][2], m[1][3]))
- cost = m[2] + dstToStart
- if cost < bestCost:
- bestCost = cost
- bestMove = m
-
- currentSquare = bestMove[1][-1]
- currentFen = bestMove[0][0]
- w = bestMove[0][1]
- b = bestMove[0][2]
- moves.append((bestMove[1], bestMove[0][0]))
- print(bestMove[1])
- return moves
-
-
-def convertSquareToCoordinates(square: str):
- return [ord(square[0]) - ord('a'), 8 - int(square[1])]
-
-
-def getAdjacentSquares(square: int):
- return [square + 1, square - 1, square + 8, square - 8]
-
-
-def isMoveLift(fen, move):
- b = chess.Board(fen)
- if move[0] == "board":
- # Check to see if there are pieces between start and end square
-
- start = move[1]
- end = move[2]
- minimum = min(start, end)
- maximum = max(start, end)
- offset = maximum - minimum
- if offset % 8 == 0:
- for i in range(minimum + 8, maximum, 8):
- if b.piece_at(i) is not None:
- return False
- if chess.square_file(start) == chess.square_file(end):
- for i in range(minimum + 1, maximum):
- if b.piece_at(i) is not None:
- return False
- if offset % 9 == 0:
- for i in range(minimum + 9, maximum, 9):
- if b.piece_at(i) is not None:
- return False
- for s in getAdjacentSquares(i):
- if b.piece_at(s) is not None:
- return False
- if offset % 7 == 0:
- for i in range(minimum + 7, maximum, 7):
- if b.piece_at(i) is not None:
- return False
- for s in getAdjacentSquares(i):
- if b.piece_at(s) is not None:
- return False
- return True
-
-
-def reset_game_board(fen, captured: CapturedPieceManagement):
- a = Arduino.Arduino("/dev/cu.usbmodem142101")
- a.waitForReady()
- path = findPathGreedy(fen, captured)
- if path is False:
- print("Unable to find path")
- return False
- for m, f in path:
- if m[0] == "board":
- startSquare = convertSquareToCoordinates(chess.square_name(m[1]))
- endSquare = convertSquareToCoordinates(chess.square_name(m[2]))
- a.sendCommand("move", [startSquare[0], startSquare[1]])
- a.waitForReady()
- if isMoveLift(f, m):
- a.sendCommand("pickup", [])
- else:
- a.sendCommand("smallPickup", [])
- a.waitForReady()
- a.sendCommand("move", [endSquare[0], endSquare[1]])
- a.waitForReady()
- a.sendCommand("drop", [])
- a.waitForReady()
- if m[0] == "white":
- a.sendCommand("moveWhiteTaken", [m[1], m[2]])
- a.waitForReady()
- a.sendCommand("pickupTaken", [])
- endSquare = convertSquareToCoordinates(chess.square_name(m[3]))
- a.sendCommand("move", [endSquare[0], endSquare[1]])
- a.waitForReady()
- a.sendCommand("drop", [])
- a.waitForReady()
- if m[0] == "black":
- a.sendCommand("moveBlackTaken", [m[1], m[2]])
- a.waitForReady()
- a.sendCommand("pickupTaken", [])
- endSquare = convertSquareToCoordinates(chess.square_name(m[3]))
- a.sendCommand("move", [endSquare[0], endSquare[1]])
- a.waitForReady()
- a.sendCommand("drop", [])
- a.waitForReady()
-
-
-if __name__ == "__main__":
- cap = CapturedPieceManagement()
- b = chess.Board()
- # Testing
- b.set_board_fen("r3k1nr/p4pNp/n7/1p1pP2P/6P1/3P1Q2/PRP1K3/q5bR")
- cap.placePiece("black", "pawn")
- cap.placePiece("black", "pawn")
- cap.placePiece("black", "pawn")
- cap.placePiece("black", "bishop")
- cap.placePiece("white", "pawn")
- cap.placePiece("white", "pawn")
- cap.placePiece("white", "bishop")
- cap.placePiece("white", "bishop")
- cap.placePiece("white", "knight")
- print(findPathGreedy(b.fen(), cap))
- reset_game_board(b.fen(), cap)
-```
+When solving for an optimal path using a state-space exploration with A*, the space rapidly expands and is infeasible to solve. Our approach was to use a [greedy algorithm minimizing axes movement](https://github.com/Connor205/Chess-Robot-NURobotics/blob/main/mk1/resetFinder.py).
diff --git a/content/posts/robot-arm-edu/assembly_instructions.png b/content/posts/robot-arm-edu/assembly_instructions.png
new file mode 100644
index 0000000..e2c6b07
Binary files /dev/null and b/content/posts/robot-arm-edu/assembly_instructions.png differ
diff --git a/content/posts/robot-arm-edu/index.md b/content/posts/robot-arm-edu/index.md
index 8abaa53..55147ab 100644
--- a/content/posts/robot-arm-edu/index.md
+++ b/content/posts/robot-arm-edu/index.md
@@ -1,7 +1,7 @@
---
title: "Educational Robot Arm"
date: 2024-01-05T09:00:00+00:00
-description: Introduction to Sample Post
+description: Educational Kit for Introductory Robotics
hero: images/kavar_background.jpg
author:
image: /images/sharwin_portrait.jpg
@@ -10,6 +10,15 @@ menu:
name: Educational Robot Arm
identifier: robot-arm-edu
weight: 4
-tags: ["Basic", "Multi-lingual"]
+tags: ["3D Printing", "Arduino", "C++", "MATLAB"]
# categories: ["Basic"]
----
\ No newline at end of file
+---
+
+An educational kit designed to teach the fundamentals of kinematics and dynamics. The kit is intended to accompany the course ME3460: Robot Dynamics & Control at Northeastern University. The kit is a physical representation of the final project, which is currently done purely through MATLAB simulation.
+
+## Kit Design
+The entire kit is composed of 3D printed parts, and off-the-shelf hardware/electronics. Students can assemble the kit without any soldering and with minimal tools.
+
+