Connexion machine-homme

1. Concept

L’imprimante 3D est devenu un instrument très importante dans le design et l’industrie. Le design génératif on permet de manipuler les formes et de les changer rapidement avec un input des données extérieurs.
Mais jusqu’à présent il n’y a pas beaucoup des projets où les formes à imprimer est changé pendant l’impression.
Le conception est de le faire pour atteindre une plus fort connexion des machines et les humains.

2. Manipuler l’impression

2.1 L’utilisation d’Octopi

Le logiciel OctoPi établit une connexion entre une imprimante 3D utilisant un RaspberryPi et un navigateur Web. Donc on peut de faire moification d’une forme pendant l’impression.

2.2 Envoyer un Gcode avec un script Python

Ce script Python envoie und gcode utilisant l’Octopi directement au imprimante.

#!/usr/local/bin/python3

import requests
import argparse
import sys
import json
import math

__author__ = 'Andres Torti'


class OctoprintAPI:
    """
    This class is an interface for the Octoprint server API
    """

    def __init__(self, address, port, api_key):
        self.host = address
        self.s = requests.Session()
        self.s.headers.update({'X-Api-Key': api_key,
                               'Content-Type': 'application/json'})

        # Base address for all the requests
        self.base_address = 'http://' + address + ':' + str(port)

    def connect_to_printer(self, port=None, baudrate=None, printer_profile=None, save=None, autoconnect=None):
        """
        Connects to the printer
        :param port: [Optional] port where the printer is connected (ie: COMx in Windows, /dev/ttyXX in Unix systems).
                if not specified the current selected port will be used or if no port is selected auto detection will
                be used
        :param baudrate: [Optional] baud-rate, if not specified the current baud-rate will be used ot if no baud-rate
                is selected auto detection will be used
        :param printer_profile: [Optional] printer profile to be used for the connection, if not specified the default
                one will be used
        :param save: [Optional] whether to save or not the connection settings
        :param autoconnect: [Optional] whether to connect automatically or not on the next Ocotprint start
        """
        data = {'command': 'connect'}
        if port is not None:
            data['port'] = port
        if baudrate is not None:
            data['baudrate'] = baudrate
        if printer_profile is not None:
            data['printerProfile'] = printer_profile
        if save is not None:
            data['save'] = save
        if autoconnect is not None:
            data['autoconnect'] = autoconnect

        r = self.s.post(self.base_address + '/api/connection', json=data)
        if r.status_code != 204:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))

    def is_printer_connected(self):
        """
        Checks if the printer is connected to the Octoprint server
        :return: True if connected, False if not
        """
        r = self.s.get(self.base_address + '/api/printer')
        if r.status_code != 200:
            raise Exception('Error trying to get printer connection status')
        try:
            return json.loads(r.content.decode('utf-8'))["state"]["flags"]["operational"]
        except:
            raise Exception('Error trying to get printer connection status')

    def get_printer_status(self):
        """
        Get the printer status
        :return: string with the printer status (Operational, Disconnected, ...). Returns an empty string
                    if there was an error trying to get the status.
        :raise: TypeError when failed to get printer status
        """
        r = self.s.get(self.base_address + '/api/printer')
        if r.status_code != 200:
           raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))
        try:
            return json.loads(r.content.decode('utf-8'))["state"]["text"]
        except:
            raise Exception('Error trying to get printer status')

    def set_bed_temp(self, temp):
        """
        Set the bed temperature
        :param temp: desired bed temperature
        """
        r = self.s.post(self.base_address + '/api/printer/bed', json={'command': 'target', 'target': temp})
        if r.status_code != 204:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))

    def get_bed_temp(self):
        """
        Get the current bed temperature
        :return: current bed temperature. Returns -1 y there was some error getting the temperature.
        """
        r = self.s.get(self.base_address + '/api/printer/bed')
        if r.status_code != 200:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))
        try:
            return json.loads(r.content.decode('utf-8'))["bed"]["actual"]
        except:
            raise Exception("Error getting bed temperature")

    def pause_job(self):
        """
        Pause the current job
        """
        r = self.s.post(self.base_address + '/api/job', json={'command': 'pause'})
        if r.status_code != 204:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))

    def resume_job(self):
        """
        Resume the current job
        """
        r = self.s.post(self.base_address + '/api/job', json={'command': 'pause'})
        if r.status_code != 204:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))

    def start_job(self):
        """
        Start printing with the currently selected file
        """
        r = self.s.post(self.base_address + '/api/job', json={'command': 'start'})
        if r.status_code != 204:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))

    def cancel_job(self):
        """
        Cancel the current job
        """
        r = self.s.post(self.base_address + '/api/job', json={'command': 'cancel'})
        if r.status_code != 204:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))

    def get_version(self):
        """
        Get Octoprint version
        :return: string with Octoprint version. It returns '0.0.0' if there was an error obtaining the version
        """
        r = self.s.get(self.base_address + '/api/version')
        if r.status_code != 200:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))
        try:
            return json.loads(r.content.decode('utf-8'))["server"]
        except:
            raise Exception("Error getting Octoprint version")

    def get_print_progress(self):
        """
        Get the print progress as a percentage
        :return: float indicating the current print progress
        """
        r = self.s.get(self.base_address + '/api/job')
        if r.status_code != 200:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))
        try:
            return json.loads(r.content.decode('utf-8'))["progress"]["completion"]
        except:
            raise Exception('Error reading print progress')

    def get_total_print_time(self):
        """
        Get the total print time in seconds
        :return: total print time in seconds
        """
        r = self.s.get(self.base_address + '/api/job')
        if r.status_code != 200:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))
        try:
            return json.loads(r.content.decode('utf-8'))["job"]["estimatedPrintTime"]
        except:
            raise Exception('Error reading total print time')

    def get_print_time_left(self):
        """
        Get the print time left of the current job in seconds
        :return: print time left in seconds
        """
        r = self.s.get(self.base_address + '/api/job')
        if r.status_code != 200:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))
        try:
            return json.loads(r.content.decode('utf-8'))["progress"]["printTimeLeft"]
        except:
            raise Exception('Error reading print time left')

    def get_elapsed_print_time(self):
        """
        Get the elapsed print time in seconds of the current job
        :return: elapsed print time in seconds
        """
        r = self.s.get(self.base_address + '/api/job')
        if r.status_code != 200:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))
        try:
            return json.loads(r.content.decode('utf-8'))["progress"]["printTime"]
        except:
            raise Exception('Error reading elapsed print time')

    def get_file_printing(self):
        """
        Get the name of the current file being printed
        :return: name of the file being printed
        """
        r = self.s.get(self.base_address + '/api/job')
        if r.status_code != 200:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))
        try:
            return json.loads(r.content.decode('utf-8'))["job"]["file"]["name"]
        except:
            raise Exception('Error reading filename being printed')

    def send_gcode(self, gcode):
        """
        Sends one or multiple comma separated G-codes to the printer
        :param gcode: G-Code/s to send as a list containing all the G-codes to send
        """
        r = self.s.post(self.base_address + '/api/printer/command', json={'commands': gcode})
        if r.status_code != 204:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))

    def select_file(self, file_name):
        r = self.s.post(self.base_address + '/api/files/local/' + file_name, json={'command': 'select', 'print': True})
        if r.status_code != 200:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))

    def get_extruder_target_temp(self):
        """
        Get the target extruder temperature in degrees celsius
        :return: target extruder temperature in degrees celsius
        """
        r = self.s.get(self.base_address + '/api/printer/tool')
        if r.status_code != 200:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))
        try:
            return json.loads(r.content.decode('utf-8'))["tool0"]["target"]
        except:
            raise Exception('Error retrieving extruder target temperature')

    def get_extruder_current_temp(self):
        """
        Get the current extruder temperature in degrees celsius
        :return: current extruder temperature in degrees celsius
        """
        r = self.s.get(self.base_address + '/api/printer/tool')
        if r.status_code != 200:
            raise Exception("Error: {code} - {content}".format(code=r.status_code, content=r.content.decode('utf-8')))
        try:
            return json.loads(r.content.decode('utf-8'))["tool0"]["actual"]
        except:
            raise Exception('Error retrieving extruder temperature')


