5iMX.com 我爱模型 玩家论坛 ——专业遥控模型和无人机玩家论坛(玩模型就上我爱模型,创始于2003年)

标题: 单片机 实现6轴联动控制 ,最高输出频率200K 可能吗 [打印本页]

作者: scottmaxwell    时间: 2012-4-6 00:37
标题: 单片机 实现6轴联动控制 ,最高输出频率200K 可能吗
:em04:
论坛为什么只能上传 195k的图片呀

[ 本帖最后由 scottmaxwell 于 2012-4-6 00:51 编辑 ]
作者: 惠民    时间: 2012-4-6 01:00
不懂。帮顶。
作者: kissjack    时间: 2012-4-6 02:18
如果只是控制,也就是IO输出高低电平,可以做到。
但是如果一边计算一边输出,这个没办法,特别是涉及到除法运算。
作者: qwert8mg    时间: 2012-4-6 08:47
这个完全看单片机性能和程序设计了,还有控制需求。预加载刀路的话可以考虑先运算后输出。
作者: hxq123    时间: 2012-4-6 08:53
不做复杂运算估计没什么问题。貌似现在51单片机可以上三四十M的晶振。
为什么不用ARM呢,价格也便宜,量又足。
作者: scottmaxwell    时间: 2012-4-6 11:02
原帖由 hxq123 于 2012-4-6 08:53 发表
不做复杂运算估计没什么问题。貌似现在51单片机可以上三四十M的晶振。
为什么不用ARM呢,价格也便宜,量又足。

需要做插补运算的,每走一步都需要计算下一步各轴的输出.ARM   IO口的操作效率不高,51单片机,就是上三四百M的晶振,也计算不过来,还必须要借助单片机的硬件外设模块完成,
现在使用的是 pic32    80M 主频   1.56 DMIPS/MHZ,带有DMA模块(这个很重要),最重要的是他的io口有单时钟周期操作能力,这个是ARM7远远做不到的,必须要有快速中断处理功能,就是要有影子寄存器

[ 本帖最后由 scottmaxwell 于 2012-4-6 11:21 编辑 ]
作者: scottmaxwell    时间: 2012-4-6 11:04
原帖由 kissjack 于 2012-4-6 02:18 发表
如果只是控制,也就是IO输出高低电平,可以做到。
但是如果一边计算一边输出,这个没办法,特别是涉及到除法运算。

就是一边计算   一边输出,需要避免除法运算的, 除法可以转换成定点乘法运算.
当然同时还要给下面几条G代码进行预处理

[ 本帖最后由 scottmaxwell 于 2012-4-6 11:08 编辑 ]
作者: godson    时间: 2012-4-6 11:04
这个听大牛解说了
作者: cslzgts    时间: 2012-4-6 11:18
我试过了51 不行  单轴都做不好
作者: scottmaxwell    时间: 2012-4-6 12:34
如果可以的话  6轴联动插补,最高200KHZ输出, io输出输入全部光电隔离, USB接口    0 -10v 模拟量输出,电子手轮接口,原点,限位  都可以做进去.
上位自己写,或支持mach3,估计下来硬件成本不超过 150元
作者: hzs_1002    时间: 2012-4-6 14:10
细分不要搞太高,或许可以.
作者: scottmaxwell    时间: 2012-4-6 15:27
原帖由 hzs_1002 于 2012-4-6 14:10 发表
细分不要搞太高,或许可以.

1.8度的步进电机   16细分   丝杆导程为4mm的    200KHZ的输出  f值最高可以到 15000
作者: 3dbuild    时间: 2012-4-6 18:56
f值15000好象没什么实际意义吧?惯性这么大,机器会抖得很,影响加工质量,除非很轻的负载,贴片机之类的,不过这种场合可以用同步带,这就不需要这么高的f值了。我觉得LZ有能力,不如研究一下用低成本的8位AVR单片机实现最高f2000就够了,M8最便宜的才几块一片,用一片M8做脉冲输出,用另一片M168和PC通讯、G代码预处理、开关量控制和模拟量采集,M168和M8之间用IIC通讯,这样成本极低

运行在20MHz主频的M8,在f2000的情况下,每个脉冲上升沿和下降沿之间的时间,M8的中断程序可以执行大约375条指令,实际上6轴的中断输出程序不到100条指令

ATmega8-16AU 3.75元/片
ATmega168-20AU 7.5元/片

[ 本帖最后由 3dbuild 于 2012-4-6 18:59 编辑 ]
作者: scottmaxwell    时间: 2012-4-6 19:14
原帖由 3dbuild 于 2012-4-6 18:56 发表
f值15000好象没什么实际意义吧?惯性这么大,机器会抖得很,影响加工质量,除非很轻的负载,贴片机之类的,不过这种场合可以用同步带,这就不需要这么高的f值了。我觉得LZ有能力,不如研究一下用低成本的8位AVR单片机 ...

F15000对于使用1MM 800脉冲(1.8度  16细分  丝杆导程 4mm),但是对于我现在使用的 伺服驱动意义很大  
3600线的伺服 四倍频后  丝杆导程 4mm  每移动 1mm  需要3600个脉冲    这是的f值就是 3300.
以前我就是玩AVR的,但是AVR 8位单片机基本无戏,运算能力相差百倍,还缺少 DMA 这种不需要CPU干预传输数据的模块
M8的中断也不是快速中断  缺少影子寄存器,中断的时候需要保护现场,也需要许多的指令周期   况且8位单片机 计算32位数据时根本就力不从心,做插补时候  8位数据是远远不够的,还有我不知到 你如何使用8位单片机  6轴插补运算只有 100条指令,我现在的32位单片机需要300多条指令
ATmega8-16AU 3.75元/片
ATmega168-20AU 7.5元/片

