Xiaotong and I worked together on this project! The goal was to create a collaborative live drawing app using ITP’s Axi-Draw Machine and RESTful APIs.
The functions we aimed for:
- Co-Draw allows people to contribute to a drawing using a web interface
- Control the Axidraw’s position based on the user’s mouse x and y position on the website.
- Use socket.io to allow many people to draw at the same time.
When coding this project, we came across many challenges and we ended up with 2 versions:
- version 1: tweaked example code for the Axi draw and added sockets to it (as backup)
- version 2 (final): uses our own RESTful API that communicates from client → server → serially communicates to machine
Final Version
This version uses our own RESTful API, which was done with a lot of help from Professor Tom Igoe. We were able to get as far as sending commands from the client side –> server side –> (communicate serially) –> to axi draw machine.
Systems Diagram
Server side:
a.) GET and POST endpoints
// here are all your endpoints. The pattern is: // GET the current value, or // POST the new value as a request param: server.get('/mouse', getMouseState); server.get('/command/:command', runRemoteCommand); server.post('/mouse/:mouse_x/:mouse_y', moveMouse); server.post('/mouse/:mouse_y', handlePostRequest); server.get('/state', handleGetRequest); server.post('/state/:state', handlePostRequest);
b.) moveMouse() function that gets request from client and puts into a string to send to Serial
function moveMouse(request, response) { // request is /mouse/:mouse_x/:mouse_y' // get the position from the request //SM,1000,-250,766\r let result='SM,'+'1000,'+request.params.mouse_x+","+request.params.mouse_y; // send it to the serial port as a command sendSerialData(result); // wait for confirmation from the serial port // send a response back to the user response.send(result); //send for string }
c.) Send command from mouseMove() function to Serial
function sendSerialData(command) { console.log(command+'\r'); myPort.write(command+'\r'); console.log("Sending something out the serial port"); }
—
Client Side
a.) setMouse() sends POST request to server using httpDo function of p5js
function setMouse(x, y) { var path = '/mouse/' + x + '/' + y; // assemble the full URL var content = ''; console.log('path: ' + path); //httpDo( path, 'GET', content, 'text', getResponse); //HTTP PUT the change httpDo(path, 'POST', content, 'text', responseHandler); //HTTP PUT the change }
b.) setMouse() function is called on in index
<!--top left--> <buttononclick="setMouse('-550', '0'); moveTopLeft()">top left</button> <!--top--> <buttononclick="setMouse('-1000', '550'); moveTop()">top</button> <!--top right--> <buttononclick="setMouse('0', '550'); moveTopRight()">top right</button> <!--bottom left--> <buttononclick="setMouse('0', '-550'); moveButtomLeft()">bottom left</button> <!--bottom--> <buttononclick="setMouse('550', '-550'); moveButtom()">bottom</button> <!--bottom right--> <buttononclick="setMouse('1000', '500'); moveButtomRight()">bottom right</button>
—
Socket Code
// Function for sending to the socket function sendmouse(xpos, ypos) { // We are sending! console.log("sendmouse: "+xpos+" "+ypos); // Make a little object with and y vardata= { x:xpos, y:ypos }; // Send that object to the socket socket.emit('mouse', data); }
b.) Socket code on server side for listening for data, then emitting
// When this user emits, client side: socket.emit('otherevent',some data); socket.on('mouse', function (data) { // Data comes in as whatever was sent, including objects console.log("Received: 'mouse' "+data.x+" "+data.y); // Send it to all other clients socket.broadcast.emit('mouse', data); // This is a way to send to everyone including sender // io.sockets.emit('message', "this goes to everyone"); } );
Version 2 (sockets added to AxiDraw Example Code)
For this version, we used the cncserver code as our example: https://github.com/techninja/cncserver
Run cncserver.js
install Node.js
install npm
node cncserver.js
References we used:
- SerialOut: https://github.com/tigoe/NodeExamples/blob/master/SerialIntro/serialOut.js
- Set up serial port
- Readline parser
- myPort
- httpDo (for p5): https://p5js.org/reference/#/p5/httpDo
- EBB Command Set
- EBB command documentation about using serial communication APIs: http://evil-mad.github.io/EggBot/ebb.html#SM
- To use serial in terminal: https://www.youtube.com/watch?v=vpZDfii5n3A
- RESTful API
- https://github.com/tigoe/NodeExamples/blob/master/RestTest/server.js
- We tried to get the mouse position
- Go to the IP address
- Enter the endpoint (mouse/mouse_x)
- Get the data (20, 50)
- AxiDraw app code
- Node with p5js Coding Tutorials + Source code
Process:
a.) Our backup plan of using the AxiDraw code and just adding sockets to it (when our own code wasn’t working.)
b.) Practicing sockets to disconnect a user after 30 seconds.
c.) inital start: simply communicating to Axi Draw using serialPort
So Many Thanks:
We bugged way too many people and professors for this project. I’m so grateful to everyone who took the time to help and listen. The biggest thank you to Professor Tom Igoe for being patient and spending so much time to help us understand how to write RESTful APIs and how to communicate with the AxiDraw using serial.
Thank you so much to Professor Shawn for providing guidance and troubleshooting help. Thank you Professor Mimi for helping us last minute with the socket pairing.
Thank you Dana and Noah for asking critical questions and giving good feedback during the start/ideation of this project. Thank you Jackie and Andrew for guiding us through the logic.