def run_and_handle(method, *_args):
    """
    Just a clean way to call any function and print the returned value to 'stdout' if valid or print the error message to
        to 'stderr'
    :param method: function to execute
    :param _args: arguments to pass to the function
    :return: None
    """
    try:
        result = method(*_args)
        if result is not None:
            print(result)
    except Exception as e:
        print(str(e), file=sys.stderr)

if __name__ == '__main__':
    # Create the Octoprint interface
    octo_api = OctoprintAPI("172.30.41.8", "80", "1733C46E4AEE4756B9F2A66F468C7C9F")
    run_and_handle(octo_api.send_gcode, ["G0 Z2 F1000"])
    radius = 20
    point_count_per_layer = 20
    layer_count = 10
    layer_height = 2
    initial_height = 0.3
    speed = 2000
    # start extrusion
    z = initial_height
    for l in range(10):
        for i in range(point_count_per_layer):
            x = radius * math.cos(i / point_count_per_layer * 2 * math.pi)
            y = radius * math.sin(i / point_count_per_layer * 2 * math.pi)
            x = str(round(x, 2))
            y = str(round(y, 2))
            run_and_handle(octo_api.send_gcode, ["G0 X{} Y{} Z{} F{}".format(x, y, z, speed)])
        z = z + layer_height
    # stop extrusion
    print("finished")