这个价格是谁报给你的

[ 本帖最后由 scottmaxwell 于 2012-4-6 19:30 编辑 ]
作者: 3dbuild    时间: 2012-4-6 19:43
你用伺服驱动就没办法了,是要这么高的输出频率
用我的方案,不需要M8来计算32位数据,由M168来做计算准备,把一长串脉冲拆分成最多255个脉冲,M8只负责输出脉冲,程序变得很简单,对于M168来说,处理时间比单CPU方案多了255倍,相当于M168运行在5G
价格是前段时间在淘宝上买的,可能是散新件,测试过运行正常,没有问题,唯一不确定的是里面的EEPROM不知道是不是给写过,写过多少次?不过我的程序不用EEPROM,所以没有问题

我觉得如果可以在有限的硬件里实现高级的功能,才能体现一个技术水平,当然用更高级的CPU会省事一些

[ 本帖最后由 3dbuild 于 2012-4-6 19:46 编辑 ]
作者: scottmaxwell    时间: 2012-4-6 19:47
原帖由 3dbuild 于 2012-4-6 19:43 发表
你用伺服驱动就没办法了,是要这么高的输出频率
用我的方案,不需要M8来计算32位数据,由M168来做计算准备,把一长串脉冲拆分成最多255个脉冲,M8只负责输出脉冲,程序变得很简单,对于M168来说,处理时间比单CPU方 ...


插补需要实时计算的,每走一步需要计算下一步,保证最小误差1步以内,况且AVR 168 也没有 USB接口. PIC32的USB通许也可以 不需要 CPU干预,可以直接拷贝到预先设定好的内存缓存取.

[ 本帖最后由 scottmaxwell 于 2012-4-6 19:51 编辑 ]
作者: 3dbuild    时间: 2012-4-6 19:50
如果你用伺服的目的,只是要它的高速度和高可靠定位精度,而它的每圈脉冲数成为问题的话,可以考虑用我的方案,外加倍频芯片,成本也很低的
作者: scottmaxwell    时间: 2012-4-6 19:56
原帖由 3dbuild 于 2012-4-6 19:50 发表
如果你用伺服的目的,只是要它的高速度和高可靠定位精度,而它的每圈脉冲数成为问题的话,可以考虑用我的方案,外加倍频芯片,成本也很低的

不是每圈脉冲数   比如  G1 X100 Y200 Z300 A400 B500 C600  做 插补  
每个轴 每走1MM 需要800个 脉冲 ,如何实现  
X走第一步时  X输出一个脉冲      X走第2步是   X 输出一个脉冲  Y也输出一个脉冲   
X走第2步  X 输出一个脉冲  Z输出一个脉冲  ......

[ 本帖最后由 scottmaxwell 于 2012-4-6 19:59 编辑 ]
作者: 3dbuild    时间: 2012-4-6 19:56
原帖由 scottmaxwell 于 2012-4-6 19:47 发表


插补需要实时计算的,每走一步需要计算下一步,保证最小误差1步以内

这个可以做到,对于6轴输出的其中一段来说,准备好6轴的每脉冲数据,每次定时器中断时进行各轴位置累加,判断各个输出端是否要输出,结果用位&操作保存在一个寄存器临时变量,最后一次性在同一个端口寄存器输出,每步都不会有误差

每个轴 每走1MM 需要800个 脉冲 ,如何实现
把800个脉冲用M168分成4段,每段200个脉冲,预先处理数据传给M8,在中断服务程序里输出脉冲,输出脉冲的同时,M8的主循环用IIC接收下一段200个或者其他个数的输出脉冲命令

[ 本帖最后由 3dbuild 于 2012-4-6 19:58 编辑 ]
作者: scottmaxwell    时间: 2012-4-6 20:04
原帖由 3dbuild 于 2012-4-6 19:56 发表

这个可以做到,对于6轴输出的其中一段来说,准备好6轴的每脉冲数据,每次定时器中断时进行各轴位置累加,判断各个输出端是否要输出,结果用位&操作保存在一个寄存器临时变量,最后一次性在同一个端口寄存器输出,每 ...

X轴总共要走 800*100   
分别需要判断6轴   判断  累加  我不知到你有没有看程序编译好的汇编代码,他到底产生了多少条指令
置位后  你还需要在1us -10 us 后让他边为低电平  才是一个脉冲 ,这个对于AVR 就是使用一个定时器  但是定时器中断 需要写中断程序   中断程序 需要保护现场 恢复现场    拉到低电平 也需要几条指令 因为 AVR io口没有置位和清零寄存器,否则你就会影响其他位 所以要先读取8个io口的状态 ,这些都需要CPU 开销的
还有我不知道你这个方法实现过了 ,还是只是停留在理论之上

