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.