3. Usage des donnés sur Internet

On peut chercher beaucoup des photos sur Instagram avec les hashtags. Ici l’exemple est #machineintelligence . https://www.instagram.com/explore/tags/machineintelligence/

3.1 Collecte des données

Avec un script Python on peut collecter toutes les données sur une site Web.

La première exemple est collecter les données sans ordre.

import json
import urllib
from urllib import request

url = "https://www.instagram.com/explore/tags/33thomasstreet/?__a=1"
response = request.urlopen(url)
#print (response)
d = json.loads(response.read())
print(json.dumps(d))

Le résultat est toutes les données comme text:

Mais on peut faire la collecte aussi avec un ordre et faire un fichier .json

import json
import urllib
from urllib import request

url = "https://www.instagram.com/explore/tags/33thomasstreet/?__a=1"
response = request.urlopen(url)
#print (response)
d = json.loads(response.read())
print(json.dumps(d, indent=4, sort_keys=True))

Le résultat est toutes les données ordonnées:

Le script collecte toutes les données on peut trouver sur le site https://www.instagram.com/explore/tags/machineintelligence/?__a=1

3.2 Collecter seulement les données du text

Avec ce script c’est possible de collecter seulement un type des données. Par exemple “text”

import json
import requests
import urllib
from urllib import request
from recursive_json import extract_values

url = "https://www.instagram.com/explore/tags/machineintelligence/?__a=1"
#response = request.urlopen(url)
#d = json.loads(response.read())

# Convert from bytes to text
response = urllib.request.urlopen(url).read().decode('UTF-8')

json_obj = json.loads(response)

text_values = extract_values(json_obj, "text")
print(text_values)

4. Perspective

Comment on peut commencer avec ça recherche?

4.1 Recherche de certains détails

La prochaine étape serait faire un script qui cherche pour certains hashtags (par exemple #future, #3d-printing, #impression3d, #machine, #human, #humanoid, etc.) dans l’ensemble de données. Ainsi, on peut se concentrer sur un résultat spécifique et on peut utiliser ça pour manipuler la forme d’impression.

4.2 Connexion des codes

Depuis, il faut faire une connexion des codes pour faire seulement un script Python, que l’on peut exécuter. Ce script doit chercher dans le site pour certain données et se on trouve certain mots, le script change le Gcode pour manipuler la forme, qui est imprimé.

4.3 Exemple de la forme

La forme peut être un simple cylindre. Sur la forme existe couches qui se modifient. Le script chercher pour certain hashtags toutes les cing couches d’impression. S’il y a un nouveau post avec un certain hashtag la forme se change et le radius du cylindre s’agrandit , s’il n’y a pas un nouveau post, le radius se réduit.

Leave a Reply