[ 本帖最后由 scottmaxwell 于 2012-4-6 20:15 编辑 ]
作者: lvsoft    时间: 2012-4-6 20:12
原帖由 3dbuild 于 2012-4-6 19:43 发表
你用伺服驱动就没办法了,是要这么高的输出频率
用我的方案,不需要M8来计算32位数据,由M168来做计算准备,把一长串脉冲拆分成最多255个脉冲,M8只负责输出脉冲,程序变得很简单,对于M168来说,处理时间比单CPU方 ...


我觉得没这个必要吧...
成本主要在光耦上面,MCU贵点一点问题都没有。
又不是大规模量产,这方面的成本没必要扣的这么死给自己找罪受。
作者: lvsoft    时间: 2012-4-6 20:16
原帖由 lvsoft 于 2012-4-6 20:12 发表


我觉得没这个必要吧...
成本主要在光耦上面,MCU贵点一点问题都没有。
又不是大规模量产,这方面的成本没必要扣的这么死给自己找罪受。


额,我忘了,这里最高200K,那也没必要像我那样用速度10M的光耦了,成本可以降低不少。
作者: scottmaxwell    时间: 2012-4-6 20:19
原帖由 lvsoft 于 2012-4-6 20:16 发表


额,我忘了,这里最高200K,那也没必要像我那样用速度10M的光耦了,成本可以降低不少。

对的,高速光耦价格不便宜。
作者: zhanghailu    时间: 2012-4-6 20:25
这是在论战什么?坐板凳听。
作者: cjseng    时间: 2012-4-6 22:46
在我看来,这是不可能的,单片机的速度根本到不到要求。不要说200K,20K也不可能。
前天刚好用单片机做了一个小东西,相当于控制4轴输出,最高频率50hz,最低1hz,不仔细点还做不好。
作者: 3dbuild    时间: 2012-4-6 23:35
原帖由 scottmaxwell 于 2012-4-6 20:04 发表
AVR io口没有置位和清零寄存器,否则你就会影响其他位 所以要先读取8个io口的状态 ,这些都需要CPU 开销的


从这段话来看,觉得你要么没有对AVR的处理器做深入的了解,要么没理解我的算法。实际上不需要置位和清零寄存器,也不需要读8个IO口的状态,CPU只是输出,不用管它原来是什么状态,原来的状态是通过运算得到。例如,你可以把6轴的脉冲IO对应到PORTB的低6位,高2位不接输出,所以不用管,然后在中断程序里把一个寄存器变量A设为0,再按顺序判断每个IO是否需要拉高,是就置位,例如0位需要拉高,就A=0x1,接着如果第2位需要拉高,就A &= 0x2,如此把全部6个轴都处理完,变量A里得到一个6轴状态,然后用PORTB = A一条指令把6个轴的当次脉冲状态输出,完成后运行30条空指令延时1us以上,然后PORTB=0一条指令把6个轴的输出拉低,再退出中断程序。在这个过程中,如果某个轴当次不需要输出,则对应的输出脚会保持低电平,不会有问题。

这个算法的关键地方,是定时器要永远运行在最高的输出频率,例如100KHz,中断程序要处理各轴的累加状态和是否输出脉冲,这个过程全部是整数运算,中间会用到一些预先由上一个CPU算好的参数,来控制各轴在合适的脉冲个数输出脉冲,可以参考一下Bresenham直线算法与画圆算法的介绍:http://oldj.net/article/bresenham-algorithm/

熟悉PC开发然后再搞单片机的人,习惯于用1个CPU做全部的事情,这个在单片机的世界里是不太一样的,在需要的时候完全可以1个CPU专注一个事情,多个CPU协作以达到更高的性价比
作者: 3dbuild    时间: 2012-4-6 23:41
原帖由 cjseng 于 2012-4-6 22:46 发表
在我看来,这是不可能的,单片机的速度根本到不到要求。不要说200K,20K也不可能。
前天刚好用单片机做了一个小东西,相当于控制4轴输出,最高频率50hz,最低1hz,不仔细点还做不好。

RepRap里的Marlin固件可以用1个8位AVR CPU稳定输出10K的4轴脉冲驱动打印机,XY轴还带标准线性加减速控制,同时还在读SD卡,解释G代码,G代码还支持前向预读,可以在转向位置尽量保持恒定运动速度,还支持圆弧插补,读取和控制喷头温度和加热床温度,检测限位开关,还要和PC通讯,按你的说法是根本不可能的了,可是人家却做到了

[ 本帖最后由 3dbuild 于 2012-4-6 23:43 编辑 ]
作者: lvsoft    时间: 2012-4-6 23:59
原帖由 3dbuild 于 2012-4-6 23:41 发表

RepRap里的Marlin固件可以用1个8位AVR CPU稳定输出10K的4轴脉冲驱动打印机,XY轴还带标准线性加减速控制,同时还在读SD卡,解释G代码,G代码还支持前向预读,可以在转向位置尽量保持恒定运动速度,还支持圆弧插补, ...


不是做不到...而是真心没啥意义,只要愿意堆精力,人总是能找出方法不断的压榨出硬件的潜力的。
很多搞开源的人喜欢给自己树立一个目标挑战下自己,
但是我还是希望还是能换个别的类型的目标...
作者: scottmaxwell    时间: 2012-4-7 00:01
原帖由 3dbuild 于 2012-4-6 23:35 发表


从这段话来看,觉得你要么没有对AVR的处理器做深入的了解,要么没理解我的算法。实际上不需要置位和清零寄存器,也不需要读8个IO口的状态,CPU只是输出,不用管它原来是什么状态,原来的状态是通过运算得到。例如 ...


