文章目录
- NXP MCUXPresso - cc1plus.exe: out of memory allocating 65536 bytes
- 概述
- 实验结论
- 补充
- END
NXP MCUXPresso - cc1plus.exe: out of memory allocating 65536 bytes
概述
在尝试迁移 openpnp - Smoothieware project 从gcc命令行 + MRI调试方式 到NXP MCUXpresso工程.
遇到了编译器错误 cc1plus.exe: out of memory allocating
错误后面的字节数, 根据代码实现的不同, 也可能是其他数字.
查到资料上说的原始资料 cc1plus.exe: out of memory allocating 65536 bytes
尝试对MCUXPresso的cc1plus.exe做修改.
我的环境为win10x64工作站版
bcdedit /set IncreaseUserVa 3072
先查一下, editbin在哪里?
我计算机上装了vs2022
进入命令行, 到达editbin的目录
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.35.32215\bin\Hostx86\arm>
看看MCUXPresso用的cc1plus在哪里? 还好, 就一个.
执行官方资料的第2步修改.
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.35.32215\bin\Hostx86\arm>
editbin /LARGEADDRESSAWARE "D:\nxp\MCUXpressoIDE_11.7.1_9221\ide\plugins\com.nxp.mcuxpresso.tools.win32_11.7.1.202301190959\tools\lib\gcc\arm-none-eabi\10.3.1\cc1plus.exe"
Microsoft (R) COFF/PE Editor Version 14.35.32215.0
Copyright (C) Microsoft Corporation. All rights reserved.
查看修改后的cc1plus
D:\nxp\MCUXpressoIDE_11.7.1_9221\ide\plugins\com.nxp.mcuxpresso.tools.win32_11.7.1.202301190959\tools\lib\gcc\arm-none-eabi\10.3.1>dumpbin -headers cc1plus.exe | more
Microsoft (R) COFF/PE Dumper Version 14.29.30148.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file cc1plus.exe
PE signature found
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (x86)
7 number of sections
0 time date stamp
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
32F characteristics
Relocations stripped
Executable
Line numbers stripped
Symbols stripped
Application can handle large (>2GB) addresses // 这里已经修改过来了.
32 bit word machine
Debug information stripped
OPTIONAL HEADER VALUES
10B magic # (PE32)
2.30 linker version
-- More --
再尝试编译迁移中的工程, cc1plus 内存不够的报错还有.
尝试关掉MCUXpresso, 再打开工程编译. 还是报错.
最后根据提示信息, 定位到 路径 /my_Smoothieware_best-for-pnp/src/src/modules/robot/Robot.cpp 编译不过.
cc1plus.exe: out of memory allocating 65536 bytes
Building file: ../src/mbed/src/cpp/Timeout.cpp
Finished building: ../src/mbed/src/cpp/Serial.cpp
Finished building: ../src/mbed/src/cpp/Stream.cpp
Invoking: MCU C++ Compiler
Invoking: MCU C++ Compiler
make[1]: *** [src/src/modules/robot/subdir.mk:30: src/src/modules/robot/Robot.o] Error 1
arm-none-eabi-c++ -DDEBUG -DMRI_INIT_PARAMETERS=\"MRI_UART_3\" -DWRITE_BUFFER_DISABLE=1 -DMRI_BREAK_ON_INIT=0 -DMRI_SEMIHOST_STDIO=0 -DSTACK_SIZE=1024 -DMRI_ENABLE=1 -DDEFAULT_SERIAL_BAUD_RATE=115200 -D__CODE_RED -D__NEWLIB__ -DCORE_M3 -DCPP_NO_HEAP -D__LPC17XX__ -I"D:\my_dev\my_local_git_prj\hardware\LS_openpnp_hardware\src\my_Smoothieware_best-for-pnp\my_Smoothieware_best-for-pnp\inc" -I"D:\my_dev\my_local_git_prj\hardware\LS_openpnp_hardware\src\my_Smoothieware_best-for-pnp\my_Smoothieware_best-for-pnp\src\src\libs" -I"D:\my_dev\my_local_git_prj\hardware\LS_openpnp_hardware\src\my_Smoothieware_best-for-pnp\my_Smoothieware_best-for-pnp\src\src" -I"D:\my_dev\my_local_git_prj\hardware\LS_openpnp_hardware\src\my_Smoothieware_best-for-pnp\my_Smoothieware_best-for-pnp\src\mbed\src" -O0 -fno-common -g3 -Wall -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -fno-rtti -fno-exceptions -fmerge-constants -fmacro-prefix-map="../src/mbed/src/cpp/"= -mcpu=cortex-m3 -mthumb -D__NEWLIB__ -fstack-usage -MMD -MP -MF"src/mbed/src/cpp/Ticker.d" -MT"src/mbed/src/cpp/Ticker.o" -MT"src/mbed/src/cpp/Ticker.d" -o "src/mbed/src/cpp/Ticker.o" "../src/mbed/src/cpp/Ticker.cpp"
make[1]: *** Waiting for unfinished jobs....
去查看src/src/modules/robot/subdir.mk
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../src/src/modules/robot/Block.cpp \
../src/src/modules/robot/BlockQueue.cpp \
../src/src/modules/robot/Conveyor.cpp \
../src/src/modules/robot/Planner.cpp \
../src/src/modules/robot/Robot.cpp
CPP_DEPS += \
./src/src/modules/robot/Block.d \
./src/src/modules/robot/BlockQueue.d \
./src/src/modules/robot/Conveyor.d \
./src/src/modules/robot/Planner.d \
./src/src/modules/robot/Robot.d
OBJS += \
./src/src/modules/robot/Block.o \
./src/src/modules/robot/BlockQueue.o \
./src/src/modules/robot/Conveyor.o \
./src/src/modules/robot/Planner.o \
./src/src/modules/robot/Robot.o
# Each subdirectory must supply rules for building sources it contributes
src/src/modules/robot/%.o: ../src/src/modules/robot/%.cpp src/src/modules/robot/subdir.mk
@echo 'Building file: $<'
@echo 'Invoking: MCU C++ Compiler'
arm-none-eabi-c++ -DDEBUG -DMRI_INIT_PARAMETERS=\"MRI_UART_3\" -DWRITE_BUFFER_DISABLE=1 -DMRI_BREAK_ON_INIT=0 -DMRI_SEMIHOST_STDIO=0 -DSTACK_SIZE=1024 -DMRI_ENABLE=1 -DDEFAULT_SERIAL_BAUD_RATE=115200 -D__CODE_RED -D__NEWLIB__ -DCORE_M3 -DCPP_NO_HEAP -D__LPC17XX__ -I"D:\my_dev\my_local_git_prj\hardware\LS_openpnp_hardware\src\my_Smoothieware_best-for-pnp\my_Smoothieware_best-for-pnp\inc" -I"D:\my_dev\my_local_git_prj\hardware\LS_openpnp_hardware\src\my_Smoothieware_best-for-pnp\my_Smoothieware_best-for-pnp\src\src\libs" -I"D:\my_dev\my_local_git_prj\hardware\LS_openpnp_hardware\src\my_Smoothieware_best-for-pnp\my_Smoothieware_best-for-pnp\src\src" -I"D:\my_dev\my_local_git_prj\hardware\LS_openpnp_hardware\src\my_Smoothieware_best-for-pnp\my_Smoothieware_best-for-pnp\src\mbed\src" -O0 -fno-common -g3 -Wall -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -fno-rtti -fno-exceptions -fmerge-constants -fmacro-prefix-map="$(<D)/"= -mcpu=cortex-m3 -mthumb -D__NEWLIB__ -fstack-usage -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
@echo 'Finished building: $<'
@echo ' '
clean: clean-src-2f-src-2f-modules-2f-robot
clean-src-2f-src-2f-modules-2f-robot:
-$(RM) ./src/src/modules/robot/Block.d ./src/src/modules/robot/Block.o ./src/src/modules/robot/BlockQueue.d ./src/src/modules/robot/BlockQueue.o ./src/src/modules/robot/Conveyor.d ./src/src/modules/robot/Conveyor.o ./src/src/modules/robot/Planner.d ./src/src/modules/robot/Planner.o ./src/src/modules/robot/Robot.d ./src/src/modules/robot/Robot.o
.PHONY: clean-src-2f-src-2f-modules-2f-robot
查看生成的.o, 发现robot.o没有生成出来.
尝试单独编译robot.cpp, 还是编译不过, 报错信息同样是cc1plus.exe …
12:02:10 **** Building Selected Files of configuration Debug for project my_Smoothieware_best-for-pnp ****
Info: Internal Builder is used for build
arm-none-eabi-c++ -DDEBUG "-DMRI_INIT_PARAMETERS=\\MRI_UART_3\\" -DWRITE_BUFFER_DISABLE=1 -DMRI_BREAK_ON_INIT=0 -DMRI_SEMIHOST_STDIO=0 -DSTACK_SIZE=1024 -DMRI_ENABLE=1 -DDEFAULT_SERIAL_BAUD_RATE=115200 -D__CODE_RED -D__NEWLIB__ -DCORE_M3 -DCPP_NO_HEAP -D__LPC17XX__ "-ID:\\my_dev\\my_local_git_prj\\hardware\\LS_openpnp_hardware\\src\\my_Smoothieware_best-for-pnp\\my_Smoothieware_best-for-pnp\\inc" "-ID:\\my_dev\\my_local_git_prj\\hardware\\LS_openpnp_hardware\\src\\my_Smoothieware_best-for-pnp\\my_Smoothieware_best-for-pnp\\src\\src\\libs" "-ID:\\my_dev\\my_local_git_prj\\hardware\\LS_openpnp_hardware\\src\\my_Smoothieware_best-for-pnp\\my_Smoothieware_best-for-pnp\\src\\src" "-ID:\\my_dev\\my_local_git_prj\\hardware\\LS_openpnp_hardware\\src\\my_Smoothieware_best-for-pnp\\my_Smoothieware_best-for-pnp\\src\\mbed\\src" -O0 -fno-common -g3 -Wall -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -fno-rtti -fno-exceptions -fmerge-constants -fmacro-prefix-map=$(<D)/= -mcpu=cortex-m3 -mthumb -D__NEWLIB__ -fstack-usage -o "src\\src\\modules\\robot\\Robot.o" "..\\src\\src\\modules\\robot\\Robot.cpp"
cc1plus.exe: out of memory allocating 65536 bytes
12:02:44 Build Finished. 0 errors, 0 warnings. (took 33s.373ms)
不知道cc1plus.exe内部哪里内存开小了. 找一下解决方法.
打开cc1plus.exe看了一下, 报错信息的提示引用处, 都是给了一个size, 如果分配失败, 就打印报错信息.
分配内存的函数调用点很多, 而且给的size各种各样的大小. 可以确定, 不是cc1plus.exe实现的问题.
是不是robot.cpp写的不合适?
从定位到的robot.cpp的实现上, 用排除法看看, 到底是哪里引起cc1plus报错.
将robot.cpp分为2个文件. robot_A.cpp, robot_B.cpp.
2个实现, 都包含同样的头内容.
然后用二分法, 将实现拆开. 尝试编译2个实现.
发现, 其中一个是能编译过的, 一个是编译不过的.
将实现函数向能编译过的.cpp转移. 直到定位到编译不过的函数实现为止.
最后确定, 是Robot::load_config()函数编译不过, 引起cc1plus.exe报错.
将Robot::load_config()函数从下到上开始注释(用2分法), 最后确定, 是函数尾部几行实现引起编译报错.
在类中, 新添了一个函数void Robot::load_config_next1(), 将报错函数引起报错的语句, 改为调用load_config_next1().
在load_config_next1()中, 将引起报错的多余实现丢进去.
再编译, 编译通过! 搞定:)
void Robot::load_config()
{
// Arm solutions are used to convert positions in millimeters into position in steps for each stepper motor.
// While for a cartesian arm solution, this is a simple multiplication, in other, less simple cases, there is some serious math to be done.
// To make adding those solution easier, they have their own, separate object.
// Here we read the config to find out which arm solution to use
if (this->arm_solution) delete this->arm_solution;
int solution_checksum = get_checksum(THEKERNEL->config->value(arm_solution_checksum)->by_default("cartesian")->as_string());
// Note checksums are not const expressions when in debug mode, so don't use switch
if(solution_checksum == hbot_checksum || solution_checksum == corexy_checksum) {
this->arm_solution = new HBotSolution(THEKERNEL->config);
} else if(solution_checksum == corexz_checksum) {
this->arm_solution = new CoreXZSolution(THEKERNEL->config);
} else if(solution_checksum == rostock_checksum || solution_checksum == kossel_checksum || solution_checksum == delta_checksum || solution_checksum == linear_delta_checksum) {
this->arm_solution = new LinearDeltaSolution(THEKERNEL->config);
} else if(solution_checksum == rotatable_cartesian_checksum) {
this->arm_solution = new RotatableCartesianSolution(THEKERNEL->config);
} else if(solution_checksum == rotary_delta_checksum) {
this->arm_solution = new RotaryDeltaSolution(THEKERNEL->config);
} else if(solution_checksum == morgan_checksum) {
this->arm_solution = new MorganSCARASolution(THEKERNEL->config);
} else if(solution_checksum == cartesian_checksum) {
this->arm_solution = new CartesianSolution(THEKERNEL->config);
} else {
this->arm_solution = new CartesianSolution(THEKERNEL->config);
}
// 以上可以编译过
this->feed_rate = THEKERNEL->config->value(default_feed_rate_checksum )->by_default( 100.0F)->as_number();
this->seek_rate = THEKERNEL->config->value(default_seek_rate_checksum )->by_default( 100.0F)->as_number();
this->mm_per_line_segment = THEKERNEL->config->value(mm_per_line_segment_checksum )->by_default( 0.0F)->as_number();
this->delta_segments_per_second = THEKERNEL->config->value(delta_segments_per_second_checksum )->by_default(0.0f )->as_number();
this->mm_per_arc_segment = THEKERNEL->config->value(mm_per_arc_segment_checksum )->by_default( 0.0f)->as_number();
this->mm_max_arc_error = THEKERNEL->config->value(mm_max_arc_error_checksum )->by_default( 0.01f)->as_number();
this->arc_correction = THEKERNEL->config->value(arc_correction_checksum )->by_default( 5 )->as_number();
// in mm/sec but specified in config as mm/min
this->max_speeds[X_AXIS] = THEKERNEL->config->value(x_axis_max_speed_checksum )->by_default(60000.0F)->as_number() / 60.0F;
this->max_speeds[Y_AXIS] = THEKERNEL->config->value(y_axis_max_speed_checksum )->by_default(60000.0F)->as_number() / 60.0F;
this->max_speeds[Z_AXIS] = THEKERNEL->config->value(z_axis_max_speed_checksum )->by_default( 300.0F)->as_number() / 60.0F;
this->max_speed = THEKERNEL->config->value(max_speed_checksum )->by_default( -60.0F)->as_number() / 60.0F;
this->segment_z_moves = THEKERNEL->config->value(segment_z_moves_checksum )->by_default(true)->as_bool();
this->save_g92 = THEKERNEL->config->value(save_g92_checksum )->by_default(false)->as_bool();
this->save_g54 = THEKERNEL->config->value(save_g54_checksum )->by_default(THEKERNEL->is_grbl_mode())->as_bool();
string g92 = THEKERNEL->config->value(set_g92_checksum )->by_default("")->as_string();
if(!g92.empty()) {
// optional setting for a fixed G92 offset
std::vector<float> t= parse_number_list(g92.c_str());
if(t.size() == 3) {
g92_offset[0] = t[0];
g92_offset[1] = t[1];
g92_offset[2] = t[2];
}
}
// 以上可以编译过
// default s value for laser
this->s_value = THEKERNEL->config->value(laser_module_default_power_checksum)->by_default(0.8F)->as_number();
// 以上编译过了
// default acceleration setting, can be overriden with newer per axis settings
this->default_acceleration= THEKERNEL->config->value(acceleration_checksum)->by_default(100.0F )->as_number(); // Acceleration is in mm/s^2
// make each motor
for (size_t a = 0; a < MAX_ROBOT_ACTUATORS; a++) {
Pin pins[3]; //step, dir, enable
for (size_t i = 0; i < 3; i++) {
pins[i].from_string(THEKERNEL->config->value(motor_checksums[a][i])->by_default("nc")->as_string())->as_output();
}
if(!pins[0].connected() || !pins[1].connected()) { // step and dir must be defined, but enable is optional
if(a <= Z_AXIS) {
THEKERNEL->streams->printf("FATAL: motor %c is not defined in config\n", 'X'+a);
n_motors= a; // we only have this number of motors
return;
}
break; // if any pin is not defined then the axis is not defined (and axis need to be defined in contiguous order)
}
StepperMotor *sm = new StepperMotor(pins[0], pins[1], pins[2]);
// register this motor (NB This must be 0,1,2) of the actuators array
uint8_t n= register_motor(sm);
if(n != a) {
// this is a fatal error
THEKERNEL->streams->printf("FATAL: motor %d does not match index %d\n", n, a);
return;
}
actuators[a]->change_steps_per_mm(THEKERNEL->config->value(motor_checksums[a][3])->by_default(a == 2 ? 2560.0F : 80.0F)->as_number());
actuators[a]->set_max_rate(THEKERNEL->config->value(motor_checksums[a][4])->by_default(30000.0F)->as_number()/60.0F); // it is in mm/min and converted to mm/sec
actuators[a]->set_acceleration(THEKERNEL->config->value(motor_checksums[a][5])->by_default(NAN)->as_number()); // mm/secs²
}
check_max_actuator_speeds(); // check the configs are sane
// if we have not specified a z acceleration see if the legacy config was set
if(isnan(actuators[Z_AXIS]->get_acceleration())) {
float acc= THEKERNEL->config->value(z_acceleration_checksum)->by_default(NAN)->as_number(); // disabled by default
if(!isnan(acc)) {
actuators[Z_AXIS]->set_acceleration(acc);
}
}
// initialise actuator positions to current cartesian position (X0 Y0 Z0)
// so the first move can be correct if homing is not performed
ActuatorCoordinates actuator_pos;
arm_solution->cartesian_to_actuator(machine_position, actuator_pos);
for (size_t i = X_AXIS; i <= Z_AXIS; i++) {
actuators[i]->change_last_milestone(actuator_pos[i]);
}
#if MAX_ROBOT_ACTUATORS > 3
// initialize any extra axis to machine position
for (size_t i = A_AXIS; i < n_motors; i++) {
actuators[i]->change_last_milestone(machine_position[i]);
}
#endif
// 以上编译过
//this->clearToolOffset(); // 这句原来就注释了
load_config_next1(); // 函数的size有限制(根据编译器而不同), 分成多个小函数搞定:)
}
void Robot::load_config_next1()
{
soft_endstop_enabled= THEKERNEL->config->value(soft_endstop_checksum, enable_checksum)->by_default(false)->as_bool();
soft_endstop_halt= THEKERNEL->config->value(soft_endstop_checksum, halt_checksum)->by_default(true)->as_bool();
soft_endstop_min[X_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, xmin_checksum)->by_default(NAN)->as_number();
soft_endstop_min[Y_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, ymin_checksum)->by_default(NAN)->as_number();
soft_endstop_min[Z_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, zmin_checksum)->by_default(NAN)->as_number();
soft_endstop_max[X_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, xmax_checksum)->by_default(NAN)->as_number();
soft_endstop_max[Y_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, ymax_checksum)->by_default(NAN)->as_number();
soft_endstop_max[Z_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, zmax_checksum)->by_default(NAN)->as_number();
}
实验结论
通过这次排错, 可以猜测到, 编译器对一个函数实现编译后的大小是有限制的, 具体是多少, 根据目标平台和编译器的实现而定.
函数太大就会引起报错.
同样的代码, 换用特定的编译器, 就能直接编译过. 但是换用另外一种IDE自带的编译器, 就可能报错.
Smoothieware作者在文档中还特意说了, 只能用他们命令行安装的工具链才能编译过, 如果用其他工具链, 可能有各种各样的编译问题.
Smoothieware作者整的不规范, 能看出来, 他们不想带小白玩.
如果想膜拜Smoothieware的实现, 只能像我这样, 自己迁移Smoothieware工程, 从命令行到其他嵌入式开发的IDE. 这活, 不是随便拉一个项目小白就能搞的, 有点门槛.
如果编译不过, 出现cc1plus的报错, 可以试试排除法, 将引起的报错的函数找到, 然后将报错函数拆成几个较小的函数, 然后在报错点调用这几个小函数, 问题就解决了.
这个问题头一次遇到, 当网上公版的方法不好使的时候, 还可以依靠自己以前积累下来的调试感觉, 不断折腾, 终于搞定:) 机智!
补充
在正式工程中搞了一下, 有一些细节出入. 总体思路是对的.
文件还是一个robot.cpp
添加了一个函数load_config_next1(), 用来放装不下的实现 然后load_config()尾部上调用load_config_next1().
常量数组不能放在函数中间, 这个数组是一个常量数组(相当于一个常量数组), 可以放到函数外面.
数组的大小是根据宏来实现的, 需要设置预定义宏 MAX_ROBOT_ACTUATORS 为确定的值, 否则编译器可能将数组的size搞错, 导致编译不过.
感觉原始工程这块的编码不规范, 引起好多不必要的麻烦.
依然已经使用了类, 这个数组又是常量的, 放在类里作为成员. 在类初始化函数中赋值就好了. 为啥要放在函数中间, 将编译器搞懵逼呢?
C++的高级特性和编译器有关系, 不是不得已就不用. 使用C++简单一些好, 就像使用带类的C那样简单的使用C++就挺好. 即使换了编译器(或者换了C++标准), 也没啥影响.
如果在非必要场景下, 使用了C++高级特性, 纯粹在给自己找麻烦.
// 在工程设置中, 添加预定义宏 MAX_ROBOT_ACTUATORS=5
// 给这个宏一个确定的值, 因为这个宏的值影响这个常量数组的大小. 否则编译器不知道这个数组多大. 会导致编译不过.
// Make our Primary XYZ StepperMotors, and potentially A B C
uint16_t const motor_checksums[][6] = {
ACTUATOR_CHECKSUMS("alpha"), // X
ACTUATOR_CHECKSUMS("beta"), // Y
ACTUATOR_CHECKSUMS("gamma"), // Z
#if MAX_ROBOT_ACTUATORS > 3
ACTUATOR_CHECKSUMS("delta"), // A
#if MAX_ROBOT_ACTUATORS > 4
ACTUATOR_CHECKSUMS("epsilon"), // B
#if MAX_ROBOT_ACTUATORS > 5
ACTUATOR_CHECKSUMS("zeta") // C
#endif
#endif
#endif
};
void Robot::load_config()
{
// Arm solutions are used to convert positions in millimeters into position in steps for each stepper motor.
// While for a cartesian arm solution, this is a simple multiplication, in other, less simple cases, there is some serious math to be done.
// To make adding those solution easier, they have their own, separate object.
// Here we read the config to find out which arm solution to use
if (this->arm_solution) delete this->arm_solution;
int solution_checksum = get_checksum(THEKERNEL->config->value(arm_solution_checksum)->by_default("cartesian")->as_string());
// Note checksums are not const expressions when in debug mode, so don't use switch
if(solution_checksum == hbot_checksum || solution_checksum == corexy_checksum) {
this->arm_solution = new HBotSolution(THEKERNEL->config);
} else if(solution_checksum == corexz_checksum) {
this->arm_solution = new CoreXZSolution(THEKERNEL->config);
} else if(solution_checksum == rostock_checksum || solution_checksum == kossel_checksum || solution_checksum == delta_checksum || solution_checksum == linear_delta_checksum) {
this->arm_solution = new LinearDeltaSolution(THEKERNEL->config);
} else if(solution_checksum == rotatable_cartesian_checksum) {
this->arm_solution = new RotatableCartesianSolution(THEKERNEL->config);
} else if(solution_checksum == rotary_delta_checksum) {
this->arm_solution = new RotaryDeltaSolution(THEKERNEL->config);
} else if(solution_checksum == morgan_checksum) {
this->arm_solution = new MorganSCARASolution(THEKERNEL->config);
} else if(solution_checksum == cartesian_checksum) {
this->arm_solution = new CartesianSolution(THEKERNEL->config);
} else {
this->arm_solution = new CartesianSolution(THEKERNEL->config);
}
this->feed_rate = THEKERNEL->config->value(default_feed_rate_checksum )->by_default( 100.0F)->as_number();
this->seek_rate = THEKERNEL->config->value(default_seek_rate_checksum )->by_default( 100.0F)->as_number();
this->mm_per_line_segment = THEKERNEL->config->value(mm_per_line_segment_checksum )->by_default( 0.0F)->as_number();
this->delta_segments_per_second = THEKERNEL->config->value(delta_segments_per_second_checksum )->by_default(0.0f )->as_number();
this->mm_per_arc_segment = THEKERNEL->config->value(mm_per_arc_segment_checksum )->by_default( 0.0f)->as_number();
this->mm_max_arc_error = THEKERNEL->config->value(mm_max_arc_error_checksum )->by_default( 0.01f)->as_number();
this->arc_correction = THEKERNEL->config->value(arc_correction_checksum )->by_default( 5 )->as_number();
// in mm/sec but specified in config as mm/min
this->max_speeds[X_AXIS] = THEKERNEL->config->value(x_axis_max_speed_checksum )->by_default(60000.0F)->as_number() / 60.0F;
this->max_speeds[Y_AXIS] = THEKERNEL->config->value(y_axis_max_speed_checksum )->by_default(60000.0F)->as_number() / 60.0F;
this->max_speeds[Z_AXIS] = THEKERNEL->config->value(z_axis_max_speed_checksum )->by_default( 300.0F)->as_number() / 60.0F;
this->max_speed = THEKERNEL->config->value(max_speed_checksum )->by_default( -60.0F)->as_number() / 60.0F;
this->segment_z_moves = THEKERNEL->config->value(segment_z_moves_checksum )->by_default(true)->as_bool();
this->save_g92 = THEKERNEL->config->value(save_g92_checksum )->by_default(false)->as_bool();
this->save_g54 = THEKERNEL->config->value(save_g54_checksum )->by_default(THEKERNEL->is_grbl_mode())->as_bool();
string g92 = THEKERNEL->config->value(set_g92_checksum )->by_default("")->as_string();
if(!g92.empty()) {
// optional setting for a fixed G92 offset
std::vector<float> t= parse_number_list(g92.c_str());
if(t.size() == 3) {
g92_offset[0] = t[0];
g92_offset[1] = t[1];
g92_offset[2] = t[2];
}
}
// default s value for laser
this->s_value = THEKERNEL->config->value(laser_module_default_power_checksum)->by_default(0.8F)->as_number();
// 下面这个数组放在这里, 编译不过
// cc1plus.exe: out of memory allocating 65536 bytes
// 只是一个常量数组, 移到函数外面
// // Make our Primary XYZ StepperMotors, and potentially A B C
// uint16_t const motor_checksums[][6] = {
// ACTUATOR_CHECKSUMS("alpha"), // X
// ACTUATOR_CHECKSUMS("beta"), // Y
// ACTUATOR_CHECKSUMS("gamma"), // Z
// #if MAX_ROBOT_ACTUATORS > 3
// ACTUATOR_CHECKSUMS("delta"), // A
// #if MAX_ROBOT_ACTUATORS > 4
// ACTUATOR_CHECKSUMS("epsilon"), // B
// #if MAX_ROBOT_ACTUATORS > 5
// ACTUATOR_CHECKSUMS("zeta") // C
// #endif
// #endif
// #endif
// };
// default acceleration setting, can be overriden with newer per axis settings
this->default_acceleration= THEKERNEL->config->value(acceleration_checksum)->by_default(100.0F )->as_number(); // Acceleration is in mm/s^2
// make each motor
for (size_t a = 0; a < MAX_ROBOT_ACTUATORS; a++) {
Pin pins[3]; //step, dir, enable
for (size_t i = 0; i < 3; i++) {
pins[i].from_string(THEKERNEL->config->value(motor_checksums[a][i])->by_default("nc")->as_string())->as_output();
}
if(!pins[0].connected() || !pins[1].connected()) { // step and dir must be defined, but enable is optional
if(a <= Z_AXIS) {
THEKERNEL->streams->printf("FATAL: motor %c is not defined in config\n", 'X'+a);
n_motors= a; // we only have this number of motors
return;
}
break; // if any pin is not defined then the axis is not defined (and axis need to be defined in contiguous order)
}
StepperMotor *sm = new StepperMotor(pins[0], pins[1], pins[2]);
// register this motor (NB This must be 0,1,2) of the actuators array
uint8_t n= register_motor(sm);
if(n != a) {
// this is a fatal error
THEKERNEL->streams->printf("FATAL: motor %d does not match index %d\n", n, a);
return;
}
actuators[a]->change_steps_per_mm(THEKERNEL->config->value(motor_checksums[a][3])->by_default(a == 2 ? 2560.0F : 80.0F)->as_number());
actuators[a]->set_max_rate(THEKERNEL->config->value(motor_checksums[a][4])->by_default(30000.0F)->as_number()/60.0F); // it is in mm/min and converted to mm/sec
actuators[a]->set_acceleration(THEKERNEL->config->value(motor_checksums[a][5])->by_default(NAN)->as_number()); // mm/secs²
}
check_max_actuator_speeds(); // check the configs are sane
// if we have not specified a z acceleration see if the legacy config was set
if(isnan(actuators[Z_AXIS]->get_acceleration())) {
float acc= THEKERNEL->config->value(z_acceleration_checksum)->by_default(NAN)->as_number(); // disabled by default
if(!isnan(acc)) {
actuators[Z_AXIS]->set_acceleration(acc);
}
}
load_config_next1();
}
void Robot::load_config_next1()
{
// initialise actuator positions to current cartesian position (X0 Y0 Z0)
// so the first move can be correct if homing is not performed
ActuatorCoordinates actuator_pos;
arm_solution->cartesian_to_actuator(machine_position, actuator_pos);
for (size_t i = X_AXIS; i <= Z_AXIS; i++) {
actuators[i]->change_last_milestone(actuator_pos[i]);
}
#if MAX_ROBOT_ACTUATORS > 3
// initialize any extra axis to machine position
for (size_t i = A_AXIS; i < n_motors; i++) {
actuators[i]->change_last_milestone(machine_position[i]);
}
#endif
//this->clearToolOffset();
soft_endstop_enabled= THEKERNEL->config->value(soft_endstop_checksum, enable_checksum)->by_default(false)->as_bool();
soft_endstop_halt= THEKERNEL->config->value(soft_endstop_checksum, halt_checksum)->by_default(true)->as_bool();
soft_endstop_min[X_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, xmin_checksum)->by_default(NAN)->as_number();
soft_endstop_min[Y_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, ymin_checksum)->by_default(NAN)->as_number();
soft_endstop_min[Z_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, zmin_checksum)->by_default(NAN)->as_number();
soft_endstop_max[X_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, xmax_checksum)->by_default(NAN)->as_number();
soft_endstop_max[Y_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, ymax_checksum)->by_default(NAN)->as_number();
soft_endstop_max[Z_AXIS]= THEKERNEL->config->value(soft_endstop_checksum, zmax_checksum)->by_default(NAN)->as_number();
}