Skip to content

Commit

Permalink
feature: build firmware from web interface using firmware/src
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Hechenberger committed Aug 2, 2013
1 parent de50b6d commit 5c1569b
Show file tree
Hide file tree
Showing 21 changed files with 3,029 additions and 14 deletions.
49 changes: 44 additions & 5 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from bottle import *
from serial_manager import SerialManager
from flash import flash_upload, reset_atmega
from build import build_firmware
from filereaders import read_svg, read_dxf


Expand Down Expand Up @@ -72,7 +73,7 @@ class HackedWSGIRequestHandler(WSGIRequestHandler):
on the BeagleBone and RaspberryPi. The problem is WSGIRequestHandler
which does a reverse lookup on every request calling gethostbyaddr.
For some reason this is super slow when connected to the LAN.
(adding the the IP and name of the requester in the /etc/hosts file
(adding the IP and name of the requester in the /etc/hosts file
solves the problem but obviously is not practical)
"""
def address_string(self):
Expand Down Expand Up @@ -373,13 +374,33 @@ def flash_firmware_handler(firmware_file=FIRMWARE):
else:
print "ERROR: Failed to flash Arduino."
ret.append('<h2>Flashing Failed!</h2> Check terminal window for possible errors. ')
ret. append('Most likely LasaurApp could not find the right serial port.<br><a href="/">return</a><br><br>')
ret.append('Most likely LasaurApp could not find the right serial port.')
ret.append('<br><a href="/flash_firmware/'+firmware_file+'">try again</a> or <a href="/">return</a><br><br>')
if os.name != 'posix':
ret. append('If you know the COM ports the Arduino is connected to you can specifically select it here:')
for i in range(1,13):
ret. append('<br><a href="/flash_firmware?port=COM%s">COM%s</a>' % (i, i))
return ''.join(ret)



@route('/build_firmware')
def build_firmware_handler():
ret = []
buildname = "LasaurGrbl_from_src"
firmware_dir = os.path.join(resources_dir(), 'firmware')
source_dir = os.path.join(resources_dir(), 'firmware', 'src')
return_code = build_firmware(source_dir, firmware_dir, buildname)
if return_code != 0:
print ret
ret.append('<h2>FAIL: build error!</h2>')
ret.append('Syntax error maybe? Try builing in the terminal.')
ret.append('<br><a href="/">return</a><br><br>')
else:
print "SUCCESS: firmware built."
ret.append('<h2>SUCCESS: new firmware built!</h2>')
ret.append('<br><a href="/flash_firmware/'+buildname+'.hex">Flash Now!</a><br><br>')
return ''.join(ret)


@route('/reset_atmega')
def reset_atmega_handler():
Expand Down Expand Up @@ -501,8 +522,10 @@ def svg_upload():
argparser.add_argument('-v', '--version', action='version', version='%(prog)s ' + VERSION)
argparser.add_argument('-p', '--public', dest='host_on_all_interfaces', action='store_true',
default=False, help='bind to all network devices (default: bind to 127.0.0.1)')
argparser.add_argument('-f', '--flash', dest='build_and_flash', action='store_true',
argparser.add_argument('-f', '--flash', dest='flash', action='store_true',
default=False, help='flash Arduino with LasaurGrbl firmware')
argparser.add_argument('-b', '--build', dest='build_flash', action='store_true',
default=False, help='build and flash from firmware/src')
argparser.add_argument('-l', '--list', dest='list_serial_devices', action='store_true',
default=False, help='list all serial devices currently connected')
argparser.add_argument('-d', '--debug', dest='debug', action='store_true',
Expand Down Expand Up @@ -672,12 +695,28 @@ def svg_upload():
debug(True)
if hasattr(sys, "_MEIPASS"):
print "Data root is: " + sys._MEIPASS
if args.build_and_flash:
if args.flash:
return_code = flash_upload(SERIAL_PORT, resources_dir(), FIRMWARE, HARDWARE)
if return_code == 0:
print "SUCCESS: Arduino appears to be flashed."
else:
print "ERROR: Failed to flash Arduino."
elif args.build_flash:
# build
buildname = "LasaurGrbl_from_src"
firmware_dir = os.path.join(resources_dir(), 'firmware')
source_dir = os.path.join(resources_dir(), 'firmware', 'src')
return_code = build_firmware(source_dir, firmware_dir, buildname)
if return_code != 0:
print ret
else:
print "SUCCESS: firmware built."
# flash
return_code = flash_upload(SERIAL_PORT, resources_dir(), FIRMWARE, HARDWARE)
if return_code == 0:
print "SUCCESS: Arduino appears to be flashed."
else:
print "ERROR: Failed to flash Arduino."
else:
if args.host_on_all_interfaces:
run_with_callback('', NETWORK_PORT)
Expand Down
94 changes: 94 additions & 0 deletions backend/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Super Awesome LasaurGrbl python flash script.
#
# Copyright (c) 2011 Nortd Labs
# Open Source by the terms of the Gnu Public License (GPL3) or higher.

import os, sys, subprocess, shutil

# Make sure you have the Arduino IDE installed (we've tested this on 022 and newer).
# While build.py does not use the IDE directly it makes use of its tool chain.
# On Linux all you need is the "arduino-core" package.
# Please verify the following locations are correct for you platform:

if sys.platform == "darwin": # OSX
AVRDUDEAPP = "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avrdude"
AVRGCCAPP = "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-gcc"
AVROBJCOPYAPP = "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-objcopy"
AVRSIZEAPP = "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-size"
AVROBJDUMPAPP = "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-objdump"
AVRDUDECONFIG = "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/etc/avrdude.conf"

elif sys.platform == "win32": # Windows
AVRDUDEAPP = "C:\\arduino\\hardware\\tools\\avr\\bin\\avrdude"
AVRGCCAPP = "C:\\arduino\\hardware\\tools\\avr\\bin\\avr-gcc"
AVROBJCOPYAPP = "C:\\arduino\\hardware\\tools\\avr\\bin\\avr-objcopy"
AVRSIZEAPP = "C:\\arduino\\hardware\\tools\\avr\\bin\\avr-size"
AVROBJDUMPAPP = "C:\\arduino\\hardware\\tools\\avr\\bin\\avr-objdump"
AVRDUDECONFIG = "C:\\arduino\\hardware\\tools\\avr\\etc\\avrdude.conf"

elif sys.platform == "linux" or sys.platform == "linux2": #Linux
AVRDUDEAPP = "avrdude"
AVRGCCAPP = "avr-gcc"
AVROBJCOPYAPP = "avr-objcopy"
AVRSIZEAPP = "avr-size"
AVROBJDUMPAPP = "avr-objdump"
AVRDUDECONFIG = "/etc/avrdude.conf"



# =============================================================================
# No need to edit anything below this line


def build_firmware(source_dir, firmware_dir, firmware_name):
ret = 0
cwd_temp = os.getcwd()
os.chdir(source_dir)

DEVICE = "atmega328p"
CLOCK = "16000000"
BUILDNAME = firmware_name
OBJECTS = ["main", "serial", "gcode", "planner", "sense_control", "stepper"]

COMPILE = AVRGCCAPP + " -Wall -Os -DF_CPU=" + CLOCK + " -mmcu=" + DEVICE + " -I. -ffunction-sections" + " --std=c99"

for fileobj in OBJECTS:
command = '%(compile)s -c %(obj)s.c -o %(obj)s.o' % {'compile': COMPILE, 'obj':fileobj}
ret += subprocess.call(command, shell=True)

command = '%(compile)s -o main.elf %(alldoto)s -lm' % {'compile': COMPILE, 'alldoto':".o ".join(OBJECTS)+'.o'}
ret += subprocess.call(command, shell=True)

command = '%(objcopy)s -j .text -j .data -O ihex main.elf %(product)s.hex' % {'objcopy': AVROBJCOPYAPP, 'obj':fileobj, 'product':BUILDNAME}
ret += subprocess.call(command, shell=True)

command = '%(size)s *.hex *.elf *.o' % {'size':AVRSIZEAPP}
ret += subprocess.call(command, shell=True)

# os.system('%(objdump)s -t -j .bss main.elf' % {'objdump':AVROBJDUMPAPP})

if ret != 0:
os.chdir(cwd_temp)
return "Error: failed to build"

try:
## clean after upload
print "Cleaning up build files."
for fileobj in OBJECTS:
f = '%s.o' % (fileobj)
if os.path.isfile(f):
os.remove(f)
if os.path.isfile('main.elf'):
os.remove('main.elf')

## move firmware hex file
print "Moving firmware to standard location."
firmware_src = firmware_name+'.hex'
firmware_dst = os.path.join(firmware_dir, firmware_src)
shutil.move(firmware_src, firmware_dst)
finally:
#restore previous cwd
os.chdir(cwd_temp)

return 0

4 changes: 2 additions & 2 deletions backend/flash.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def flash_upload(serial_port, resources_dir, firmware_file, hardware='x86'):
AVRDUDECONFIG = os.path.join(resources_dir, "firmware/tools_osx/avrdude.conf")

elif sys.platform == "win32": # Windows
AVRDUDEAPP = os.path.join(resources_dir, "firmware/tools_win/avrdude")
AVRDUDECONFIG = os.path.join(resources_dir, "firmware/tools_win/avrdude.conf")
AVRDUDEAPP = os.path.join(resources_dir, "firmware", "tools_win", "avrdude")
AVRDUDECONFIG = os.path.join(resources_dir, "firmware", "tools_win", "avrdude.conf")

elif sys.platform == "linux" or sys.platform == "linux2": #Linux
AVRDUDEAPP = os.path.join(resources_dir, "/usr/bin/avrdude")
Expand Down
50 changes: 50 additions & 0 deletions firmware/src/NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@


Beam Dynamics Contemplations
-----------------------------

### intensity assumptions
intensity 100% = 100 pulses per 32us
intensity 20% = 20 pulses per 32us
pulses_per_32us * 31250 = pulses_per_seconds
intensity 100% = 3125000 pulses per seconds

!! but pulse length not a good measure, because beginning of the pulse most energy !!


### nominal
nominal_intensity
nominal_steps_per_minute = nominal_feedrate * CONFIG_STEPS_PER_MM

nominal_pulses_per_second = nominal_intensity * 31250
nominal_step_dur_in_seconds = 60/nominal_steps_per_minute
nominal_pulses_per_step = nominal_step_dur_in_seconds / nominal_pulses_per_second

### actual
steps_per_minute
step_dur_in_seconds = 60/steps_per_minute
pulses_per_step = step_dur_in_seconds / pulses_per_second



### Q: what intensity so pulses_per_step == nominal_pulses_per_step?

pulses_per_step == nominal_pulses_per_step
step_dur_in_seconds / pulses_per_second == nominal_step_dur_in_seconds / nominal_pulses_per_second
step_dur_in_seconds / (intensity * 31250) == nominal_step_dur_in_seconds / (nominal_intensity * 31250)
(step_dur_in_seconds/31250) = (intensity*nominal_step_dur_in_seconds) / (nominal_intensity * 31250)

intensity = (step_dur_in_seconds/31250) / ((nominal_step_dur_in_seconds) / (nominal_intensity * 31250))
intensity = (step_dur_in_seconds/31250) * ((nominal_intensity * 31250) / (nominal_step_dur_in_seconds))
intensity = (step_dur_in_seconds * nominal_intensity) / nominal_step_dur_in_seconds
intensity = (60/steps_per_minute * nominal_intensity) / 60/nominal_steps_per_minute
intensity = ((60/steps_per_minute) * nominal_intensity) / (60/(nominal_feedrate*CONFIG_STEPS_PER_MM))
intensity = (nominal_intensity/steps_per_minute) / (1/(nominal_feedrate*CONFIG_STEPS_PER_MM))
intensity = (nominal_intensity/steps_per_minute) * (nominal_feedrate*CONFIG_STEPS_PER_MM)
intensity = (nominal_intensity * nominal_feedrate * CONFIG_STEPS_PER_MM) / steps_per_minute

intensity = (current_block->nominal_laser_intensity * current_block->nominal_speed * CONFIG_STEPS_PER_MM) / steps_per_minute

!! we actually need this based on the actual head speed !!

adjusted_intensity = nominal_intensity * (nominal_speed/actual_speed)
71 changes: 71 additions & 0 deletions firmware/src/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@

Lasersaur - Open Source Laser cutter
-------------------------------------

This is the firmware we use for the Lasersaur. It's a slightly modified version of grbl. It's what runs on an Arduino Uno and takes g-code files to controls the stepper motors accordingly.

How to get this firmware onto an Arduino Uno? There is a python script that will do the trick. Edit the "flash.py" and follow the instruction in it. You will need a USB cable and the Arduino IDE.

For more information see the [Lasersaur Software Setup Guide](http://labs.nortd.com/lasersaur/manual/software_setup).

**DISCLAIMER:** Please be aware that operating a DIY laser cutter can be dangerous and requires full awareness of the risks involved. You build the machine and you will have to make sure it is safe. The instructions of the Lasersaur project and related software come without any warranty or guarantees whatsoever. All information is provided as-is and without claims to mechanical or electrical fitness, safety, or usefulness. You are fully responsible for doing your own evaluations and making sure your system does not burn, blind, or electrocute people.


Grbl - An embedded g-code interpreter and motion-controller for the Arduino/AVR328 microcontroller
--------------

For more information [on Grbl](https://github.com/simen/grbl)


TODO
------
- g55 wrong offset
- homing cycle cannot recover out of bounds when limit already triggering

mbed merger notes
------------------
- removed
- inverse mode
- plane selection, G17, G18, G19
- arc support, G2, G3
- M112, use M2 instead

- laser intensity, 255 or 1.0
- trunc() function in gcode parser
- NEXT_ACTION_STOP, newer code
- direction_bits to be uint8_t
- nominal_laser_intensity to be uint8_t
- rate_delta to be int32
- SystemCoreClock/4 to be F_CPU
- out_bits to be uint8_t
- static volatile int busy; no need
- stepper_init
- stepper_synchronize
- stepper_wake_up
- stepper_go_idle
- bit masking

TODO: dwell, cancel, coordinate systems
proportional laser intensity
check for: limits, door, power (vrel), chiller


Coordinate Systems
------------------

- use G10 L20 P1 to make the current position the origin in the G54 coordinate system, P2 for the G55 coord system
- select coord system with G54, G55, G56
- usage scenario:
- use G10 L20 P1 in homing cycle to set the physical home position, associated with G54
- use G10 L2 P2 X10 Y10 to set a standard offset from the home, associated with the G55 coords
- use G10 L20 P3 (or G10 L2 P3 X__ Y1__) to set a temporary origin, associated with G56

stop, pause, resume
--------------------
stop on: power, chiller, limit, \03 control char
stop resume on: \02 control char
pause on: door, resume on door close




28 changes: 28 additions & 0 deletions firmware/src/beaglebone_flash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Super Awesome LasaurGrbl python flash script.
#
# Copyright (c) 2011 Nortd Labs
# Open Source by the terms of the Gnu Public License (GPL3) or higher.

import os, sys


# Make sure you have avrdude installed on the beaglebone
# opkg install libreadline5_5.2-r8.9_armv4.ipk
# opkg install avrdude_5.10-r1.9_armv7a.ipk
# get the packages from http://www.angstrom-distribution.org/repo/

AVRDUDEAPP = "avrdude"
AVRDUDECONFIG = "/etc/avrdude.conf"
SERIAL_PORT = "/dev/ttyO1"
DEVICE = "atmega328p"
PROGRAMMER = "arduino" # use this for bootloader
SERIAL_OPTION = '-P %(port)s' % {'port':SERIAL_PORT}
BITRATE = "115200"
BUILDNAME = "LasaurGrbl"

# use beaglebone gpio2_7 to reset the atmege here

os.system('%(dude)s -c %(programmer)s -b %(bps)s %(serial_option)s -p %(device)s -C %(dudeconf)s -Uflash:w:%(product)s.hex:i' % {'dude':AVRDUDEAPP, 'programmer':PROGRAMMER, 'bps':BITRATE, 'serial_option':SERIAL_OPTION, 'device':DEVICE, 'dudeconf':AVRDUDECONFIG, 'product':BUILDNAME})
# os.system('%(dude)s -c %(programmer)s -b %(bps)s -P %(port)s -p %(device)s -C %(dudeconf)s -B 10 -F -U flash:w:%(product)s.hex:i' % {'dude':AVRDUDEAPP, 'programmer':PROGRAMMER, 'bps':BITRATE, 'port':SERIAL_PORT, 'device':DEVICE, 'dudeconf':AVRDUDECONFIG, 'product':BUILDNAME})


Loading

0 comments on commit 5c1569b

Please sign in to comment.