你这个讲的是最基础的只是  很多年前我就知道了  1你废了2个IO口   6轴输出  除了这个  还有方向也需要6个口,使能信号6个口,还有需要采集输入多个口,你认为你的单片机有几个口让你废,还有他这个是专用的   每个轴的脉冲数可以预先知道,这样也可以减小计算位数.
Bresenham 画直线运算我很多年年就研究过了 写GUI画直线函数.
作者: 3dbuild    时间: 2012-4-7 00:06
方向,使能,脉冲总共用3个8位IO口,一片M8就足够了,M8只管脉冲,有什么问题吗?其他的采集口用M168,感觉你还是在想着用1片CPU做全部事情

[ 本帖最后由 3dbuild 于 2012-4-7 00:07 编辑 ]
作者: scottmaxwell    时间: 2012-4-7 00:08
原帖由 3dbuild 于 2012-4-6 23:41 发表

RepRap里的Marlin固件可以用1个8位AVR CPU稳定输出10K的4轴脉冲驱动打印机,XY轴还带标准线性加减速控制,同时还在读SD卡,解释G代码,G代码还支持前向预读,可以在转向位置尽量保持恒定运动速度,还支持圆弧插补, ...

RepRap本身的精度就不高,专用控制的 ,  10k 4轴  提高一下效率  或许是可以作到的 ,但是他肯定是有很多限制的,并不是通用的.
比如你用 其他  CAM 软件生成的G代码,根本就不能运行
作者: 3dbuild    时间: 2012-4-7 00:10
用8位单片机回应你这个主题的意思是,200K,用你的32位单片机,本来就不是做不到的事,只是没有人这么做,可能是商业上的原因,这个你要考虑清楚
作者: 3dbuild    时间: 2012-4-7 00:15
原帖由 scottmaxwell 于 2012-4-7 00:08 发表

RepRap本身的精度就不高,专用控制的 ,  10k 4轴  提高一下效率  或许是可以作到的 ,但是他肯定是有很多限制的,并不是通用的.
比如你用 其他  CAM 软件生成的G代码,根本就不能运行

RepRap精度不高是机械部分,电子部分没有精度这个说法,只有稳定性,而稳定性可能比MACH3还高或者维宏卡还高,RepRap的打印动不动就连续运行24小时的,中间一出错就全部报废,这个你可能不了解。至于通用性,没有东西是万能的,你做得再通用,也只是业余人士敢用,专业点的,例如木工加工中心,机加工中心,不可能用的,这个是商业定位问题,如果你有想法向这个方向发展,首先面对的就是一堆类似西门子之类的专业控制器,竞争不是一般的大
作者: scottmaxwell    时间: 2012-4-7 00:20
原帖由 3dbuild 于 2012-4-7 00:06 发表
方向,使能,脉冲总共用3个8位IO口,一片M8就足够了,M8只管脉冲,有什么问题吗?其他的采集口用M168,感觉你还是在想着用1片CPU做全部事情

不要认为 你的2片AVR 性能会比一片高      一片PIC32的性能至少是 AVR 单片机的几十倍性能,数控插补软件算法没有几种,效率也就在那片,还有什么整数计算,这个是最基本的能力,如果需要快速运算,实时处理,还有浮点,除法,那你就什么都做不成了.
你认为单独的一片AVR可以处理接受数据  读取SD卡   我告诉你 有DMA的单片机  读取这个都不需要CPU干预的.
作者: cjseng    时间: 2012-4-7 00:25
原帖由 3dbuild 于 2012-4-6 23:41 发表

RepRap里的Marlin固件可以用1个8位AVR CPU稳定输出10K的4轴脉冲驱动打印机,XY轴还带标准线性加减速控制,同时还在读SD卡,解释G代码,G代码还支持前向预读,可以在转向位置尽量保持恒定运动速度,还支持圆弧插补, ...


走走停停当然做得到,实时插补还要200K绝对不可能。
作者: scottmaxwell    时间: 2012-4-7 00:27
原帖由 3dbuild 于 2012-4-7 00:15 发表

RepRap精度不高是机械部分,电子部分没有精度这个说法,只有稳定性,而稳定性可能比MACH3还高或者维宏卡还高,RepRap的打印动不动就连续运行24小时的,中间一出错就全部报废,这个你可能不了解。至于通用性,没有东 ...

RepRap 很早就研究过的.
国外的电子开源项目,几乎都晚过  mega8 经典的开源就是控制32路舵机. 06 年的时候就仿制,改进过

[ 本帖最后由 scottmaxwell 于 2012-4-7 00:32 编辑 ]
作者: 3dbuild    时间: 2012-4-7 00:29
我好象从来都没有说过“2片AVR 性能会比一片高”?只是暗示"2片AVR价格比一片PIC32便宜几倍,而且可以做到类似的事情,前提是要求稍微降低一些"

遇到一些搞单片机开发的人,总是觉得8位的低级,觉得搞就得要搞32位的,最好还是ARM的,能跑Linux的更好,这才体现其专业水准。我不反对这个观点,能搞高级的肯定比只会低级的水平高,但是真正做项目时就未必用这个标准,而是要找最合适的,例如做个充电器,用32的合适还是8的合适?
作者: 3dbuild    时间: 2012-4-7 00:30
原帖由 cjseng 于 2012-4-7 00:25 发表


