diff options
author | David Crocker <dcrocker@eschertech.com> | 2019-01-24 20:24:03 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2019-01-24 20:24:03 +0300 |
commit | cb1e5eb665b63ab4deee381fd1511d5722d9d963 (patch) | |
tree | 7d96793031a1d235d70e334d5d3a6643b9b5f237 | |
parent | 057218b6af1482bbffedcd7e8a940b56075f4a7a (diff) |
Towards 2.03beta1
Fixes to generalised Cartesian kinematics
Support linear delta kinematics with up to 6 towers
M106 Pn Sxx updates mapped fan speed if n is a mapped fan
M408 S2 response now includes bed standby temperature
Support G30 S-3
Added user-settable minimum radius to SCARA parameters
12864 bug fix: erase items that should no longer be visible
30 files changed, 467 insertions, 276 deletions
@@ -20,7 +20,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850" name="Duet085" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850" name="Duet085" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf" "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin""> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.947353540" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.1742191832" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -138,7 +138,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="${ProjName}-RADDS" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1027429289" name="RADDS_RTOS" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="${ProjName}-RADDS" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1027429289" name="RADDS_RTOS" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf" "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin""> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1027429289." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.1973208555" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.2092504710" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -257,13 +257,13 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="${ProjName}-Alligator" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1745168887" name="Alligator" optionalBuildProperties="org.eclipse.cdt.docker.launcher.containerbuild.property.selectedvolumes=,org.eclipse.cdt.docker.launcher.containerbuild.property.volumes=" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="${ProjName}-Alligator" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1745168887" name="Alligator" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf" "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin""> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1745168887." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.623324432" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.645044151" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> <option id="cdt.managedbuild.option.gnu.cross.prefix.629438941" name="Prefix" superClass="cdt.managedbuild.option.gnu.cross.prefix" useByScannerDiscovery="false" value="arm-none-eabi-" valueType="string"/> <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.878309876" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/> - <builder buildPath="${workspace_loc:/RepRapFirmware}/Alligator" id="cdt.managedbuild.builder.gnu.cross.1518897616" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="cdt.managedbuild.builder.gnu.cross"/> + <builder buildPath="${workspace_loc:/RepRapFirmware}/Alligator" id="cdt.managedbuild.builder.gnu.cross.1518897616" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="cdt.managedbuild.builder.gnu.cross"/> <tool id="cdt.managedbuild.tool.gnu.cross.assembler.384615201" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler"> <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1769413014" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> </tool> @@ -381,7 +381,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="Duet2CombinedFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622" name="Duet2_RTOS" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="Duet2CombinedFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622" name="Duet2_RTOS" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf" "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin""> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.435431950" name="Cross GCC" nonInternalBuilderId="cdt.managedbuild.builder.gnu.cross" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.1881231799" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -504,7 +504,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="DuetMaestroFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786" name="DuetM_RTOS" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="DuetMaestroFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786" name="DuetM_RTOS" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf" "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin""> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.1494327638" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.1101985181" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -627,7 +627,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="Duet3Firmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.1275216290.274082366.1645191116.1852610203" name="Duet3" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="Duet3Firmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.1275216290.274082366.1645191116.1852610203" name="Duet3" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf" "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin""> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.1275216290.274082366.1645191116.1852610203." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.5959303" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.163568524" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -766,7 +766,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="PccbFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396" name="PCCB" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="PccbFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396" name="PCCB" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf" "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin""> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.1017317107" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.1932906636" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -888,7 +888,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="PccbFirmware_X5" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396.239853003" name="PCCB_X5" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="PccbFirmware_X5" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396.239853003" name="PCCB_X5" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf" "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin""> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786.1798324396.239853003." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.2113529528" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.1216992967" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -1012,7 +1012,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="SAME70XPLDFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.1275216290.274082366.1645191116.1852610203.216858457" name="SAME70XPLD" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="SAME70XPLDFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.1275216290.274082366.1645191116.1852610203.216858457" name="SAME70XPLD" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf" "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin""> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.1275216290.274082366.1645191116.1852610203.216858457." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.1157300775" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.2145914464" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> @@ -1150,7 +1150,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactExtension="elf" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1168118439" name="Duet085_RTOS" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf ${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin"> + <configuration artifactExtension="elf" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1168118439" name="Duet085_RTOS" optionalBuildProperties="" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.elf" "${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.bin""> <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.1168118439." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.734437241" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release"> <option id="cdt.managedbuild.option.gnu.cross.path.546334814" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/> diff --git a/Maths/trilateration-l3.wxmx b/Maths/trilateration-l3.wxmx Binary files differnew file mode 100644 index 00000000..b16bca05 --- /dev/null +++ b/Maths/trilateration-l3.wxmx diff --git a/src/BugList.txt b/src/BugList.txt index d87bd82c..7ca6034e 100644 --- a/src/BugList.txt +++ b/src/BugList.txt @@ -240,6 +240,9 @@ Done in 2.02 release: - [done, ok] M572 and M221 with no extruder drive number to set all extruders used by the current tool, https://forum.duet3d.com/topic/8444/setting-pressure-advance-in-filament-file - [done, ok with new filament monitor, test with old] Support filament sensor firmware v2 - [done, ok] Improve efficiency of debug print in WiFiInterface: don't keep calling cat and strlen +- [done, ok] Filament monitor to use time since end of last nonprinting extruder move +- [done, ok on bench] Fix continuous rotation speed error bug on Polar kinematics, https://forum.duet3d.com/topic/8747/polar-printing-polar-axis-rotation-issue/3 +- [done, ok, needs community test] Generalised Cartesian kinematics - [done, test] Disable mdns in legacy Duets, https://forum.duet3d.com/topic/8352/duet-0-6-randomly-reboots/5 - [done, test] rr_fileinfo and M36 with no filename to include estimated print time and simulation time in the response, as in the report with a filename - [done, test] In CNC and laser mode update user Z coordinate after tool change, https://forum.duet3d.com/topic/8181/tool-offset-honored-but-not-displayed-correctly @@ -247,6 +250,14 @@ Done in 2.02 release: - [done, test] G92 should not constrain the passed coordinates to the M208 limits if M564 S0 has been used to disable limits - [done, test] Bug fix: month number written to height map.csv and filament files was too low by 1 - [done, test] wilriker PR to allow steps/mm to be quoted in M92, https://forum.duet3d.com/topic/8225/m92-parameter-to-indicate-microstepping/6 +- [done, ok but test with babystepping] Deferred DM allocation and removal of DM array +- [done, test] G30 S-3 option, to set trigger height to stopped height +- [done, test] Bug: 12864 display needs to be refreshed when a change in printer state alters visibility +- [done, test] When M106 Pn Sxxx received, if n = current print cooling fan number, update the print cooling fan speed variable, https://forum.duet3d.com/topic/8540/part-fan-value-missing/6 +- [done, test] PR to send standby bed temperature in M408 +- [done] Scara R parameter to set min radius, https://github.com/dc42/RepRapFirmware/issues/221 +- [done, test] DAA to handle requested accel/decl > max +- [could be related to visibility issue] Investigate 12864 display heater fault warning, https://forum.duet3d.com/topic/7718/12864-display-current-tool-temperatures/6 - Slow startup move issue, https://forum.duet3d.com/topic/8284/firmware-2-02-released/7 (adding S2 fixes it) - M291 issue, https://forum.duet3d.com/topic/8381/m291-s2-does-not-block-macro-execution/5 - In laser mode allow M3 instead of S to control laser power? (wait for feedback, not as simple as it looked) @@ -255,15 +266,16 @@ Done in 2.02 release: - Danny's G1->G0 request? [added IntermediatePositionsReachable function] - Warm up time not always displayed in 2.02 - For PanelDue, send heater data for the first heater in each tool, https://forum.duet3d.com/topic/8458/hide-unused-heater-channels-paneldue-5/4 -- Investigate 12864 display heater fault warning, https://forum.duet3d.com/topic/7718/12864-display-current-tool-temperatures/6 -- Generalised Cartesian axes; need to return bitmap of 'axes' involved for stall detect homing, see Platform::Stopped -- Deffered allocation of DMs: don't create DMs for nonlocal drives, pass #steps to CAN interface instead -- Remove the DM array -- Filament monitor to use time since end of last nonprinting extruder move -- DAA to handle requested accel/decl > max +- Deferred allocation of DMs: don't create DMs for nonlocal drives, pass #steps to CAN interface instead - Reports that DueX5 endstops stop working after a while, https://forum.duet3d.com/topic/8284/firmware-2-02-released/9 - I2C error recovery? -- Test babystepping with the deferred DM allocation +- Pressure advance issue? https://forum.duet3d.com/topic/8672/extruder-motors-skip-steps-with-pressure-advance-enabled/3 +- After pausing a print, if Cancel is pressed, cancel initial heating first like M108 does +- 4-tower delta kinematics +- Bug: M997 S1 sent from USB keeps returning M105 status reports while the wifi firmware is flashing +- Test with Duet 3 + +Look at icon generation, https://forum.duet3d.com/topic/8177/icon-generation/7 2.03 planned: - Stop print after a short to ground report? https://forum.duet3d.com/topic/8239/duet-maestro-short-to-ground/10 diff --git a/src/Display/Menu.cpp b/src/Display/Menu.cpp index 0479266e..ea88a15f 100644 --- a/src/Display/Menu.cpp +++ b/src/Display/Menu.cpp @@ -358,14 +358,12 @@ const char *Menu::ParseMenuLine(char * const commandWord) { const char *const acText = AppendString(text); MenuItem * const pNewItem = new TextMenuItem(row, column, width, alignment, fontNumber, xVis, acText); - pNewItem->UpdateWidth(lcd); AddItem(pNewItem, false); column += pNewItem->GetWidth() + 1; } else if (StringEqualsIgnoreCase(commandWord, "image") && fname != nullptr) { ImageMenuItem * const pNewItem = new ImageMenuItem(row, column, xVis, fname); - pNewItem->UpdateWidth(lcd); AddItem(pNewItem, false); column += pNewItem->GetWidth() + 1; } @@ -375,7 +373,6 @@ const char *Menu::ParseMenuLine(char * const commandWord) const char * const actionString = AppendString(action); const char * const c_acFileString = AppendString(fname); ButtonMenuItem * const pNewItem = new ButtonMenuItem(row, column, width, fontNumber, xVis, textString, actionString, c_acFileString); - pNewItem->UpdateWidth(lcd); AddItem(pNewItem, true); column += pNewItem->GetWidth() + 1; } @@ -497,6 +494,7 @@ void Menu::Reload() void Menu::AddItem(MenuItem *item, bool isSelectable) { + item->UpdateWidthAndHeight(lcd); MenuItem::AppendToList((isSelectable) ? &selectableItems : &unSelectableItems, item); } @@ -689,6 +687,18 @@ void Menu::Refresh() void Menu::DrawAll() { + // First erase any displayed items that should now be invisible + for (MenuItem *item = selectableItems; item != nullptr; item = item->GetNext()) + { + item->EraseIfInvisible(lcd, rowOffset); + } + + for (MenuItem *item = unSelectableItems; item != nullptr; item = item->GetNext()) + { + item->EraseIfInvisible(lcd, rowOffset); + } + + // Now draw items const PixelNumber rightMargin = NumCols - currentMargin; for (MenuItem *item = selectableItems; item != nullptr; item = item->GetNext()) { diff --git a/src/Display/MenuItem.cpp b/src/Display/MenuItem.cpp index e3d83665..c725066b 100644 --- a/src/Display/MenuItem.cpp +++ b/src/Display/MenuItem.cpp @@ -20,7 +20,7 @@ #include "PrintMonitor.h" MenuItem::MenuItem(PixelNumber r, PixelNumber c, PixelNumber w, Alignment a, FontNumber fn, Visibility vis) - : row(r), column(c), width(w), align(a), fontNumber(fn), visCase(vis), itemChanged(true), highlighted(false), next(nullptr) + : row(r), column(c), width(w), height(0), align(a), fontNumber(fn), visCase(vis), itemChanged(true), highlighted(false), drawn(false), next(nullptr) { } @@ -88,6 +88,16 @@ bool MenuItem::IsVisible() const } } +// Erase this item if it is drawn but should not be visible +void MenuItem::EraseIfInvisible(Lcd7920& lcd, PixelNumber tOffset) +{ + if (drawn && !IsVisible()) + { + lcd.Clear(row - tOffset, column, row + height, column + width); + drawn = false; + } +} + TextMenuItem::TextMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, Alignment a, FontNumber fn, Visibility vis, const char* t) : MenuItem(r, c, w, a, fn, vis), text(t) { @@ -105,10 +115,11 @@ void TextMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, P { PrintAligned(lcd, tOffset, rightMargin); itemChanged = false; + drawn = true; } } -void TextMenuItem::UpdateWidth(Lcd7920& lcd) +void TextMenuItem::UpdateWidthAndHeight(Lcd7920& lcd) { if (width == 0) { @@ -119,6 +130,11 @@ void TextMenuItem::UpdateWidth(Lcd7920& lcd) lcd.print(text); width = lcd.GetColumn(); } + if (height == 0) + { + lcd.SetFont(fontNumber); + height = lcd.GetFontHeight(); + } } ButtonMenuItem::ButtonMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, FontNumber fn, Visibility vis, const char* t, const char* cmd, char const* acFile) @@ -140,10 +156,11 @@ void ButtonMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, highlighted = highlight; PrintAligned(lcd, tOffset, rightMargin); itemChanged = false; + drawn = true; } } -void ButtonMenuItem::UpdateWidth(Lcd7920& lcd) +void ButtonMenuItem::UpdateWidthAndHeight(Lcd7920& lcd) { if (width == 0) { @@ -154,6 +171,11 @@ void ButtonMenuItem::UpdateWidth(Lcd7920& lcd) CorePrint(lcd); width = lcd.GetColumn(); } + if (height == 0) + { + lcd.SetFont(fontNumber); + height = lcd.GetFontHeight(); + } } // TODO WS1: if we overflow the command or directory string, we should probably offer a return value that tells the caller to do nothing... @@ -325,6 +347,7 @@ void ValueMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, highlighted = highlight; PrintAligned(lcd, tOffset, rightMargin); itemChanged = false; + drawn = true; } } @@ -334,6 +357,16 @@ bool ValueMenuItem::Select(const StringRef& cmd) return false; } +void ValueMenuItem::UpdateWidthAndHeight(Lcd7920& lcd) +{ + // The width is always set for a ValueMenuItem so we just need to determine the height + if (height == 0) + { + lcd.SetFont(fontNumber); + height = lcd.GetFontHeight(); + } +} + PixelNumber ValueMenuItem::GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const { // TODO @@ -663,6 +696,7 @@ void FilesMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, m_oMS->AbandonFindNext(); // release the mutex, there may be more files that we don't have room to display itemChanged = false; + drawn = true; highlighted = highlight; } } @@ -813,6 +847,16 @@ bool FilesMenuItem::Select(const StringRef& cmd) return false; } +void FilesMenuItem::UpdateWidthAndHeight(Lcd7920& lcd) +{ + // The width is always set for a FilesMenuItem so we just need to determine the height + if (height == 0) + { + lcd.SetFont(fontNumber); + height = lcd.GetFontHeight() * numDisplayLines; + } +} + PixelNumber FilesMenuItem::GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const { // TODO @@ -859,21 +903,23 @@ void ImageMenuItem::Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, fs->Close(); } itemChanged = false; + drawn = true; highlighted = highlight; } } -void ImageMenuItem::UpdateWidth(Lcd7920& lcd) +void ImageMenuItem::UpdateWidthAndHeight(Lcd7920& lcd) { - if (width == 0) + if (width == 0 || height == 0) { FileStore * const fs = reprap.GetPlatform().OpenFile(MENU_DIR, fileName.c_str(), OpenMode::read); if (fs != nullptr) { - uint8_t w; - fs->Read(w); // read the number of columns + uint8_t w[2]; + fs->Read(w, 2); // read the number of columns fs->Close(); - width = w; + width = w[0]; + height = w[1]; } } } diff --git a/src/Display/MenuItem.h b/src/Display/MenuItem.h index 1ca16c7c..7bba6fac 100644 --- a/src/Display/MenuItem.h +++ b/src/Display/MenuItem.h @@ -49,8 +49,11 @@ public: // 'clicks' is the number of encoder clicks to adjust by, or 0 if the button was pushed. virtual bool Adjust(int clicks) { return true; } - // If the width was specified as zero, update it with the actual width - virtual void UpdateWidth(Lcd7920& lcd) { } + // If the width was specified as zero, update it with the actual width. Also update the height. + virtual void UpdateWidthAndHeight(Lcd7920& lcd) = 0; + + // DC: I don't know what this one is for, the person who wrote it didn't document it + virtual PixelNumber GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const { return 0; } virtual ~MenuItem() { } @@ -59,10 +62,12 @@ public: void SetChanged() { itemChanged = true; } bool IsVisible() const; - virtual PixelNumber GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const { return 0; } + // Erase this item if it is drawn but should not be visible + void EraseIfInvisible(Lcd7920& lcd, PixelNumber tOffset); // Return the width of this item in pixels PixelNumber GetWidth() const { return width; } + PixelNumber GetHeight() const { return height; } static void AppendToList(MenuItem **root, MenuItem *item); @@ -77,13 +82,14 @@ protected: void PrintAligned(Lcd7920& lcd, PixelNumber tOffset, PixelNumber rightMargin); const PixelNumber row, column; - PixelNumber width; + PixelNumber width, height; const Alignment align; const FontNumber fontNumber; const Visibility visCase; bool itemChanged; bool highlighted; + bool drawn; private: MenuItem *next; @@ -97,7 +103,7 @@ public: TextMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, Alignment a, FontNumber fn, Visibility vis, const char *t); void Draw(Lcd7920& lcd, PixelNumber maxWidth, bool highlight, PixelNumber tOffset) override; - void UpdateWidth(Lcd7920& lcd) override; + void UpdateWidthAndHeight(Lcd7920& lcd) override; protected: void CorePrint(Lcd7920& lcd) override; @@ -114,7 +120,7 @@ public: ButtonMenuItem(PixelNumber r, PixelNumber c, PixelNumber w, FontNumber fn, Visibility vis, const char *t, const char *cmd, const char *acFile); void Draw(Lcd7920& lcd, PixelNumber maxWidth, bool highlight, PixelNumber tOffset) override; - void UpdateWidth(Lcd7920& lcd) override; + void UpdateWidthAndHeight(Lcd7920& lcd) override; bool Select(const StringRef& cmd) override; PixelNumber GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const override; @@ -139,6 +145,7 @@ public: bool Select(const StringRef& cmd) override; bool CanAdjust() override { return true; } bool Adjust(int clicks) override; + void UpdateWidthAndHeight(Lcd7920& lcd) override; PixelNumber GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const override; @@ -175,6 +182,7 @@ public: void Enter(bool bForwardDirection) override; int Advance(int nCounts) override; bool Select(const StringRef& cmd) override; + void UpdateWidthAndHeight(Lcd7920& lcd) override; PixelNumber GetVisibilityRowOffset(PixelNumber tCurrentOffset, PixelNumber fontHeight) const override; @@ -215,7 +223,7 @@ public: ImageMenuItem(PixelNumber r, PixelNumber c, Visibility vis, const char *pFileName); void Draw(Lcd7920& lcd, PixelNumber rightMargin, bool highlight, PixelNumber tOffset) override; - void UpdateWidth(Lcd7920& lcd) override; + void UpdateWidthAndHeight(Lcd7920& lcd) override; private: String<MaxFilenameLength> fileName; diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index ac49c6a5..0d9c5c25 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -948,7 +948,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) break; } - g30zHeightError = moveBuffer.coords[Z_AXIS] - platform.ZProbeStopHeight(); + g30zHeightError = moveBuffer.coords[Z_AXIS] - platform.GetZProbeStopHeight(); g30zHeightErrorSum += g30zHeightError; } @@ -1215,7 +1215,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) float m[MaxAxes]; reprap.GetMove().GetCurrentMachinePosition(m, false); // get height without bed compensation g30zStoppedHeight = m[Z_AXIS] - g30HValue; // save for later - g30zHeightError = g30zStoppedHeight - platform.ZProbeStopHeight(); + g30zHeightError = g30zStoppedHeight - platform.GetZProbeStopHeight(); g30zHeightErrorSum += g30zHeightError; } } @@ -1223,9 +1223,9 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) if (g30ProbePointIndex < 0) // if no P parameter { // Simple G30 probing move - if (g30SValue == -1 || g30SValue == -2) + if (g30SValue == -1 || g30SValue == -2 || g30SValue == -3) { - // G30 S-1 command taps once and reports the height, S-2 sets the tool offset to the negative of the current height + // G30 S-1 command taps once and reports the height, S-2 sets the tool offset to the negative of the current height, S-3 sets the Z probe trigger height gb.SetState(GCodeState::probingAtPoint7); // special state for reporting the stopped height at the end if (platform.GetZProbeType() != ZProbeType::none && !probeIsDeployed) { @@ -1237,7 +1237,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) if (tapsDone == 1 && !hadProbingError) { // Reset the Z axis origin according to the height error so that we can move back up to the dive height - moveBuffer.coords[Z_AXIS] = platform.ZProbeStopHeight(); + moveBuffer.coords[Z_AXIS] = platform.GetZProbeStopHeight(); reprap.GetMove().SetNewPosition(moveBuffer.coords, false); reprap.GetMove().SetZeroHeightError(moveBuffer.coords); g30zHeightError = 0; // there is no longer any height error from this probe @@ -1343,8 +1343,16 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) break; case GCodeState::probingAtPoint7: - // Here when we have finished executing G30 S-1 or S-2 including retracting the probe if necessary - if (g30SValue == -2) + // Here when we have finished executing G30 S-1 or S-2 or S-3 including retracting the probe if necessary + if (g30SValue == -3) + { + // Adjust the Z probe trigger height to the stop height + ZProbe zp = platform.GetCurrentZProbeParameters(); + zp.triggerHeight = g30zStoppedHeight; + platform.SetZProbeParameters(platform.GetZProbeType(), zp); + reply.printf("Z probe trigger height set to %.3f mm", (double)g30zStoppedHeight); + } + else if (g30SValue == -2) { // Adjust the Z offset of the current tool to account for the height error Tool * const tool = reprap.GetCurrentTool(); @@ -3143,7 +3151,7 @@ GCodeResult GCodes::DoHome(GCodeBuffer& gb, const StringRef& reply) // We already own the movement lock before this is called. GCodeResult GCodes::ExecuteG30(GCodeBuffer& gb, const StringRef& reply) { - g30SValue = (gb.Seen('S')) ? gb.GetIValue() : -3; // S-3 is equivalent to having no S parameter + g30SValue = (gb.Seen('S')) ? gb.GetIValue() : -4; // S-4 or lower is equivalent to having no S parameter if (g30SValue == -2 && reprap.GetCurrentTool() == nullptr) { reply.copy("G30 S-2 commanded with no tool selected"); @@ -3750,30 +3758,33 @@ bool GCodes::ChangeMicrostepping(size_t drive, unsigned int microsteps, bool int } // Set the speeds of fans mapped for the current tool to lastDefaultFanSpeed -void GCodes::SetMappedFanSpeed() +void GCodes::SetMappedFanSpeed(float f) { - if (reprap.GetCurrentTool() == nullptr) + lastDefaultFanSpeed = f; + const Tool * const ct = reprap.GetCurrentTool(); + if (ct == nullptr) { - platform.SetFanValue(0, lastDefaultFanSpeed); + platform.SetFanValue(0, f); } else { - const uint32_t fanMap = reprap.GetCurrentTool()->GetFanMapping(); + const uint32_t fanMap = ct->GetFanMapping(); for (size_t i = 0; i < NUM_FANS; ++i) { if (IsBitSet(fanMap, i)) { - platform.SetFanValue(i, lastDefaultFanSpeed); + platform.SetFanValue(i, f); } } } } -// Set the mapped fan speed -void GCodes::SetMappedFanSpeed(float f) +// Return true if this fan number is currently being used as a print cooling fan +bool GCodes::IsMappedFan(unsigned int fanNumber) { - lastDefaultFanSpeed = f; - SetMappedFanSpeed(); + const Tool * const ct = reprap.GetCurrentTool(); + return (ct == nullptr) ? fanNumber == 0 + : IsBitSet(ct->GetFanMapping(), fanNumber); } // Save the speeds of all fans diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h index 3e5859dc..dceb4b3c 100644 --- a/src/GCodes/GCodes.h +++ b/src/GCodes/GCodes.h @@ -223,7 +223,7 @@ public: #endif float GetMappedFanSpeed() const { return lastDefaultFanSpeed; } // Get the mapped fan speed - void SetMappedFanSpeed(float f); // Set the mapped fan speed + void SetMappedFanSpeed(float f); // Set the speeds of fans mapped for the current tool void HandleReply(GCodeBuffer& gb, GCodeResult rslt, const char *reply); // Handle G-Code replies void EmergencyStop(); // Cancel everything bool GetLastPrintingHeight(float& height) const; // Get the height in user coordinates of the last printing move @@ -350,7 +350,7 @@ private: bool DoEmergencyPause(); // Do an emergency pause following loss of power or a motor stall #endif - void SetMappedFanSpeed(); // Set the speeds of fans mapped for the current tool + bool IsMappedFan(unsigned int fanNumber); // Return true if this fan number is currently being used as a print cooling fan void SaveFanSpeeds(); // Save the speeds of all fans GCodeResult SetOrReportZProbe(GCodeBuffer& gb, const StringRef &reply); // Handle M558 diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index ea306a21..39a433e0 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -1243,6 +1243,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) if (seenFanNum) { platform.SetFanValue(fanNum, f); + if (IsMappedFan(fanNum)) + { + lastDefaultFanSpeed = f; + } } else { @@ -1262,16 +1266,14 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) } else { - lastDefaultFanSpeed = pausedDefaultFanSpeed; - SetMappedFanSpeed(); + SetMappedFanSpeed(pausedDefaultFanSpeed); } } } break; case 107: // Fan off - deprecated - lastDefaultFanSpeed = 0.0; - SetMappedFanSpeed(); + SetMappedFanSpeed(0.0); break; case 108: // Cancel waiting for temperature @@ -3641,7 +3643,6 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) const KinematicsType oldK = move.GetKinematics().GetKinematicsType(); // get the current kinematics type so we can tell whether it changed bool seen = false; - bool changedToCartesian = false; if (gb.Seen('S')) { // Switch to the correct CoreXY mode @@ -3650,7 +3651,6 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) { case 0: move.SetKinematics(KinematicsType::cartesian); - changedToCartesian = true; break; case 1: @@ -3671,14 +3671,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) if (result == GCodeResult::ok) { - if (!changedToCartesian) // don't ask the kinematics to process M667 if we switched to Cartesian mode + if (gb.Seen('X') || gb.Seen('Y') || gb.Seen('Z')) { - bool error = false; - if (move.GetKinematics().Configure(667, gb, reply, error)) - { - seen = true; - } - result = GetGCodeResultFromError(error); + reply.copy("M667 XYZ parameters are no longer supported, use M669 matrix parameters instead"); + result = GCodeResult::error; } if (seen) diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp index 607365ac..ccd5e698 100644 --- a/src/Movement/DDA.cpp +++ b/src/Movement/DDA.cpp @@ -221,11 +221,11 @@ void DDA::DebugPrintAll() const DebugPrint(); for (DriveMovement* dm = activeDMs; dm != nullptr; dm = dm->nextDM) { - dm->DebugPrint(isDeltaMovement); + dm->DebugPrint(); } for (DriveMovement* dm = completedDMs; dm != nullptr; dm = dm->nextDM) { - dm->DebugPrint(isDeltaMovement); + dm->DebugPrint(); } } @@ -441,9 +441,9 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping) // We use the Cartesian motion system to implement these moves, so the feed rate will be interpreted in Cartesian coordinates. // This is wrong, we want the feed rate to apply to the drive that is moving the farthest. float maxDistance = 0.0; - for (size_t axis = 0; axis < DELTA_AXES; ++axis) + for (size_t axis = 0; axis < numTotalAxes; ++axis) { - if (normalisedDirectionVector[axis] > maxDistance) + if (k.GetMotionType(axis) == MotionType::segmentFreeDelta && normalisedDirectionVector[axis] > maxDistance) { maxDistance = normalisedDirectionVector[axis]; } @@ -462,7 +462,7 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping) // for diagonal moves. On other architectures, this is not OK and any movement in the XY plane should be limited on other ways. if (doMotorMapping) { - k.LimitSpeedAndAcceleration(*this, normalisedDirectionVector, numVisibleAxes); // give the kinematics the chance to further restrict the speed and acceleration + k.LimitSpeedAndAcceleration(*this, normalisedDirectionVector, numVisibleAxes, continuousRotationShortcut); // give the kinematics the chance to further restrict the speed and acceleration } // 7. Calculate the provisional accelerate and decelerate distances and the top speed @@ -741,6 +741,7 @@ LA_DEBUG; } // Try to push babystepping earlier in the move queue, returning the amount we pushed +//TODO this won't work for CoreXZ, rotary delta, Kappa, or SCARA with Z crosstalk float DDA::AdvanceBabyStepping(float amount) { DDA *cdda = this; @@ -771,9 +772,12 @@ float DDA::AdvanceBabyStepping(float amount) cdda->endCoordinates[Z_AXIS] += babySteppingDone; if (cdda->isDeltaMovement) { - for (size_t tower = 0; tower < DELTA_AXES; ++tower) + for (size_t axis = 0; axis < reprap.GetGCodes().GetTotalAxes(); ++axis) { - cdda->endPoint[tower] += (int32_t)(babySteppingDone * reprap.GetPlatform().DriveStepsPerUnit(tower)); + if (reprap.GetMove().GetKinematics().GetMotionType(axis) == MotionType::segmentFreeDelta) + { + cdda->endPoint[axis] += (int32_t)(babySteppingDone * reprap.GetPlatform().DriveStepsPerUnit(axis)); + } } } else @@ -960,34 +964,47 @@ inline void DDA::AdjustAcceleration() { // Try to reduce the acceleration/deceleration of the move to cancel ringing const float idealPeriod = reprap.GetMove().GetDRCperiod(); - const float accTime = (topSpeed - startSpeed)/acceleration; - const bool adjustAcceleration = - (accTime < idealPeriod && ((prev->state != DDAState::frozen && prev->state != DDAState::executing) || !prev->IsAccelerationMove())); - float proposedAcceleration, proposedAccelDistance; - if (adjustAcceleration) - { - proposedAcceleration = (topSpeed - startSpeed)/idealPeriod; - proposedAccelDistance = (fsquare(topSpeed) - fsquare(startSpeed))/(2 * proposedAcceleration); - } - else - { - proposedAcceleration = acceleration; - proposedAccelDistance = accelDistance; - } - const float decelTime = (topSpeed - endSpeed)/deceleration; - const float adjustDeceleration = - (decelTime < idealPeriod && (next->state != DDAState::provisional || !next->IsDecelerationMove())); - float proposedDeceleration, proposedDecelDistance; - if (adjustDeceleration) + float proposedAcceleration = acceleration, proposedAccelDistance = accelDistance; + bool adjustAcceleration = false; + if ((prev->state != DDAState::frozen && prev->state != DDAState::executing) || !prev->IsAccelerationMove()) { - proposedDeceleration = (topSpeed - endSpeed)/idealPeriod; - proposedDecelDistance = (fsquare(topSpeed) - fsquare(endSpeed))/(2 * proposedDeceleration); + const float accelTime = (topSpeed - startSpeed)/acceleration; + if (accelTime < idealPeriod) + { + proposedAcceleration = (topSpeed - startSpeed)/idealPeriod; + adjustAcceleration = true; + } + else if (accelTime < idealPeriod * 2) + { + proposedAcceleration = (topSpeed - startSpeed)/(idealPeriod * 2); + adjustAcceleration = true; + } + if (adjustAcceleration) + { + proposedAccelDistance = (fsquare(topSpeed) - fsquare(startSpeed))/(2 * proposedAcceleration); + } } - else + + float proposedDeceleration = deceleration, proposedDecelDistance = decelDistance; + bool adjustDeceleration = false; + if (next->state != DDAState::provisional || !next->IsDecelerationMove()) { - proposedDeceleration = deceleration; - proposedDecelDistance = decelDistance; + const float decelTime = (topSpeed - endSpeed)/deceleration; + if (decelTime < idealPeriod) + { + proposedDeceleration = (topSpeed - endSpeed)/idealPeriod; + adjustDeceleration = true; + } + else if (decelTime < idealPeriod * 2) + { + proposedDeceleration = (topSpeed - endSpeed)/(idealPeriod * 2); + adjustDeceleration = true; + } + if (adjustDeceleration) + { + proposedDecelDistance = (fsquare(topSpeed) - fsquare(endSpeed))/(2 * proposedDeceleration); + } } if (adjustAcceleration || adjustDeceleration) @@ -1111,8 +1128,6 @@ void DDA::Prepare(uint8_t simMode, float extrusionPending[]) params.zMovement = GetEndCoordinate(Z_AXIS, false) - prev->GetEndCoordinate(Z_AXIS, false); #endif params.dparams = static_cast<const LinearDeltaKinematics*>(&(reprap.GetMove().GetKinematics())); - params.diagonalSquared = params.dparams->GetDiagonalSquared(); - params.a2b2D2 = params.a2plusb2 * params.diagonalSquared; } // Convert the accelerate/decelerate distances to times @@ -1184,9 +1199,9 @@ void DDA::Prepare(uint8_t simMode, float extrusionPending[]) } } } - else if (isDeltaMovement && drive < DELTA_AXES) + else if (isDeltaMovement && reprap.GetMove().GetKinematics().GetMotionType(drive) == MotionType::segmentFreeDelta) { - // On a delta we need to allocate a DM for all three towers even if there is no net movement + // On a delta we need to allocate a DM for all towers even if there is no net movement DriveMovement* const pdm = DriveMovement::Allocate(drive, DMState::moving); const int32_t delta = endPoint[drive] - prev->endPoint[drive]; pdm->totalSteps = labs(delta); @@ -1778,7 +1793,7 @@ bool DDA::Step() activeDMs = dm; // remove the chain from the list while (dmToInsert != dm) // note that both of these may be nullptr { - const bool hasMoreSteps = (isDeltaMovement && dmToInsert->drive < DELTA_AXES) + const bool hasMoreSteps = (isDeltaMovement && dmToInsert->isDelta) ? dmToInsert->CalcNextStepTimeDelta(*this, true) : dmToInsert->CalcNextStepTimeCartesian(*this, true); DriveMovement * const nextToInsert = dmToInsert->nextDM; @@ -1945,7 +1960,7 @@ void DDA::ReduceHomingSpeed() DriveMovement* const pdm = FindDM(drive); if (pdm != nullptr && pdm->state == DMState::moving) { - pdm->ReduceSpeed(*this, ProbingSpeedReductionFactor); + pdm->ReduceSpeed(ProbingSpeedReductionFactor); } } } diff --git a/src/Movement/DriveMovement.cpp b/src/Movement/DriveMovement.cpp index ff38432f..222930ff 100644 --- a/src/Movement/DriveMovement.cpp +++ b/src/Movement/DriveMovement.cpp @@ -91,6 +91,7 @@ bool DriveMovement::PrepareCartesianAxis(const DDA& dda, const PrepParams& param nextStepTime = 0; stepInterval = 999999; // initialise to a large value so that we will calculate the time for just one step stepsTillRecalc = 0; // so that we don't skip the calculation + isDelta = false; return CalcNextStepTimeCartesian(dda, false); } @@ -101,7 +102,7 @@ bool DriveMovement::PrepareDeltaAxis(const DDA& dda, const PrepParams& params) const float A = params.initialX - params.dparams->GetTowerX(drive); const float B = params.initialY - params.dparams->GetTowerY(drive); const float aAplusbB = A * dda.directionVector[X_AXIS] + B * dda.directionVector[Y_AXIS]; - const float dSquaredMinusAsquaredMinusBsquared = params.diagonalSquared - fsquare(A) - fsquare(B); + const float dSquaredMinusAsquaredMinusBsquared = params.dparams->GetDiagonalSquared(drive) - fsquare(A) - fsquare(B); const float h0MinusZ0 = sqrtf(dSquaredMinusAsquaredMinusBsquared); mp.delta.hmz0sK = roundS32(h0MinusZ0 * stepsPerMm * DriveMovement::K2); mp.delta.minusAaPlusBbTimesKs = -roundS32(aAplusbB * stepsPerMm * DriveMovement::K2); @@ -120,7 +121,7 @@ bool DriveMovement::PrepareDeltaAxis(const DDA& dda, const PrepParams& params) { // The distance to reversal is the solution to a quadratic equation. One root corresponds to the carriages being below the bed, // the other root corresponds to the carriages being above the bed. - const float drev = ((dda.directionVector[Z_AXIS] * sqrtf(params.a2b2D2 - fsquare(A * dda.directionVector[Y_AXIS] - B * dda.directionVector[X_AXIS]))) + const float drev = ((dda.directionVector[Z_AXIS] * sqrtf(params.a2plusb2 * params.dparams->GetDiagonalSquared(drive) - fsquare(A * dda.directionVector[Y_AXIS] - B * dda.directionVector[X_AXIS]))) - aAplusbB)/params.a2plusb2; if (drev > 0.0 && drev < dda.totalDistance) // if the reversal point is within range { @@ -181,6 +182,7 @@ bool DriveMovement::PrepareDeltaAxis(const DDA& dda, const PrepParams& params) nextStepTime = 0; stepInterval = 999999; // initialise to a large value so that we will calculate the time for just one step stepsTillRecalc = 0; // so that we don't skip the calculation + isDelta = true; return CalcNextStepTimeDelta(dda, false); } @@ -309,10 +311,11 @@ bool DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params, fl nextStepTime = 0; stepInterval = 999999; // initialise to a large value so that we will calculate the time for just one step stepsTillRecalc = 0; // so that we don't skip the calculation + isDelta = false; return CalcNextStepTimeCartesian(dda, false); } -void DriveMovement::DebugPrint(bool isDeltaMovement) const +void DriveMovement::DebugPrint() const { const size_t totalAxes = reprap.GetGCodes().GetTotalAxes(); char c = (drive < totalAxes) ? reprap.GetGCodes().GetAxisLetters()[drive] : (char)('0' + (drive - totalAxes)); @@ -323,7 +326,7 @@ void DriveMovement::DebugPrint(bool isDeltaMovement) const c, (state == DMState::stepError) ? " ERR:" : ":", (direction) ? 'F' : 'B', totalSteps, nextStep, reverseStartStep, stepInterval, twoDistanceToStopTimesCsquaredDivD); - if (isDeltaMovement && drive < DELTA_AXES) + if (isDelta) { debugPrintf("hmz0sK=%" PRIi32 " minusAaPlusBbTimesKs=%" PRIi32 " dSquaredMinusAsquaredMinusBsquared=%" PRId64 "\n" "2c2mmsda=%" PRIu64 "2c2mmsdd=%" PRIu64 " asdsk=%" PRIu32 " dsdsk=%" PRIu32 " mmstcdts=%" PRIu32 "\n", @@ -573,9 +576,9 @@ pre(nextStep < totalSteps; stepsTillRecalc == 0) } // Reduce the speed of this movement. Called to reduce the homing speed when we detect we are near the endstop for a drive. -void DriveMovement::ReduceSpeed(const DDA& dda, uint32_t inverseSpeedFactor) +void DriveMovement::ReduceSpeed(uint32_t inverseSpeedFactor) { - if (dda.isDeltaMovement && drive < DELTA_AXES) + if (isDelta) { // Force the linear motion phase mp.delta.accelStopDsK = 0; diff --git a/src/Movement/DriveMovement.h b/src/Movement/DriveMovement.h index 10a29761..8ab22dd4 100644 --- a/src/Movement/DriveMovement.h +++ b/src/Movement/DriveMovement.h @@ -111,9 +111,7 @@ struct PrepParams float zMovement; #endif const LinearDeltaKinematics *dparams; - float diagonalSquared; float a2plusb2; // sum of the squares of the X and Y movement fractions - float a2b2D2; }; enum class DMState : uint8_t @@ -136,8 +134,8 @@ public: bool PrepareCartesianAxis(const DDA& dda, const PrepParams& params) __attribute__ ((hot)); bool PrepareDeltaAxis(const DDA& dda, const PrepParams& params) __attribute__ ((hot)); bool PrepareExtruder(const DDA& dda, const PrepParams& params, float& extrusionPending, float speedChange, bool doCompensation) __attribute__ ((hot)); - void ReduceSpeed(const DDA& dda, uint32_t inverseSpeedFactor); - void DebugPrint(bool isDeltaMovement) const; + void ReduceSpeed(uint32_t inverseSpeedFactor); + void DebugPrint() const; int32_t GetNetStepsLeft() const; int32_t GetNetStepsTaken() const; @@ -172,7 +170,8 @@ private: uint8_t drive; // the drive that this DM controls uint8_t microstepShift : 4, // log2 of the microstepping factor (for when we use dynamic microstepping adjustment) direction : 1, // true=forwards, false=backwards - fullCurrent : 1; // true if the drivers are set to the full current, false if they are set to the standstill current + fullCurrent : 1, // true if the drivers are set to the full current, false if they are set to the standstill current + isDelta : 1; // true if this DM uses segment-free delta kinematics uint8_t stepsTillRecalc; // how soon we need to recalculate uint32_t totalSteps; // total number of steps for this move diff --git a/src/Movement/Kinematics/CoreKinematics.cpp b/src/Movement/Kinematics/CoreKinematics.cpp index 1be02488..6e6c5fe0 100644 --- a/src/Movement/Kinematics/CoreKinematics.cpp +++ b/src/Movement/Kinematics/CoreKinematics.cpp @@ -68,10 +68,12 @@ void CoreKinematics::Recalc() for (size_t axis = 0; axis < MaxAxes; ++axis) { + motorsUsedByAxis[axis] = 0; for (size_t motor = 0; motor < MaxAxes; ++motor) { if (inverseMatrix(axis, motor) != 0.0) { + SetBit(motorsUsedByAxis[axis], motor); if (motor < firstMotor[axis]) { firstMotor[axis] = motor; @@ -236,16 +238,6 @@ bool CoreKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const String bool seen; switch (mCode) { - case 667: - seen = gb.Seen('S'); - if (gb.Seen('X') || gb.Seen('Y') || gb.Seen('Z')) - { - seen = true; - error = true; - reply.copy("M667 XYZ parameters are no longer supported. Please use M669 matrix paramerters instead."); - } - break; - case 669: { seen = gb.Seen('K'); @@ -388,7 +380,7 @@ void CoreKinematics::OnHomingSwitchTriggered(size_t axis, bool highEnd, const fl // Limit the speed and acceleration of a move to values that the mechanics can handle // The speeds along individual Cartesian axes have already been limited before this is called, so we need only be concerned with shared motors -void CoreKinematics::LimitSpeedAndAcceleration(DDA& dda, const float* normalisedDirectionVector, size_t numVisibleAxes) const +void CoreKinematics::LimitSpeedAndAcceleration(DDA& dda, const float* normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const { // For each shared motor, calculate how much of the total move it contributes float motorMovements[MaxAxes]; @@ -426,4 +418,11 @@ void CoreKinematics::LimitSpeedAndAcceleration(DDA& dda, const float* normalised } } +// Return a bitmap of the motors that are involved in homing a particular axis or tower. Used for implementing stall detection endstops. +// Usually it is just the corresponding motor (hence this default implementation), but CoreXY and similar kinematics move multiple motors to home an individual axis. +AxesBitmap CoreKinematics::MotorsUsedToHomeAxis(size_t axis) const +{ + return motorsUsedByAxis[axis]; +} + // End diff --git a/src/Movement/Kinematics/CoreKinematics.h b/src/Movement/Kinematics/CoreKinematics.h index 1eccf5df..6d1c2778 100644 --- a/src/Movement/Kinematics/CoreKinematics.h +++ b/src/Movement/Kinematics/CoreKinematics.h @@ -24,14 +24,19 @@ public: bool QueryTerminateHomingMove(size_t axis) const override; void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; HomingMode GetHomingMode() const override { return homeCartesianAxes; } - void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const override; + void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const override; + AxesBitmap MotorsUsedToHomeAxis(size_t axis) const override; private: void Recalc(); // recalculate internal variables following a configuration change bool HasSharedMotor(size_t axis) const; // return true if the axis doesn't have a single dedicated motor + // Primary parameters FixedMatrix<float, MaxAxes, MaxAxes> inverseMatrix; // maps coordinates to motor positions + + // Derived parameters FixedMatrix<float, MaxAxes, MaxAxes> forwardMatrix; // maps motor positions to coordinates + AxesBitmap motorsUsedByAxis[MaxAxes]; // which motors are used to move each axis AxesBitmap axesWithSharedMotors; // bitmap of axes without exclusive control of the corresponding motor, or that use other motors bool modified; // true if matrix has been altered uint8_t firstMotor[MaxAxes], lastMotor[MaxAxes]; // first and last motor used by each axis diff --git a/src/Movement/Kinematics/HangprinterKinematics.cpp b/src/Movement/Kinematics/HangprinterKinematics.cpp index d92c071b..f727c33f 100644 --- a/src/Movement/Kinematics/HangprinterKinematics.cpp +++ b/src/Movement/Kinematics/HangprinterKinematics.cpp @@ -269,7 +269,7 @@ AxesBitmap HangprinterKinematics::MustBeHomedAxes(AxesBitmap axesMoving, bool di // Limit the speed and acceleration of a move to values that the mechanics can handle. // The speeds in Cartesian space have already been limited. -void HangprinterKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const +void HangprinterKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const { // Limit the speed in the XY plane to the lower of the X and Y maximum speeds, and similarly for the acceleration const float xyFactor = sqrtf(fsquare(normalisedDirectionVector[X_AXIS]) + fsquare(normalisedDirectionVector[Y_AXIS])); diff --git a/src/Movement/Kinematics/HangprinterKinematics.h b/src/Movement/Kinematics/HangprinterKinematics.h index a524e3b1..a9a43b18 100644 --- a/src/Movement/Kinematics/HangprinterKinematics.h +++ b/src/Movement/Kinematics/HangprinterKinematics.h @@ -37,7 +37,7 @@ public: bool QueryTerminateHomingMove(size_t axis) const override; void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; bool WriteResumeSettings(FileStore *f) const override; - void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const override; + void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const override; private: static constexpr float DefaultSegmentsPerSecond = 100.0; diff --git a/src/Movement/Kinematics/Kinematics.cpp b/src/Movement/Kinematics/Kinematics.cpp index 0835222a..f0e7dbbc 100644 --- a/src/Movement/Kinematics/Kinematics.cpp +++ b/src/Movement/Kinematics/Kinematics.cpp @@ -130,11 +130,17 @@ AxesBitmap Kinematics::GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alread return homeFirst & ~alreadyHomed; } +// Return a bitmap of the motors that are involved in homing a particular axis or tower. Used for implementing stall detection endstops. +// Usually it is just the corresponding motor (hence this default implementation), but CoreXY and similar kinematics move multiple motors to home an individual axis. +AxesBitmap Kinematics::MotorsUsedToHomeAxis(size_t axis) const +{ + return MakeBitmap<AxesBitmap>(axis); +} + /*static*/ Kinematics *Kinematics::Create(KinematicsType k) { switch (k) { - case KinematicsType::linearDeltaPlusZ: // not implemented yet default: return nullptr; diff --git a/src/Movement/Kinematics/Kinematics.h b/src/Movement/Kinematics/Kinematics.h index 56f05318..d04d1579 100644 --- a/src/Movement/Kinematics/Kinematics.h +++ b/src/Movement/Kinematics/Kinematics.h @@ -29,7 +29,7 @@ enum class KinematicsType : uint8_t hangprinter, polar, coreXYUV, - linearDeltaPlusZ, // reserved for @sga, see https://forum.duet3d.com/topic/5775/aditional-carterian-z-axis-on-delta-printer + reserved, // reserved for @sga, see https://forum.duet3d.com/topic/5775/aditional-carterian-z-axis-on-delta-printer rotaryDelta, // not yet implemented markForged, @@ -166,11 +166,15 @@ public: // Limit the speed and acceleration of a move to values that the mechanics can handle. // The speeds along individual Cartesian axes have already been limited before this is called. - virtual void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const = 0; + virtual void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const = 0; // Return true if the specified axis is a continuous rotation axis virtual bool IsContinuousRotationAxis(size_t axis) const { return false; } + // Return a bitmap of the motors that are involved in homing a particular axis or tower. Used for implementing stall detection endstops. + // Usually it is just the corresponding motor, but CoreXY and similar kinematics move multiple motors to home an individual axis. + virtual AxesBitmap MotorsUsedToHomeAxis(size_t axis) const; + // Override this virtual destructor if your constructor allocates any dynamic memory virtual ~Kinematics() { } diff --git a/src/Movement/Kinematics/LinearDeltaKinematics.cpp b/src/Movement/Kinematics/LinearDeltaKinematics.cpp index a0b9b5cf..dab6612e 100644 --- a/src/Movement/Kinematics/LinearDeltaKinematics.cpp +++ b/src/Movement/Kinematics/LinearDeltaKinematics.cpp @@ -13,7 +13,7 @@ #include "GCodes/GCodeBuffer.h" -LinearDeltaKinematics::LinearDeltaKinematics() : Kinematics(KinematicsType::linearDelta, -1.0, 0.0, true) +LinearDeltaKinematics::LinearDeltaKinematics() : Kinematics(KinematicsType::linearDelta, -1.0, 0.0, true), numTowers(UsualNumTowers) { Init(); } @@ -26,17 +26,21 @@ const char *LinearDeltaKinematics::GetName(bool forStatusReport) const void LinearDeltaKinematics::Init() { - diagonal = DefaultDiagonal; radius = DefaultDeltaRadius; xTilt = yTilt = 0.0; printRadius = DefaultPrintRadius; homedHeight = DefaultDeltaHomedHeight; doneAutoCalibration = false; - for (size_t axis = 0; axis < DELTA_AXES; ++axis) + for (size_t axis = 0; axis < UsualNumTowers; ++axis) { angleCorrections[axis] = 0.0; endstopAdjustments[axis] = 0.0; + } + + for (size_t axis = 0; axis < MaxTowers; ++axis) + { + diagonals[axis] = DefaultDiagonal; towerX[axis] = towerY[axis] = 0.0; } @@ -63,13 +67,24 @@ void LinearDeltaKinematics::Recalc() coreFc = fsquare(towerX[DELTA_C_AXIS]) + fsquare(towerY[DELTA_C_AXIS]); Q = (Xca * Yab - Xab * Yca) * 2; Q2 = fsquare(Q); - D2 = fsquare(diagonal); - // Calculate the base carriage height when the printer is homed, i.e. the carriages are at the endstops less the corrections - const float tempHeight = diagonal; // any sensible height will do here - float machinePos[DELTA_AXES]; - ForwardTransform(tempHeight, tempHeight, tempHeight, machinePos); - homedCarriageHeight = homedHeight + tempHeight - machinePos[Z_AXIS]; + // Calculate the base carriage heights when the printer is homed, i.e. the carriages are at the endstops, and the always-reachable height + alwaysReachableHeight = homedHeight; + for (size_t axis = 0; axis < numTowers; ++axis) + { + D2[axis] = fsquare(diagonals[axis]); + homedCarriageHeights[axis] = homedHeight + sqrtf(D2[axis] - fsquare(radius)); + if (axis < UsualNumTowers) + { + homedCarriageHeights[axis] += endstopAdjustments[axis]; + const float heightLimit = homedCarriageHeights[axis] - diagonals[axis]; + if (heightLimit < alwaysReachableHeight) + { + alwaysReachableHeight = heightLimit; + } + } + } + printRadiusSquared = fsquare(printRadius); } @@ -81,15 +96,14 @@ void LinearDeltaKinematics::NormaliseEndstopAdjustments() endstopAdjustments[DELTA_B_AXIS] -= eav; endstopAdjustments[DELTA_C_AXIS] -= eav; homedHeight += eav; - homedCarriageHeight += eav; // no need for a full recalc, this is sufficient } // Calculate the motor position for a single tower from a Cartesian coordinate. float LinearDeltaKinematics::Transform(const float machinePos[], size_t axis) const { - if (axis < DELTA_AXES) + if (axis < numTowers) { - return sqrtf(D2 - fsquare(machinePos[X_AXIS] - towerX[axis]) - fsquare(machinePos[Y_AXIS] - towerY[axis])) + return sqrtf(D2[axis] - fsquare(machinePos[X_AXIS] - towerX[axis]) - fsquare(machinePos[Y_AXIS] - towerY[axis])) + machinePos[Z_AXIS] + (machinePos[X_AXIS] * xTilt) + (machinePos[Y_AXIS] * yTilt); @@ -101,7 +115,7 @@ float LinearDeltaKinematics::Transform(const float machinePos[], size_t axis) co } // Calculate the Cartesian coordinates from the motor coordinates -void LinearDeltaKinematics::ForwardTransform(float Ha, float Hb, float Hc, float machinePos[DELTA_AXES]) const +void LinearDeltaKinematics::ForwardTransform(float Ha, float Hb, float Hc, float machinePos[XYZ_AXES]) const { const float Fa = coreFa + fsquare(Ha); const float Fb = coreFb + fsquare(Hb); @@ -117,7 +131,7 @@ void LinearDeltaKinematics::ForwardTransform(float Ha, float Hb, float Hc, float const float A = U2 + R2 + Q2; const float minusHalfB = S * U + P * R + Ha * Q2 + towerX[DELTA_A_AXIS] * U * Q - towerY[DELTA_A_AXIS] * R * Q; - const float C = fsquare(S + towerX[DELTA_A_AXIS] * Q) + fsquare(P - towerY[DELTA_A_AXIS] * Q) + (fsquare(Ha) - D2) * Q2; + const float C = fsquare(S + towerX[DELTA_A_AXIS] * Q) + fsquare(P - towerY[DELTA_A_AXIS] * Q) + (fsquare(Ha) - D2[DELTA_A_AXIS]) * Q2; const float z = (minusHalfB - sqrtf(fsquare(minusHalfB) - A * C)) / A; machinePos[X_AXIS] = (U * z - S) / Q; @@ -129,7 +143,7 @@ void LinearDeltaKinematics::ForwardTransform(float Ha, float Hb, float Hc, float bool LinearDeltaKinematics::CartesianToMotorSteps(const float machinePos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, int32_t motorPos[], bool isCoordinated) const { bool ok = true; - for (size_t axis = 0; axis < min<size_t>(numVisibleAxes, DELTA_AXES); ++axis) + for (size_t axis = 0; axis < min<size_t>(numVisibleAxes, numTowers); ++axis) { const float pos = Transform(machinePos, axis); if (isnan(pos) || isinf(pos)) @@ -143,7 +157,7 @@ bool LinearDeltaKinematics::CartesianToMotorSteps(const float machinePos[], cons } // Transform any additional axes linearly - for (size_t axis = DELTA_AXES; axis < numVisibleAxes; ++axis) + for (size_t axis = numTowers; axis < numVisibleAxes; ++axis) { motorPos[axis] = lrintf(machinePos[axis] * stepsPerMm[axis]); } @@ -156,7 +170,7 @@ void LinearDeltaKinematics::MotorStepsToCartesian(const int32_t motorPos[], cons ForwardTransform(motorPos[DELTA_A_AXIS]/stepsPerMm[DELTA_A_AXIS], motorPos[DELTA_B_AXIS]/stepsPerMm[DELTA_B_AXIS], motorPos[DELTA_C_AXIS]/stepsPerMm[DELTA_C_AXIS], machinePos); // Convert any additional axes linearly - for (size_t drive = DELTA_AXES; drive < numVisibleAxes; ++drive) + for (size_t drive = numTowers; drive < numVisibleAxes; ++drive) { machinePos[drive] = motorPos[drive]/stepsPerMm[drive]; } @@ -192,14 +206,17 @@ bool LinearDeltaKinematics::LimitPosition(float coords[], size_t numVisibleAxes, coords[Z_AXIS] = reprap.GetPlatform().AxisMinimum(Z_AXIS); limited = true; } - else + else if (coords[Z_AXIS] > alwaysReachableHeight) { - // Determine the maximum reachable height at this radius, in the worst case when the head is on a radius to a tower - const float maxHeight = homedCarriageHeight - sqrtf(D2 - fsquare(radius - sqrtf(diagonalSquared))); - if (coords[Z_AXIS] > maxHeight) + // Determine the maximum reachable height at this position + for (size_t tower = 0; tower < UsualNumTowers; ++tower) { - coords[Z_AXIS] = maxHeight; - limited = true; + const float carriageHeight = Transform(coords, tower); + if (carriageHeight > homedCarriageHeights[tower]) + { + coords[Z_AXIS] -= (carriageHeight - homedCarriageHeights[tower]); + limited = true; + } } } } @@ -246,13 +263,13 @@ bool LinearDeltaKinematics::DoAutoCalibration(size_t numFactors, const RandomPro //uint32_t startTime = reprap.GetPlatform()->GetInterruptClocks(); // Transform the probing points to motor endpoints and store them in a matrix, so that we can do multiple iterations using the same data - FixedMatrix<floatc_t, MaxCalibrationPoints, DELTA_AXES> probeMotorPositions; + FixedMatrix<floatc_t, MaxCalibrationPoints, UsualNumTowers> probeMotorPositions; floatc_t corrections[MaxCalibrationPoints]; floatc_t initialSumOfSquares = 0.0; for (size_t i = 0; i < numPoints; ++i) { corrections[i] = 0.0; - float machinePos[DELTA_AXES]; + float machinePos[XYZ_AXES]; const floatc_t zp = reprap.GetMove().GetProbeCoordinates(i, machinePos[X_AXIS], machinePos[Y_AXIS], probePoints.PointWasCorrected(i)); machinePos[Z_AXIS] = 0.0; @@ -351,22 +368,22 @@ bool LinearDeltaKinematics::DoAutoCalibration(size_t numFactors, const RandomPro } // Save the old homed carriage heights before we change the endstop corrections - float homedCarriageHeights[DELTA_AXES]; - for (size_t drive = 0; drive < DELTA_AXES; ++drive) + float oldHomedCarriageHeights[UsualNumTowers]; + for (size_t drive = 0; drive < UsualNumTowers; ++drive) { - homedCarriageHeights[drive] = GetHomedCarriageHeight(drive); + oldHomedCarriageHeights[drive] = GetHomedCarriageHeight(drive); } Adjust(numFactors, solution); // adjust the delta parameters - float heightAdjust[DELTA_AXES]; - for (size_t drive = 0; drive < DELTA_AXES; ++drive) + float heightAdjust[UsualNumTowers]; + for (size_t drive = 0; drive < UsualNumTowers; ++drive) { - heightAdjust[drive] = GetHomedCarriageHeight(drive) - homedCarriageHeights[drive]; + heightAdjust[drive] = GetHomedCarriageHeight(drive) - oldHomedCarriageHeights[drive]; } // Adjust the motor endpoints to allow for the change to endstop adjustments - reprap.GetMove().AdjustMotorPositions(heightAdjust, DELTA_AXES); + reprap.GetMove().AdjustMotorPositions(heightAdjust, UsualNumTowers); // Calculate the expected probe heights using the new parameters { @@ -374,11 +391,11 @@ bool LinearDeltaKinematics::DoAutoCalibration(size_t numFactors, const RandomPro floatc_t sumOfSquares = 0.0; for (size_t i = 0; i < numPoints; ++i) { - for (size_t axis = 0; axis < DELTA_AXES; ++axis) + for (size_t axis = 0; axis < UsualNumTowers; ++axis) { probeMotorPositions(i, axis) += solution[axis]; } - float newPosition[DELTA_AXES]; + float newPosition[XYZ_AXES]; ForwardTransform(probeMotorPositions(i, DELTA_A_AXIS), probeMotorPositions(i, DELTA_B_AXIS), probeMotorPositions(i, DELTA_C_AXIS), newPosition); corrections[i] = newPosition[Z_AXIS]; expectedResiduals[i] = probePoints.GetZHeight(i) + newPosition[Z_AXIS]; @@ -422,7 +439,7 @@ bool LinearDeltaKinematics::DoAutoCalibration(size_t numFactors, const RandomPro // Return the type of motion computation needed by an axis MotionType LinearDeltaKinematics::GetMotionType(size_t axis) const { - return (axis < DELTA_AXES) ? MotionType::segmentFreeDelta : MotionType::linear; + return (axis < numTowers) ? MotionType::segmentFreeDelta : MotionType::linear; } // Compute the derivative of height with respect to a parameter at the specified motor endpoints. @@ -467,8 +484,11 @@ floatc_t LinearDeltaKinematics::ComputeDerivative(unsigned int deriv, float ha, break; case 6: - hiParams.diagonal += perturb; - loParams.diagonal -= perturb; + for (size_t tower = 0; tower < UsualNumTowers; ++tower) + { + hiParams.diagonals[tower] += perturb; + loParams.diagonals[tower] -= perturb; + } hiParams.Recalc(); loParams.Recalc(); break; @@ -479,7 +499,7 @@ floatc_t LinearDeltaKinematics::ComputeDerivative(unsigned int deriv, float ha, break; } - float newPos[DELTA_AXES]; + float newPos[XYZ_AXES]; hiParams.ForwardTransform((deriv == 0) ? ha + perturb : ha, (deriv == 1) ? hb + perturb : hb, (deriv == 2) ? hc + perturb : hc, newPos); if (deriv == 7) { @@ -508,8 +528,6 @@ floatc_t LinearDeltaKinematics::ComputeDerivative(unsigned int deriv, float ha, // Y tilt adjustment void LinearDeltaKinematics::Adjust(size_t numFactors, const floatc_t v[]) { - const float oldCarriageHeightA = GetHomedCarriageHeight(DELTA_A_AXIS); // save for later - // Update endstop adjustments endstopAdjustments[DELTA_A_AXIS] += (float)v[0]; endstopAdjustments[DELTA_B_AXIS] += (float)v[1]; @@ -527,7 +545,10 @@ void LinearDeltaKinematics::Adjust(size_t numFactors, const floatc_t v[]) if (numFactors == 7 || numFactors == 9) { - diagonal += (float)v[6]; + for (size_t tower = 0; tower < UsualNumTowers; ++tower) + { + diagonals[tower] += (float)v[6]; + } } if (numFactors == 8) @@ -541,15 +562,9 @@ void LinearDeltaKinematics::Adjust(size_t numFactors, const floatc_t v[]) yTilt += (float)v[8]/printRadius; } } - - Recalc(); } - // Adjusting the diagonal and the tower positions affects the homed carriage height. - // We need to adjust homedHeight to allow for this, to get the change that was requested in the endstop corrections. - const float heightError = GetHomedCarriageHeight(DELTA_A_AXIS) - oldCarriageHeightA - (float)v[0]; - homedHeight -= heightError; - homedCarriageHeight -= heightError; + Recalc(); // Note: if we adjusted the X and Y tilts, and there are any endstop adjustments, then the homed position won't be exactly in the centre // and changing the tilt will therefore affect the homed height. We ignore this for now. If it is ever significant, a second autocalibration @@ -559,9 +574,16 @@ void LinearDeltaKinematics::Adjust(size_t numFactors, const floatc_t v[]) // Print all the parameters for debugging void LinearDeltaKinematics::PrintParameters(const StringRef& reply) const { - reply.printf("Stops X%.3f Y%.3f Z%.3f height %.3f diagonal %.3f radius %.3f xcorr %.2f ycorr %.2f zcorr %.2f xtilt %.3f%% ytilt %.3f%%\n", - (double)endstopAdjustments[DELTA_A_AXIS], (double)endstopAdjustments[DELTA_B_AXIS], (double)endstopAdjustments[DELTA_C_AXIS], (double)homedHeight, (double)diagonal, (double)radius, - (double)angleCorrections[DELTA_A_AXIS], (double)angleCorrections[DELTA_B_AXIS], (double)angleCorrections[DELTA_C_AXIS], (double)(xTilt * 100.0), (double)(yTilt * 100.0)); + reply.printf("Stops X%.3f Y%.3f Z%.3f height %.3f diagonals", + (double)endstopAdjustments[DELTA_A_AXIS], (double)endstopAdjustments[DELTA_B_AXIS], (double)endstopAdjustments[DELTA_C_AXIS], (double)homedHeight); + for (size_t tower = 0; tower < numTowers; ++tower) + { + reply.catf("%c%.3f", (tower == 0) ? ' ' : ':', (double)diagonals[tower]); + } + reply.catf(" radius %.3f xcorr %.2f ycorr %.2f zcorr %.2f xtilt %.3f%% ytilt %.3f%%\n", + (double)radius, + (double)angleCorrections[DELTA_A_AXIS], (double)angleCorrections[DELTA_B_AXIS], (double)angleCorrections[DELTA_C_AXIS], + (double)(xTilt * 100.0), (double)(yTilt * 100.0)); } // Write the parameters that are set by auto calibration to a file, returning true if success @@ -571,8 +593,15 @@ bool LinearDeltaKinematics::WriteCalibrationParameters(FileStore *f) const if (ok) { String<ScratchStringLength> scratchString; - scratchString.printf("M665 L%.3f R%.3f H%.3f B%.1f X%.3f Y%.3f Z%.3f\n", - (double)diagonal, (double)radius, (double)homedHeight, (double)printRadius, (double)angleCorrections[DELTA_A_AXIS], (double)angleCorrections[DELTA_B_AXIS], (double)angleCorrections[DELTA_C_AXIS]); + scratchString.copy("M665 "); + for (size_t tower = 0; tower < numTowers; ++tower) + { + scratchString.catf("%c%.3f", (tower == 0) ? 'L' : ':', (double)diagonals[tower]); + } + + scratchString.catf(" R%.3f H%.3f B%.1f X%.3f Y%.3f Z%.3f\n", + (double)radius, (double)homedHeight, (double)printRadius, + (double)angleCorrections[DELTA_A_AXIS], (double)angleCorrections[DELTA_B_AXIS], (double)angleCorrections[DELTA_C_AXIS]); ok = f->Write(scratchString.c_str()); if (ok) { @@ -605,7 +634,18 @@ bool LinearDeltaKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const case 665: { bool seen = false; - gb.TryGetFValue('L', diagonal, seen); + if (gb.Seen('L')) + { + seen = true; + size_t numValues = MaxAxes; + gb.GetFloatArray(diagonals, numValues, false); + while (numValues < 3) + { + diagonals[numValues++] = diagonals[0]; + } + numTowers = numValues; + } + gb.TryGetFValue('R', radius, seen); if (gb.Seen('B')) @@ -637,9 +677,14 @@ bool LinearDeltaKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const } else { - reply.printf("Diagonal %.3f, delta radius %.3f, homed height %.3f, bed radius %.1f" + reply.copy("Diagonals"); + for (size_t tower = 0; tower < numTowers; ++tower) + { + reply.catf("%c%.3f", (tower == 0) ? ' ' : ':', (double)diagonals[tower]); + } + reply.catf(", delta radius %.3f, homed height %.3f, bed radius %.1f" ", X %.3f" DEGREE_SYMBOL ", Y %.3f" DEGREE_SYMBOL ", Z %.3f" DEGREE_SYMBOL, - (double)diagonal, (double)radius, + (double)radius, (double)homedHeight, (double)printRadius, (double)angleCorrections[DELTA_A_AXIS], (double)angleCorrections[DELTA_B_AXIS], (double)angleCorrections[DELTA_C_AXIS]); } @@ -673,6 +718,41 @@ bool LinearDeltaKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const return seen; } + case 669: + { + // X and Y give the X and Y coordinates of the additional towers beyond the first three + // The correct number of L parameters must have been given in the M665 command first + size_t numX = 0, numY = 0; + if (gb.Seen('X')) + { + numX = MaxTowers - UsualNumTowers; + gb.GetFloatArray(towerX + UsualNumTowers, numX, false); + if (numX != numTowers - UsualNumTowers) + { + reply.copy("Wrong number of X values"); + error = true; + return true; + } + } + if (gb.Seen('Y')) + { + numY = MaxTowers - UsualNumTowers; + gb.GetFloatArray(towerY + UsualNumTowers, numY, false); + if (numY != numTowers - UsualNumTowers) + { + reply.copy("Wrong number of Y values"); + error = true; + return true; + } + } + if (numX != 0 || numY != 0) + { + Recalc(); // recalculate the homed carriage heights + return true; + } + return Kinematics::Configure(mCode, gb, reply, error); + } + default: return Kinematics::Configure(mCode, gb, reply, error); } @@ -707,7 +787,7 @@ AxesBitmap LinearDeltaKinematics::MustBeHomedAxes(AxesBitmap axesMoving, bool di AxesBitmap LinearDeltaKinematics::GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alreadyHomed, size_t numVisibleAxes, const StringRef& filename) const { // If homing X, Y or Z we must home all the towers - if ((toBeHomed & LowestNBits<AxesBitmap>(DELTA_AXES)) != 0) + if ((toBeHomed & LowestNBits<AxesBitmap>(XYZ_AXES)) != 0) { filename.copy("homedelta.g"); return 0; @@ -727,12 +807,11 @@ bool LinearDeltaKinematics::QueryTerminateHomingMove(size_t axis) const // Take the action needed to define the current position, normally by calling dda.SetDriveCoordinate() and return false. void LinearDeltaKinematics::OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const { - if (axis < DELTA_AXES) + if (axis < numTowers) { if (highEnd) { - const float hitPoint = GetHomedCarriageHeight(axis); - dda.SetDriveCoordinate(lrintf(hitPoint * stepsPerMm[axis]), axis); + dda.SetDriveCoordinate(lrintf(homedCarriageHeights[axis] * stepsPerMm[axis]), axis); } } else @@ -745,7 +824,7 @@ void LinearDeltaKinematics::OnHomingSwitchTriggered(size_t axis, bool highEnd, c // Limit the speed and acceleration of a move to values that the mechanics can handle. // The speeds in Cartesian space have already been limited. -void LinearDeltaKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const +void LinearDeltaKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const { // Limit the speed in the XY plane to the lower of the X and Y maximum speeds, and similarly for the acceleration const float xyFactor = sqrtf(fsquare(normalisedDirectionVector[X_AXIS]) + fsquare(normalisedDirectionVector[Y_AXIS])); diff --git a/src/Movement/Kinematics/LinearDeltaKinematics.h b/src/Movement/Kinematics/LinearDeltaKinematics.h index 99980317..4ea71815 100644 --- a/src/Movement/Kinematics/LinearDeltaKinematics.h +++ b/src/Movement/Kinematics/LinearDeltaKinematics.h @@ -11,8 +11,6 @@ #include "RepRapFirmware.h" #include "Kinematics.h" -constexpr size_t DELTA_AXES = 3; - // Class to hold the parameter for a delta machine. class LinearDeltaKinematics : public Kinematics { @@ -43,13 +41,13 @@ public: bool QueryTerminateHomingMove(size_t axis) const override; void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; bool WriteResumeSettings(FileStore *f) const override; - void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const override; + void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const override; // Public functions specific to this class - float GetDiagonalSquared() const { return D2; } + float GetDiagonalSquared(size_t tower) const { return D2[tower]; } float GetTowerX(size_t axis) const { return towerX[axis]; } float GetTowerY(size_t axis) const { return towerY[axis]; } - float GetHomedCarriageHeight(size_t axis) const { return homedCarriageHeight + endstopAdjustments[axis]; } + float GetHomedCarriageHeight(size_t axis) const { return homedCarriageHeights[axis] + endstopAdjustments[axis]; } float GetHomedHeight() const { return homedHeight; } private: @@ -57,12 +55,15 @@ private: void Recalc(); void NormaliseEndstopAdjustments(); // Make the average of the endstop adjustments zero float Transform(const float headPos[], size_t axis) const; // Calculate the motor position for a single tower from a Cartesian coordinate - void ForwardTransform(float Ha, float Hb, float Hc, float headPos[]) const; // Calculate the Cartesian position from the motor positions + void ForwardTransform(float Ha, float Hb, float Hc, float headPos[XYZ_AXES]) const; // Calculate the Cartesian position from the motor positions floatc_t ComputeDerivative(unsigned int deriv, float ha, float hb, float hc) const; // Compute the derivative of height with respect to a parameter at a set of motor endpoints void Adjust(size_t numFactors, const floatc_t v[]); // Perform 3-, 4-, 6- or 7-factor adjustment void PrintParameters(const StringRef& reply) const; // Print all the parameters for debugging + static constexpr size_t MaxTowers = 6; // maximum number of delta towers + static constexpr size_t UsualNumTowers = 3; // the usual number of towers, which are the ones we use for forward kinematics and the ones we calibrate + // Axis names used internally static constexpr size_t DELTA_A_AXIS = 0; static constexpr size_t DELTA_B_AXIS = 1; @@ -75,22 +76,25 @@ private: static constexpr float DefaultDeltaHomedHeight = 240.0; // Core parameters - float diagonal; // The diagonal rod length, all 3 are assumed to be the same length + size_t numTowers; + float diagonals[MaxTowers]; // The diagonal rod lengths float radius; // The nominal delta radius, before any fine tuning of tower positions - float angleCorrections[DELTA_AXES]; // Tower position corrections - float endstopAdjustments[DELTA_AXES]; // How much above or below the ideal position each endstop is + float angleCorrections[UsualNumTowers]; // Tower position corrections for the first 3 axes + float endstopAdjustments[UsualNumTowers]; // How much above or below the ideal position each endstop is float printRadius; float homedHeight; float xTilt, yTilt; // How much we need to raise Z for each unit of movement in the +X and +Y directions // Derived values - float towerX[DELTA_AXES]; // The X coordinate of each tower - float towerY[DELTA_AXES]; // The Y coordinate of each tower + float towerX[MaxTowers]; // The X coordinate of each tower + float towerY[MaxTowers]; // The Y coordinate of each tower float printRadiusSquared; - float homedCarriageHeight; + float homedCarriageHeights[MaxTowers]; float Xbc, Xca, Xab, Ybc, Yca, Yab; float coreFa, coreFb, coreFc; - float Q, Q2, D2; + float Q, Q2; + float D2[MaxTowers]; + float alwaysReachableHeight; bool doneAutoCalibration; // True if we have done auto calibration }; diff --git a/src/Movement/Kinematics/PolarKinematics.cpp b/src/Movement/Kinematics/PolarKinematics.cpp index 5f891edf..e250eda4 100644 --- a/src/Movement/Kinematics/PolarKinematics.cpp +++ b/src/Movement/Kinematics/PolarKinematics.cpp @@ -257,13 +257,29 @@ void PolarKinematics::OnHomingSwitchTriggered(size_t axis, bool highEnd, const f // Limit the speed and acceleration of a move to values that the mechanics can handle. // The speeds in Cartesian space have already been limited. -void PolarKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const +void PolarKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const { - const int32_t turntableMovement = labs(dda.DriveCoordinates()[1] - dda.GetPrevious()->DriveCoordinates()[1]); + int32_t turntableMovement = labs(dda.DriveCoordinates()[1] - dda.GetPrevious()->DriveCoordinates()[1]); if (turntableMovement != 0) { - const float stepRatio = dda.GetTotalDistance() * reprap.GetPlatform().DriveStepsPerUnit(1)/turntableMovement; - dda.LimitSpeedAndAcceleration(stepRatio * maxTurntableSpeed, stepRatio * maxTurntableAcceleration); + const float stepsPerDegree = reprap.GetPlatform().DriveStepsPerUnit(1); + if (continuousRotationShortcut) + { + const int32_t stepsPerRotation = lrintf(360.0 * stepsPerDegree); + if (turntableMovement > stepsPerRotation/2) + { + turntableMovement -= stepsPerRotation; + } + else if (turntableMovement < -stepsPerRotation/2) + { + turntableMovement += stepsPerRotation; + } + } + if (turntableMovement != 0) + { + const float stepRatio = dda.GetTotalDistance() * stepsPerDegree/abs(turntableMovement); + dda.LimitSpeedAndAcceleration(stepRatio * maxTurntableSpeed, stepRatio * maxTurntableAcceleration); + } } } diff --git a/src/Movement/Kinematics/PolarKinematics.h b/src/Movement/Kinematics/PolarKinematics.h index 6a020a4a..c4d13c31 100644 --- a/src/Movement/Kinematics/PolarKinematics.h +++ b/src/Movement/Kinematics/PolarKinematics.h @@ -30,7 +30,7 @@ public: AxesBitmap GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alreadyHomed, size_t numVisibleAxes, const StringRef& filename) const override; bool QueryTerminateHomingMove(size_t axis) const override; void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; - void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const override; + void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const override; bool IsContinuousRotationAxis(size_t axis) const override; private: diff --git a/src/Movement/Kinematics/RotaryDeltaKinematics.cpp b/src/Movement/Kinematics/RotaryDeltaKinematics.cpp index 2f25c521..ca274436 100644 --- a/src/Movement/Kinematics/RotaryDeltaKinematics.cpp +++ b/src/Movement/Kinematics/RotaryDeltaKinematics.cpp @@ -359,7 +359,7 @@ bool RotaryDeltaKinematics::WriteResumeSettings(FileStore *f) const // Limit the speed and acceleration of a move to values that the mechanics can handle. // The speeds in Cartesian space have already been limited. -void RotaryDeltaKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const +void RotaryDeltaKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const { // Limit the speed in the XY plane to the lower of the X and Y maximum speeds, and similarly for the acceleration const float xyFactor = sqrtf(fsquare(normalisedDirectionVector[X_AXIS]) + fsquare(normalisedDirectionVector[Y_AXIS])); diff --git a/src/Movement/Kinematics/RotaryDeltaKinematics.h b/src/Movement/Kinematics/RotaryDeltaKinematics.h index f735fc17..c149068f 100644 --- a/src/Movement/Kinematics/RotaryDeltaKinematics.h +++ b/src/Movement/Kinematics/RotaryDeltaKinematics.h @@ -37,7 +37,7 @@ public: bool QueryTerminateHomingMove(size_t axis) const override; void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; bool WriteResumeSettings(FileStore *f) const override; - void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const override; + void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const override; private: void Init(); diff --git a/src/Movement/Kinematics/ScaraKinematics.cpp b/src/Movement/Kinematics/ScaraKinematics.cpp index e0e60786..9f51d9b6 100644 --- a/src/Movement/Kinematics/ScaraKinematics.cpp +++ b/src/Movement/Kinematics/ScaraKinematics.cpp @@ -22,7 +22,7 @@ ScaraKinematics::ScaraKinematics() thetaLimits[1] = DefaultMaxTheta; psiLimits[0] = DefaultMinPsi; psiLimits[1] = DefaultMaxPsi; - crosstalk[0] = crosstalk[1] = crosstalk[2] = 0.0; + crosstalk[0] = crosstalk[1] = crosstalk[2] = requestedMinRadius = 0.0; Recalc(); } @@ -195,6 +195,7 @@ bool ScaraKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const Strin error = true; return true; } + gb.TryGetFValue('R', requestedMinRadius, seen); if (seen || seenNonGeometry) { @@ -438,7 +439,7 @@ void ScaraKinematics::OnHomingSwitchTriggered(size_t axis, bool highEnd, const f // Limit the speed and acceleration of a move to values that the mechanics can handle. // The speeds in Cartesian space have already been limited. -void ScaraKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const +void ScaraKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const { // For now we limit the speed in the XY plane to the lower of the X and Y maximum speeds, and similarly for the acceleration. // Limiting the angular rates of the arms would be better. @@ -465,8 +466,9 @@ void ScaraKinematics::Recalc() distalArmLengthSquared = fsquare(distalArmLength); twoPd = proximalArmLength * distalArmLength * 2; - minRadius = sqrtf(proximalArmLengthSquared + distalArmLengthSquared - - twoPd * max<float>(cosf(psiLimits[0] * DegreesToRadians), cosf(psiLimits[1] * DegreesToRadians))) * 1.005; + minRadius = max<float>(sqrtf(proximalArmLengthSquared + distalArmLengthSquared + - twoPd * max<float>(cosf(psiLimits[0] * DegreesToRadians), cosf(psiLimits[1] * DegreesToRadians))) * 1.005, + requestedMinRadius); // If the total angle range is greater than 360 degrees, we assume that it supports continuous rotation supportsContinuousRotation[0] = (thetaLimits[1] - thetaLimits[0] > 360.0); diff --git a/src/Movement/Kinematics/ScaraKinematics.h b/src/Movement/Kinematics/ScaraKinematics.h index f9cc5740..beef3971 100644 --- a/src/Movement/Kinematics/ScaraKinematics.h +++ b/src/Movement/Kinematics/ScaraKinematics.h @@ -42,7 +42,7 @@ public: AxesBitmap GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alreadyHomed, size_t numVisibleAxes, const StringRef& filename) const override; bool QueryTerminateHomingMove(size_t axis) const override; void OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const override; - void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes) const override; + void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const override; bool IsContinuousRotationAxis(size_t axis) const override; private: @@ -69,6 +69,7 @@ private: float crosstalk[3]; // proximal to distal, proximal to X and distal to Z crosstalk float xOffset; // where bed X=0 is relative to the proximal joint float yOffset; // where bed Y=0 is relative to the proximal joint + float requestedMinRadius; // requested minimum radius bool supportsContinuousRotation[2]; // true if the (proximal, distal) arms support continuous rotation // Derived parameters diff --git a/src/Platform.cpp b/src/Platform.cpp index 4182fe4d..c68a4ec0 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -747,7 +747,7 @@ int Platform::GetZProbeSecondaryValues(int& v1, int& v2) } // Get our best estimate of the Z probe temperature -float Platform::GetZProbeTemperature() +float Platform::GetZProbeTemperature() const { for (size_t i = 0; i < NumBedHeaters; i++) { @@ -765,7 +765,7 @@ float Platform::GetZProbeTemperature() return 25.0; // assume 25C if we can't read the bed temperature } -float Platform::ZProbeStopHeight() +float Platform::GetZProbeStopHeight() const { return GetCurrentZProbeParameters().GetStopHeight(GetZProbeTemperature()); } @@ -2684,17 +2684,17 @@ void Platform::UpdateConfiguredHeaters() } } -EndStopHit Platform::Stopped(size_t drive) const +EndStopHit Platform::Stopped(size_t axisOrExtruder) const { const size_t numAxes = reprap.GetGCodes().GetTotalAxes(); - if (drive < numAxes) + if (axisOrExtruder < numAxes) { - switch (endStopInputType[drive]) + switch (endStopInputType[axisOrExtruder]) { case EndStopInputType::zProbe: { const EndStopHit rslt = GetZProbeResult(); - return (rslt == EndStopHit::lowHit && endStopPos[drive] == EndStopPosition::highEndStop) + return (rslt == EndStopHit::lowHit && endStopPos[axisOrExtruder] == EndStopPosition::highEndStop) ? EndStopHit::highHit : rslt; } @@ -2702,65 +2702,40 @@ EndStopHit Platform::Stopped(size_t drive) const #if HAS_STALL_DETECT case EndStopInputType::motorStall: { - bool motorIsStalled; - switch (reprap.GetMove().GetKinematics().GetKinematicsType()) + bool motorIsStalled = false; + AxesBitmap motorsUsed = reprap.GetMove().GetKinematics().MotorsUsedToHomeAxis(axisOrExtruder); + for (size_t motor = 0; motorsUsed != 0; ++motor) { - case KinematicsType::coreXY: - // Both X and Y motors are involved in homing X or Y - motorIsStalled = (drive == X_AXIS || drive == Y_AXIS) - ? AnyAxisMotorStalled(X_AXIS) || AnyAxisMotorStalled(Y_AXIS) - : AnyAxisMotorStalled(drive); - break; - - case KinematicsType::coreXYU: - // Both X and Y motors are involved in homing X or Y, and both U and V motors are involved in homing U - motorIsStalled = (drive == X_AXIS || drive == Y_AXIS) - ? AnyAxisMotorStalled(X_AXIS) || AnyAxisMotorStalled(Y_AXIS) - : (drive == U_AXIS) - ? AnyAxisMotorStalled(U_AXIS) || AnyAxisMotorStalled(V_AXIS) - : AnyAxisMotorStalled(drive); - break; - - case KinematicsType::coreXYUV: - // Both X and Y motors are involved in homing X or Y, and both U and V motors are involved in homing U and V - motorIsStalled = (drive == X_AXIS || drive == Y_AXIS) - ? AnyAxisMotorStalled(X_AXIS) || AnyAxisMotorStalled(Y_AXIS) - : (drive == U_AXIS || drive == V_AXIS) - ? AnyAxisMotorStalled(U_AXIS) || AnyAxisMotorStalled(V_AXIS) - : AnyAxisMotorStalled(drive); - break; - - case KinematicsType::coreXZ: - // Both X and Z motors are involved in homing X or Z - motorIsStalled = (drive == X_AXIS || drive == Z_AXIS) - ? AnyAxisMotorStalled(X_AXIS) || AnyAxisMotorStalled(Z_AXIS) - : AnyAxisMotorStalled(drive); - break; - - default: - motorIsStalled = AnyAxisMotorStalled(drive); - break; + if (IsBitSet(motorsUsed, motor)) + { + if (AnyAxisMotorStalled(motor)) + { + motorIsStalled = true; + break; + } + ClearBit(motorsUsed, motor); + } } return (!motorIsStalled) ? EndStopHit::noStop - : (endStopPos[drive] == EndStopPosition::highEndStop) ? EndStopHit::highHit + : (endStopPos[axisOrExtruder] == EndStopPosition::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit; } break; #endif case EndStopInputType::activeLow: - if (drive < NumEndstops && endStopPins[drive] != NoPin) + if (axisOrExtruder < NumEndstops && endStopPins[axisOrExtruder] != NoPin) { - const bool b = IoPort::ReadPin(endStopPins[drive]); - return (b) ? EndStopHit::noStop : (endStopPos[drive] == EndStopPosition::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit; + const bool b = IoPort::ReadPin(endStopPins[axisOrExtruder]); + return (b) ? EndStopHit::noStop : (endStopPos[axisOrExtruder] == EndStopPosition::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit; } break; case EndStopInputType::activeHigh: - if (drive < NumEndstops && endStopPins[drive] != NoPin) + if (axisOrExtruder < NumEndstops && endStopPins[axisOrExtruder] != NoPin) { - const bool b = !IoPort::ReadPin(endStopPins[drive]); - return (b) ? EndStopHit::noStop : (endStopPos[drive] == EndStopPosition::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit; + const bool b = !IoPort::ReadPin(endStopPins[axisOrExtruder]); + return (b) ? EndStopHit::noStop : (endStopPos[axisOrExtruder] == EndStopPosition::highEndStop) ? EndStopHit::highHit : EndStopHit::lowHit; } break; @@ -2769,10 +2744,10 @@ EndStopHit Platform::Stopped(size_t drive) const } } #if HAS_STALL_DETECT - else if (drive < NumDirectDrivers) + else if (axisOrExtruder < NumDirectDrivers) { // Endstop is for an extruder drive, so use stall detection - return (ExtruderMotorStalled(drive - numAxes)) ? EndStopHit::highHit : EndStopHit::noStop; + return (ExtruderMotorStalled(axisOrExtruder - numAxes)) ? EndStopHit::highHit : EndStopHit::noStop; } #endif return EndStopHit::noStop; diff --git a/src/Platform.h b/src/Platform.h index 2f9aa7cf..817c3cdc 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -465,7 +465,7 @@ public: // Z probe void SetZProbeDefaults(); - float ZProbeStopHeight(); + float GetZProbeStopHeight() const; float GetZProbeDiveHeight() const; float GetZProbeStartingHeight(); float GetZProbeTravelSpeed() const; @@ -484,7 +484,7 @@ public: void SetZProbeModState(bool b) const; // Heat and temperature - float GetZProbeTemperature(); // Get our best estimate of the Z probe temperature + float GetZProbeTemperature() const; // Get our best estimate of the Z probe temperature volatile ThermistorAveragingFilter& GetAdcFilter(size_t channel) pre(channel < ARRAY_SIZE(adcFilters)) diff --git a/src/RepRap.cpp b/src/RepRap.cpp index 36a28934..3d532418 100644 --- a/src/RepRap.cpp +++ b/src/RepRap.cpp @@ -1075,8 +1075,8 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) const int8_t bedHeater = (NumBedHeaters > 0) ? heat->GetBedHeater(0) : -1; if (bedHeater != -1) { - response->catf("\"bed\":{\"current\":%.1f,\"active\":%.1f,\"state\":%d,\"heater\":%d},", - (double)heat->GetTemperature(bedHeater), (double)heat->GetActiveTemperature(bedHeater), + response->catf("\"bed\":{\"current\":%.1f,\"active\":%.1f,\"standby\":%.1f,\"state\":%d,\"heater\":%d},", + (double)heat->GetTemperature(bedHeater), (double)heat->GetActiveTemperature(bedHeater), (double)heat->GetStandbyTemperature(bedHeater), heat->GetStatus(bedHeater), bedHeater); } diff --git a/src/Version.h b/src/Version.h index ad7b125f..cf228222 100644 --- a/src/Version.h +++ b/src/Version.h @@ -20,7 +20,7 @@ #endif #ifndef DATE -# define DATE "2019-01-16b2" +# define DATE "2019-01-24b1" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman, printm3d" |