走走停停当然做得到,实时插补还要200K绝对不可能。


不是200K,Marlin是10K,连续的,不可能走走停停,走走停停会影响表面质量
作者: 3dbuild    时间: 2012-4-7 00:32
原帖由 scottmaxwell 于 2012-4-7 00:27 发表

RepRap 很早就研究过的


我感觉你有精力研究一下会比搞通用的好,RepRap硬件和软件发展都很快,比你“很早”的时候应该先进了不少,而且现在卖的都是暴利,你上网查一下价格
作者: cjseng    时间: 2012-4-7 00:37
原帖由 3dbuild 于 2012-4-7 00:30 发表


不是200K,Marlin是10K,连续的,不可能走走停停,走走停停会影响表面质量


能说明一下:RepRap里的Marlin固件可以用1个8位AVR CPU稳定输出10K的4轴信号是哪四轴吗?
作者: scottmaxwell    时间: 2012-4-7 00:39
原帖由 3dbuild 于 2012-4-7 00:29 发表
我好象从来都没有说过“2片AVR 性能会比一片高”?只是暗示"2片AVR价格比一片PIC32便宜几倍,而且可以做到类似的事情,前提是要求稍微降低一些"

遇到一些搞单片机开发的人,总是觉得8位的低级,觉得搞就得要搞32位 ...

不要和我提AVR 了   04年的时候就玩AVR了,从tiny  mega 到xmega 用它作过很多项目,完全了解他的性能和特点.
我是从要求上去选者单片机,但是使用2片单片机的想法直接弊掉,并不会这个单片机不能满足就上2片,只能说明你玩单片机的种类太少

[ 本帖最后由 scottmaxwell 于 2012-4-7 00:45 编辑 ]
作者: cjseng    时间: 2012-4-7 00:46
我在想,6个轴,如果记为X、Y、Z、A、B、C的话,假设为了实现一条曲线,X频率200K,Y轴179K,Z轴127K,A轴121K,B轴89K,C轴77K,那么,请问这时候单片机的定时精度需要多少K?
作者: scottmaxwell    时间: 2012-4-7 00:53
原帖由 3dbuild 于 2012-4-7 00:30 发表


不是200K,Marlin是10K,连续的,不可能走走停停,走走停停会影响表面质量

对于一个 1.8度步进电机  16细份(如果我没有记错的画 RepRap是没有细分的 )  导成为 4mm的丝杆   F值最高就是 720
作者: scottmaxwell    时间: 2012-4-7 00:59
原帖由 cjseng 于 2012-4-7 00:46 发表
我在想,6个轴,如果记为X、Y、Z、A、B、C的话,假设为了实现一条曲线,X频率200K,Y轴179K,Z轴127K,A轴121K,B轴89K,C轴77K,那么,请问这时候单片机的定时精度需要多少K?

G91
G1 X200 Y179 Z127 A121 B89  C77
这个不是定时器精度的问题   插补肯定有误差的 因为电机控制是离散的,一个一个脉冲给的  所以画的线 和理想的线  在一个最小步误差之间摆动
事实上你只要可以最高那个轴频率的中断就可以了,通过它来计算 各轴是否要输出脉冲,200KHZ 中断 就是  5us  就是说要在这个时间内完成计算
1 DMIPS/MHz 的单片机  时钟频率为20MHZ  它5us 连续运算能力最高是 执行 5*20条指令,但是如果有条件跳转指令的话,是达不到这个速度的,因为事实上一条指令都需要4个时钟周期,由于4条指令流水线 ,连续工作就是 每个时钟执行一条指令,但是对于没有DSP核的单片机,一条加法 至少需要4条指令,分别从内存取出2个相加的数据  再相加  再保存,有硬件乘法器的,乘法同样是4条指令.运算能力还要看是几位单片机.

[ 本帖最后由 scottmaxwell 于 2012-4-7 01:22 编辑 ]
作者: scottmaxwell    时间: 2012-4-7 02:49
原帖由 3dbuild 于 2012-4-6 23:35 发表


从这段话来看,觉得你要么没有对AVR的处理器做深入的了解,要么没理解我的算法。实际上不需要置位和清零寄存器,也不需要读8个IO口的状态,CPU只是输出,不用管它原来是什么状态,原来的状态是通过运算得到。例如 ...

高手 麻烦你在优化一下我的算法,这个是2年前写的6轴插补
这个算法 在 80M  32位单片机上需要 最长耗时 4.75us,这里面有好几个变量是32位的

//6轴插补
extern inline void __attribute__((always_inline))  Six_ASIX(void)
{
    Step_out_mask = 0;  //端口输出掩码
    if(AllSteps>0)
    {
        Sum_X_ASIX +=X_ASIX;
        if(Sum_X_ASIX >= ASIX_Maxpulses)
        {
           Sum_X_ASIX -= ASIX_Maxpulses;
           AllSteps --;   
           X_POS += x_dir;
           Step_out_mask = 0x02;
        }
        Sum_Y_ASIX +=Y_ASIX;
        if(Sum_Y_ASIX >= ASIX_Maxpulses)
        {
           Sum_Y_ASIX -= ASIX_Maxpulses;
           AllSteps --;
           Y_POS += y_dir;
           Step_out_mask |= 0x04;
        }
        
        Sum_Z_ASIX +=Z_ASIX;
        if(Sum_Z_ASIX >= ASIX_Maxpulses)
        {
           Sum_Z_ASIX -= ASIX_Maxpulses;
           AllSteps --;  
           Z_POS +=z_dir;
           Step_out_mask |= 0x08;
        }
        Sum_A_ASIX +=A_ASIX;
        if(Sum_A_ASIX >= ASIX_Maxpulses)
        {
           Sum_A_ASIX -= ASIX_Maxpulses;
           AllSteps --;
           A_POS += a_dir;
           Step_out_mask |= 0x10;
        }
        Sum_B_ASIX +=B_ASIX;
        if(Sum_B_ASIX >= ASIX_Maxpulses)
        {
           Sum_B_ASIX -= ASIX_Maxpulses;
           AllSteps --;
           B_POS +=b_dir;
           Step_out_mask |= 0x20;
        }
        Sum_C_ASIX +=C_ASIX;
        if(Sum_C_ASIX >= ASIX_Maxpulses)
        {
           Sum_C_ASIX -= ASIX_Maxpulses;
           AllSteps --;
           C_POS += c_dir;
           Step_out_mask |= 0x40;
        }
    }
}

[ 本帖最后由 scottmaxwell 于 2012-4-7 02:59 编辑 ]
作者: yzwindos    时间: 2012-4-7 06:53
厉害。。。没玩过。。。加油。。。硬件成本是一个方面 。。。研发成本倒是不低。。。。。。

祝早日研发完成。。。好欣赏一下。。。
作者: 3dbuild    时间: 2012-4-7 09:48
高手就不必了


我现在用的是比较旧的G3硬件的RepRap,使用3977驱动步进电机,修改固件可以选择细分,最新的硬件已经默认使用8细分,研究程序的话,可以看看它的最新版,5D的插补程序没怎么优化


你贴上来这个2年前的程序,如果真心要请人给你优化,请把哪些变量是32位,哪些是8位写清楚,虽然我知道哪些应该是32位,还有就是你用的是什么单片机,这些变量哪些是寄存器变量类型,这些都没说,这么贴一个只有2行注释的程序出来,好象没有太大意义,所以关于指令集和CPU架构方面的优化就直接PASS掉了,只能在通用的算法层面,给你提点建议


程序里有6个类似的语句:X_POS += x_dir 没理解错的话,这个是单个脉冲输出后,记录当前位置的作用,x_dir的取值只有2种可能:+1 / -1,你现在的写法可以改为X_POS_DELTA ++,就是说在这个速度敏感的程序段,只记录运行了多少步,不管方向,在需要得到X_POS的程序段,用X_POS + X_POS_DELTA*x_dir的方法获得,再优化一下,可以把乘法都省掉。这样一改,少了6次内存读取,或者是释放了6个类似x_dir的寄存器变量(如果x_dir你设置为寄存器变量的话),对C程序优化器有一定帮助


在程序开头的 Step_out_mask = 0;  //端口输出掩码
可以改为 Step_out_mask ^= Step_out_mask,如果Step_out_mask是寄存器变量的话,编译后一般只有1条汇编指令,比你现在取一个立即数又快了一些

[ 本帖最后由 3dbuild 于 2012-4-7 09:50 编辑 ]
作者: scottmaxwell    时间: 2012-4-7 11:51
原帖由 3dbuild 于 2012-4-7 09:48 发表
高手就不必了


我现在用的是比较旧的G3硬件的RepRap,使用3977驱动步进电机,修改固件可以选择细分,最新的硬件已经默认使用8细分,研究程序的话,可以看看它的最新版,5D的插补程序没怎么优化


你贴上来这个 ...


165:                 //6轴插补
166:                 extern inline void __attribute__((always_inline))  Six_ASIX(void)
167:                 {
168:                     //Step_out_mask = 0;  //端口输出掩码
169:                     Step_out_mask ^= Step_out_mask;
9D00046C  9384806C   LBU A0, -32660(GP)
9D000470  9382806C   LBU V0, -32660(GP)
9D000478  00821826   XOR V1, A0, V0
9D00047C  A383806C   SB V1, -32660(GP)
170:                     if(AllSteps>0)

165:                 //6轴插补
166:                 extern inline void __attribute__((always_inline))  Six_ASIX(void)
167:                 {
168:                     Step_out_mask = 0;  //端口输出掩码
9D000470  A380806C   SB ZERO, -32660(GP)
169:                     //Step_out_mask ^= Step_out_mask;
170:                     if(AllSteps>0)
作者: 3dbuild    时间: 2012-4-7 23:14
从你发上来这个编译结果看,你没有把Step_out_mask设置为寄存器变量,所以改为Step_out_mask ^= Step_out_mask后,反而需要更多的内存读写,你现在的程序里,Step_out_mask只是一个存放在内存里的普通的自动变量,对这个变量操作是很慢的,即使你原来的程序只有1行编译代码。如果Step_out_mask是一个寄存器变量,例如V1,那么可以用一句XOR V1,V1把它清零,不需要操作内存,速度很快,我没搞过PIC32,不清楚它有没有这样的指令,不过在很古老的Z80里,都有XOR AL,AL这样的指令,现在这么“先进”的32位PIC32,如果没有类似的指令会让人很奇怪。

建议1:如果你找到了这样的指令,而不知道怎么把Step_out_mask设置为寄存器变量,也没关系,你可以用嵌入式汇编,直接把V1用了就可以

建议2:PIC32有很强的位运算指令,你的程序里有大量的Step_out_mask |= 0x20之类的语句,你最好检查一下编译器有没有把它编译成位运算指令,比|=指令更快

建议3:PIC32对程序和数据都有高速缓存,这个是PIC32架构的优点,你的程序里有大量的Sum_n_ASIX变量,你有考虑过利用这个高速缓存来提高内存操作速度了吗?怎么让CPU在处理Sum_X_ASIX时,已经把Sum_Y_ASIX预读进了高速缓存?怎么实现的?还是没有考虑过?

从你的程序看,可能你对程序优化只有初步的认识,你太依赖C编译器的优化,只会用inline。程序优化是一门很有意思的学问,包括算法级优化和CPU架构级优化,以上3个只是CPU架构级优化,通常是放在最后做的,效果也很有限,最有效果的是算法级优化,通过分析算法的瓶颈,找到改进的方法。

按你的说法,你这个6轴插补程序,在80M的32位PIC32上能输出200K已经觉得很不错了,不过我要告诉你,通过算法级优化,我在16M的8位AVR M168上,在最差的条件下,即每轴每个时钟中断都发出一个脉冲的条件下,测试程序实现了6轴58.8K的输出,换成20M的晶振就可以达到73.5K,而且每个轴每个脉冲的时间误差都不超过一个时钟中断的时间,也就是1/58.8K秒。实际上大部分G代码都不会有这种情况,各轴在每个时钟中断时,大部分时候只有1到2个轴经常有脉冲,其他的很多都是空白,你的程序就是把CPU浪费在这些空白的重复判断和处理上

迟点发个图给你说明一下,你的算法完全要改写,改写后不要说200K,以你80M的主频,应该可以飞上天
作者: cooooldog    时间: 2012-4-7 23:59
如此牛贴 来膜拜下各位大牛
作者: 3dbuild    时间: 2012-4-8 12:32
画个图来说明一下,这个是根据你贴上来的一个脉冲图画的,横向是时钟中断次数,纵向是6轴对应的脉冲,有脉冲的填为蓝色,其他是空白,结果是这样的


作者: 3dbuild    时间: 2012-4-8 12:37
从图上可以看出,有大量的空白的无脉冲区域,你的中断程序在每个白色的小方格里,都要运行一段类似这样的操作

          Sum_X_ASIX +=X_ASIX;
        if(Sum_X_ASIX >= ASIX_Maxpulses)
        {
           Sum_X_ASIX -= ASIX_Maxpulses;
           AllSteps --;   
           X_POS += x_dir;
           Step_out_mask = 0x02;
        }

对于PC机来说,速度够快,这么做没什么问题,但是单片机计算能力有限,这样做就太浪费了,结果就是中断程序运行时间太长,所以这里必须改进,避免这些不必要的计算
作者: scottmaxwell    时间: 2012-4-8 14:24
原帖由 3dbuild 于 2012-4-7 23:14 发表
从你发上来这个编译结果看,你没有把Step_out_mask设置为寄存器变量,所以改为Step_out_mask ^= Step_out_mask后,反而需要更多的内存读写,你现在的程序里,Step_out_mask只是一个存放在内存里的普通的自动变量,对 ...


你以为编译器会按你想像的给你编译吗,这样的话,那没有人会继续使用汇编了,不要纸上谈兵了.编译器的优化是有限制的. 还有你不用教我什么是寄存器变量,内存变量,这是做代码优化基本指示高密集算法是还可以使用 定点DSP,取两个内存变量,在相乘,最后累加.操作偏移地址,一条指令完成
还有看的的回复,你就根本没有学过pic32或者没有深入学习,连PIC32高速指令缓存怎么使用你都不知道

[ 本帖最后由 scottmaxwell 于 2012-4-8 14:42 编辑 ]
作者: scottmaxwell    时间: 2012-4-8 14:28
原帖由 3dbuild 于 2012-4-8 12:37 发表
从图上可以看出,有大量的空白的无脉冲区域,你的中断程序在每个白色的小方格里,都要运行一段类似这样的操作

          Sum_X_ASIX +=X_ASIX;
        if(Sum_X_ASIX >= ASIX_Maxpulses)
        {
          ...

你瞎扯什么呀,看懂什么意思了吗,这里没有一句是可以省略的,唯一方法就使使用嵌入式汇编优化,我现在最新写的代码就是嵌入式代码.
如果你可以使用你的双AVR 写出 25KHZ 4 轴  插补的,我拜你做老师.
至少要可以 运行 G1 X1000 Y1000 Z1000 A 1000  以内任意插补  还有平面内的圆插补 支持输出脉冲宽度 1us -10us
我又要去忙新项目了,基本上不会上论坛了,等你的好消息.
  最后提醒你的 方案中 i2c通讯是不合适的,建议你使用SPI

[ 本帖最后由 scottmaxwell 于 2012-4-8 15:03 编辑 ]
作者: 3dbuild    时间: 2012-4-8 15:14
你觉得我象是在瞎扯吗?你的相关个人信息,纳米机器人,我大概了解,我的信息,你一无所知,我搞Z80的时候,你还没进幼儿园, 所以不要太自以为是,这样对你没任何好处。以你这种性格和悟性,拜我做老师,我都不会收的。

好了,无关的不说,回到正题

这个程序刚经过优化,测试可以稳定输出66.7K脉冲,全32位6轴插补,当然它只管输出脉冲,用的16M主频的8位AVR M1280,搬到M8上没有任何问题,计算能力一样的

上面说到的这些不必要的计算,如何优化算法才能去掉呢?先用一个生活中的例子来说明一下。

假设有一个不透明的盒子,里面有100颗黄豆和30颗黑豆,现在的任务是要把30颗黑豆挑出来,有2种做法:

做法1:在盒子上开一个小孔,每次出一颗豆子,如果是黑豆则拿走,全部豆子都处理完后,30棵黑豆就挑出来了。这个方法要对每颗豆子做判断,速度很慢

做法2:把盒子里的豆子全部倒出来,把黑豆拿走,剩下的自然全部是黄豆。这个方法需要的判断很少,速度很快

你的程序其实就是第1种方法,因为每次中断的计算完全独立,无法利用前后脉冲的数据相关性,在每次中断时都需要判断各轴当前的位置,根据判断结果决定是否输出脉冲,计算量很大。如果不改变方法,确实如你所说,这段程序“没有一句是可以省略的”,如果按下面的说明改写程序,你会发现你发上来的整个程序"都是可以省略的

我改进后的算法是第2种方法,在主程序中进行插补计算,通俗一点说,就是先把上面的画面全部填为白色,然后在一个循环中根据每轴的插补数据把需要脉冲的位置填为蓝色,这个处理过程判断很少,没有脉冲的位置自然会保留成白色,脉冲间隔越大,蓝色位置越少,循环次数越少,计算越快。把这个脉冲图准备好后,在中断程序里只需要按顺序输出就可以了,中断程序变得很小。剩下的问题就是,内存有限,要把全部脉冲都准备好显然不可能,所以要准备2个缓冲区,我现在是用了2个100字节的缓冲区,一个用于中断输出,同时在另一个里准备数据,这样搭配好后,程序就可以工作了。实际运行结果是这样的:如果关闭中断,只做数据准备,可以达到156K的6轴脉冲填充率,如果打开中断输出脉冲,可以达到66.7K的脉冲填充率和输出速度,插补使用32位整数运算,和你的一样。圆弧插补不支持,需要在PC端用驱动程序处理,这样就把PC机的计算能力和单片机的实时能力结合在一起

[ 本帖最后由 3dbuild 于 2012-4-8 19:13 编辑 ]
作者: 3dbuild    时间: 2012-4-8 15:21
下面是部分程序的截图,用的是你看不上的Arduino,这是程序开始部分:
作者: 3dbuild    时间: 2012-4-8 15:23
这是中断程序
作者: 3dbuild    时间: 2012-4-8 15:27
这是6轴的32位变量和插补数据,算法经过改造,变量的含义和你的程序不一样的,为了避免部分人拿来即用,我把有关质数和奇偶数的处理删掉了,少了几个变量
作者: 3dbuild    时间: 2012-4-8 15:31
这个是关键的插补部分,同样的原因删掉了部分,不过已经可以看出算法原理,这里巧妙的结合了32位运算和8位运算,最大限度发挥CPU的性能,你看懂了么?
作者: 3dbuild    时间: 2012-4-8 16:10
从实用性角度考虑,LZ的PIC32方案只适合伺服电机,原因如下:

1 大部分DIY者使用步进电机,配合5MM滚珠丝杆和16细分驱动,200K的频率会运行在F18750,一般DIY的机器在这种速度下根本不能保持机械稳定性,由于惯性会严重抖动和摇晃
2 如果机器刚性很高,可以稳定运行F18750,这时每分钟前进18750mm,如果刀具也运行在1.8万转,那么对于双刃铣刀,每齿进给量是0.5mm,这么大的切削量,除了切泡沫塑料外,其他材料无一例外都会断刀。所以主轴至少要10万转级别的,这样的主轴什么价格?如果雕刻PCB,刀尖更小,10万转都不行
3 如果10万转主轴你刚好手头有一个,那么10万转运行带来的刀尖过热问题就出现了,要外加强制冷却
4 高速加工在转弯位置非常容易断刀,这个也很难处理

综合以上几点,LZ的200K对大部分DIY者没有实际意义,这是一个典型的木桶理论,电子部分拔得这么高,机械和材料都成为短板,结果电子部分的高性能无法发挥。倒不如用低成本的8位单片机做一个最高支持F3000到F5000的,成本35圆的6轴USB运动控制卡

用8位单片机的优点一个是成本低,另一个优点是这些芯片有DIP直插封装,项目开源之后,稍微懂点电子的人,都可以用万能板自己做一个
作者: 3dbuild    时间: 2012-4-8 16:15
我就跟贴到这里了,坛子里懂单片机的大侠很多,大家自有判断,至于LZ的方向还是你自己决定
作者: ywjianghu    时间: 2012-4-9 22:47
很好的帖子,如果能继续讨论就更好了。




欢迎光临 5iMX.com 我爱模型 玩家论坛 ——专业遥控模型和无人机玩家论坛(玩模型就上我爱模型,创始于2003年) (http://5imx.com/) Powered by Discuz! X3.3