|
本帖最后由 Gorgon_Meducer 于 2015-2-15 22:31 编辑
此贴专门用于阿莫蜘蛛项目进度报告
傻孩子工作室作品
STAFF
Hardware Design yiming988
Driver Design y574924080
Movement Design qufuta sunfulong
Mechanical Designing 老陈
Production 老陈
Architecture Design Gorgon_Meducer
SPONSOR
amobbs, Freescale
ACKNOWLEDGE
Armok
- 2015-2-15
a. 更新Joint类,增加Time属性可以控制动作在指定的时间内精确的完成,大幅度提升蜘蛛舞蹈的时间精度。
工程模板需要在IAR7.x下编译,单击这里下载:
特别说明,工程文件在“SpiderRobot_Template\application\template\build_iar”下面
- 2015-2-04
a. 更新第一版舞蹈
http://v.youku.com/v_show/id_XODg2MDIwOTA0.html
讨论在这里
http://www.amobbs.com/forum.php? ... p;page=1#pid8405770
感谢sunfulong的精彩作品!
- 2015-1-28
a. 发布工程模板v1.4a
- 提供宏模板,用以将指定的动作重复指定的次数,范例:
- ACTION_REPEATE( REF_ACTION(Spider_Go_Front), //!< target action
- 10, //!< times
- REF_STATE(Spider_Action1));
复制代码
重复执行动作(Spider_Go_Front)10次,完成后直接切换到Spider_Action1状态
- 提供宏模板,用以延时指定的时间(非阻塞延时),范例:
- ACTION_DELAY_MS(4000, //!< delay time in ms
- REF_STATE(Spider_Action2)); //!< next state
复制代码
延时4000ms,完成后直接切换到Spider_Action2状态
- 提供脚本模式,并提供范例脚本,演示了重复前进10步,延时4秒,后退10步,前进一步的简单脚本
- /*! \brief play action script
- *! \param none
- *! \return access result
- */
- bool play_action_script(void)
- {
- utilitis_init();
- return NEW_FSM(SpiderPlay, REF_STATE(Spider_Init));
- }
- IMPLEMENT_FSM(SpiderPlay)
- PRIVATE STATE(Spider_Init) BEGIN
-
- IO_CFG(
- {PB20, IO_WORKS_AS_GPIO, IO_PULL_UP},
- );
- GSP_PORTB.DIR &= ~PB20_MSK;
-
- TRANSFER_TO_STATE(Spider_Wait_for_Trigger);
- EXIT_STATE;
- END
- PRIVATE STATE(Spider_Wait_for_Trigger) BEGIN
-
- //! press key to start
- if (!(GSP_PORTB.IN & PB20_MSK)) {
- TRANSFER_TO_STATE(Spider_Play);
- }
- REFLEXIVE_STATE
- END
- PRIVATE STATE(Spider_Play) BEGIN
-
- ACTION_REPEATE( REF_ACTION(Spider_Go_Front), //!< target action
- 10, //!< times
- REF_STATE(Spider_Action1));
- EXIT_STATE;
- END
- PRIVATE STATE(Spider_Action1) BEGIN
- ACTION_DELAY_MS(4000, //!< delay time in ms
- REF_STATE(Spider_Action2)); //!< next state
- EXIT_STATE
- END
- PRIVATE STATE(Spider_Action2) BEGIN
- ACTION_REPEATE(REF_ACTION(Spider_Go_Back), 10, REF_STATE(Spider_Action3));
- EXIT_STATE
- END
- PRIVATE STATE(Spider_Action3) BEGIN
- CALL_ACTION_EX( REF_ACTION(Spider_Go_Front), //!< target action
- REF_STATE(Spider_Action4)); //!< next
- EXIT_STATE
- END
- PRIVATE STATE(Spider_Action4) BEGIN
- //! performance complete!!! wait for trigger again
- TRANSFER_TO_STATE(Spider_Wait_for_Trigger);
- EXIT_STATE
- END
-
- END_IMPLEMENT_FSM
复制代码
b. 整理工程架构,提供动作模板和脚本模板
这里actions文件夹保存了所有的单元动作脚本,你可以通过action_template.c作为模板建立新的单元动作。
步骤如下:
1. 复制action_template.c,并重新命名为action_xxxxxx.c,这里xxxxx是新单元动作的名字
2. 利用action_xxxxxxx.c里面的模板完成动作的编写
3. 再actions.h里面加入新动作的声明,例如:
- EXTERN_ACTION(Spider_Go_Front);
- EXTERN_ACTION(Spider_Go_Back);
- EXTERN_ACTION(Spider_XXXXX);
复制代码
script.c就是我们编写舞蹈脚本的地方,里面已经放入了Demo的最简单脚本。所有在actions.h里面加入的
动作在这里都可以直接使用。你可以方便的对某些动作进行重复,加入延时,等等。
c. 修正了随机偶发的动作无法正确执行的错误
d. 提供控制台模式
- 用户可以通过控制台绕过上层系统直接对目标舵机进行控制
-用户可以通过控制台对单个joint进行校准
工程模板需要在IAR7.x下编译,单击这里下载:
特别说明,工程文件在“SpiderRobot_Template\application\template\build_iar”下面
- 2015-1-4
a. 完成硬件的基本调试。完成基本充放电循环测试。完成基本舵机负载测试。由于买骨架的时候忘记拍螺丝了,
目前只能干瞪眼,哈哈哈……淘宝卖家说单独买螺丝要15RMB一包,且只能直接用支付宝转账……心头一丝
疑虑,然后我有问,可否我拍下一个别的东西,然后你改下价格?对方说,我拍什么,仓库出什么……
所以决定等老陈的蜘蛛骨架。
感谢yiming988牺牲业余时间完成了新版蜘蛛的驱动电路。感谢老陈对硬件设计做出的指导。
上图:
- 2014-12-29
a. 拿到了完全重新设计的驱动电路PCB。新的PCB上加入了两并18650电池的可编程充电和保护电路,并
直接使用mini USB进行充电,去掉了普通的DC电源接口,这样设计的目的是可以充分利用大家积攒在抽屉
里的各种手机平板充电器,包括各类充电宝。我们在PCB背面加入了一个2并 电池盒的封装,从而将重心
集中在蜘蛛的中轴上,从而平衡各个关节的受力,并尽可能降低重心,同时解决蜘蛛的供电问题。
新的电路设计由老陈监督,即便如此,错误和 疏漏也可能在所难免,如果大家发现了问题,请及时帮助我们,
我们有耐心,会坚持一版一版的加以改进。
- 2014-11-24
a. 收到飞思卡尔官方寄回的改进版蜘蛛 V1 Plus 开源项目重启。
通过这个改进版的蜘蛛,我们发现同样是10RMB的舵机……这品质差别咋就这么大捏~
飞思卡尔委托第三方“剽窃者剽窃者剽窃者剽窃者剽窃者剽窃者剽窃者剽窃者剽窃者蓝宙”进行了骨架的细小改进,并修正了我们硬件上的错误。非常感谢。另外,这
舵机……这尼玛舵机……真的是10RMB……真爽啊……哈哈哈哈,推荐莫老大搞一批咱们可以做活动了。
- 2014-9-3
a. 更新cerebel
1. 将cerebel抽象出来,剥离了与18舵机系统的强耦合,使其成为32以内舵机系统的通用控制服务模块
对Joint的初始化和校准部分被从cerebel服务中剥离开来,放在templete.c中。
2. 在cerebel内部加入了动作缓冲队列,用户通过CEREBEL.Move() 方法传入的Actions可以是栈分配的
局部变量,也就是说使用ACTION宏的时候,填充的内容不必是编译时刻就确定了的常量,可以是变
量,或者其它运行时刻经过计算获得的值。通过缓冲队列,用户可以源源不断的加入事先编排好的动
作序列而不必等待先前加入的动作完成。
b. 更新Joint
增加了一个接口IsComplete
- //! \name joint interface
- //! @{
- DEF_INTERFACE(i_joint_t)
- bool (*Init) (joint_t *ptJoint, const joint_cfg_t *ptCFG);
- void (*Finish) (joint_t *ptJoint);
- bool (*Start) (joint_t *ptJoint);
- bool (*Stop) (joint_t *ptJoint);
- const joint_cfg_t *(*Info) (joint_t *ptJoint);
- bool (*TurnTo) (joint_t *ptJoint, int32_t nAngle, int32_t nSpeed);
- bool (*TurnToInTime) (joint_t *ptJoint, int32_t nAngle, uint32_t wTime);
- struct {
- bool (*Set) (joint_t *ptJoint, int32_t nAngle);
- int32_t (*Get) (joint_t *ptJoint);
- } Angle;
- struct {
- bool (*Set) (joint_t *ptJoint, int32_t nSpeed);
- int32_t (*Get) (joint_t *ptJoint);
- } AngularSpeed;
- void (*TimerServiceRoutine)(void);
- struct {
- bool (*Register) (joint_t *ptJoint, DELEGATE_HANDLE *ptHandler);
- bool (*Unregister) (joint_t *ptJoint, DELEGATE_HANDLE *ptHandler);
- bool (*IsComplete) (joint_t *ptJoint);
- }ActionCompleteEvent;
- END_DEF_INTERFACE(i_joint_t)
- //! @}
复制代码
工程模板需要在IAR7.x下编译,单击这里下载:
特别说明,工程文件在“SpiderRobot_Template\application\template\build_iar”下面
- 2014-8-31
a. 完成了时间插补算法,更新了Joint算法
b. 增加了一个运动控制服务cerebel
通过cerebel我们可以抽象出Action的概念。Action是多个舵机的在某个时刻的运动状态片段,就好比你通过
摄像机拍摄高速运动的蜘蛛可以获得一系列的照片一样,在这个照片上,每个关节(Joint)都有对应的位置,
而Action就是这样的照片。cerebel的思路是,我们只要给它提供一系列的照片,并告诉他播放照片的速度,
cerebel就会自动的按照指定的时间播放动作,例如,下面就是一连串代表前进的动作:
- ACTION_CFG(
-
- ACTION(
- ALL_LEGS_MSK ,
- true, //!< start automatically
- 1 << JOINT_TIME_UNIT_RESOLUTION, //!< Use 1s
- {
- [LEFT_FRONT_LEG_0] = 135,
- [LEFT_MIDDLE_LEG_0] = 180,
- [LEFT_BACK_LEG_0] = 225,
- [RIGHT_FRONT_LEG_0] = 45,
- [RIGHT_MIDDLE_LEG_0] = 0,
- [RIGHT_BACK_LEG_0] = 315,
- [LEFT_FRONT_LEG_1] = 200,
- [LEFT_MIDDLE_LEG_1] = 200,
- [LEFT_BACK_LEG_1] = 200,
- [RIGHT_FRONT_LEG_1] = 335,
- [RIGHT_MIDDLE_LEG_1] = 335,
- [RIGHT_BACK_LEG_1] = 335,
- [LEFT_FRONT_LEG_2] = 115,
- [LEFT_MIDDLE_LEG_2] = 120,
- [LEFT_BACK_LEG_2] = 115,
- [RIGHT_FRONT_LEG_2] = 65,
- [RIGHT_MIDDLE_LEG_2] = 65,
- [RIGHT_BACK_LEG_2] = 65,
- }
- ),
- ACTION(
- TRI_LEGS_L1_MSK | TRI_LEGS_L0_MSK | TRI_LEGS_R1_MSK | TRI_LEGS_R2_MSK,
- true, //!< start automatically
- 1 << JOINT_TIME_UNIT_RESOLUTION, //!< Use 1s
- {
- [LEFT_FRONT_LEG_1] = 225,
- [LEFT_BACK_LEG_1] = 225,
- [RIGHT_MIDDLE_LEG_1] = 315,
- [LEFT_FRONT_LEG_0] = 135,
- [LEFT_BACK_LEG_0] = 180,
- [RIGHT_MIDDLE_LEG_0] = 23,
- [RIGHT_FRONT_LEG_1] = 0,
- [RIGHT_BACK_LEG_1] = 0,
- [LEFT_MIDDLE_LEG_1] = 180,
- [RIGHT_FRONT_LEG_2] = 90,
- [RIGHT_BACK_LEG_2] = 90,
- [LEFT_MIDDLE_LEG_2] = 90,
- }
- ),
- ACTION(
- TRI_LEGS_L1_MSK | TRI_LEGS_L2_MSK,
- true, //!< start automatically
- 1 << JOINT_TIME_UNIT_RESOLUTION, //!< Use 1s
- {
- [LEFT_FRONT_LEG_1] = 180,
- [LEFT_BACK_LEG_1] = 180,
- [RIGHT_MIDDLE_LEG_1] = 0,
- [LEFT_FRONT_LEG_2] = 90,
- [LEFT_BACK_LEG_2] = 90,
- [RIGHT_MIDDLE_LEG_2] = 90,
- }
- ),
- ACTION(
- TRI_LEGS_L0_MSK | TRI_LEGS_R0_MSK,
- true, //!< start automatically
- 1 << JOINT_TIME_UNIT_RESOLUTION, //!< Use 1s
- {
- [LEFT_FRONT_LEG_0] = 180 - 23,
- [LEFT_BACK_LEG_0] = 225,
- [RIGHT_MIDDLE_LEG_0] = 338,
-
- [RIGHT_FRONT_LEG_0] = 0,
- [RIGHT_BACK_LEG_0] = 270,
- [LEFT_MIDDLE_LEG_0] = 225,
- }
- ),
- ACTION(
- TRI_LEGS_R0_MSK | TRI_LEGS_R1_MSK | TRI_LEGS_R2_MSK,
- true, //!< start automatically
- 1 << JOINT_TIME_UNIT_RESOLUTION, //!< Use 1s
- {
- [RIGHT_FRONT_LEG_0] = 45,
- [RIGHT_BACK_LEG_0] = 350,
- [LEFT_MIDDLE_LEG_0] = 180 - 23,
- [RIGHT_FRONT_LEG_1] = 315,
- [RIGHT_BACK_LEG_1] = 315,
- [LEFT_MIDDLE_LEG_1] = 200,
- [RIGHT_FRONT_LEG_2] = 45,
- [RIGHT_BACK_LEG_2] = 45,
- [LEFT_MIDDLE_LEG_2] = 135,
- }
- ),
- ACTION(
- TRI_LEGS_R1_MSK | TRI_LEGS_R2_MSK,
- true, //!< start automatically
- 1 << JOINT_TIME_UNIT_RESOLUTION, //!< Use 1s
- {
- [RIGHT_FRONT_LEG_1] = 0,
- [RIGHT_BACK_LEG_1] = 0,
- [LEFT_MIDDLE_LEG_1] = 180,
- [RIGHT_FRONT_LEG_2] = 90,
- [RIGHT_BACK_LEG_2] = 90,
- [LEFT_MIDDLE_LEG_2] = 90,
- }
- ),
- ACTION(
- TRI_LEGS_R0_MSK | TRI_LEGS_L0_MSK | TRI_LEGS_L1_MSK | TRI_LEGS_L2_MSK,
- true, //!< start automatically
- 1 << JOINT_TIME_UNIT_RESOLUTION, //!< Use 1s
- {
- [LEFT_FRONT_LEG_0] = 135,
- [LEFT_BACK_LEG_0] = 180,
- [RIGHT_MIDDLE_LEG_0] = 23,
- [LEFT_FRONT_LEG_1] = 225,
- [LEFT_BACK_LEG_1] = 225,
- [RIGHT_MIDDLE_LEG_1] = 315,
- [LEFT_FRONT_LEG_2] = 135,
- [LEFT_BACK_LEG_2] = 135,
- [RIGHT_MIDDLE_LEG_2] = 45,
- [RIGHT_FRONT_LEG_0] = 0,
- [RIGHT_BACK_LEG_0] = 315,
- [LEFT_MIDDLE_LEG_0] = 180 + 22,
- }
- ),
- );
复制代码
这里ACTION_CFG和ACTION宏是对cerebel的封装,详细封装方法请参考cerebel.h。通过cerebel蜘蛛的运动
就可以通过“照片”的方式描述下来,而照片与照片之间的部分则由cerebel和joint的时间插补算法自动处理,
从而产生平滑的运动(运动的快慢由照片与照片之间的时间间隔来控制)。
这里,我详细介绍下ACTION_CFG和ACTION的使用方法。
首先,我们必须对整个蜘蛛建立一个统一的数学模型,不然我们就没有一个统一的标准来描述舵机的位置:
根据这个位置,我们首先要完成对舵机的角度映射,这里我们要借助Joint类,Joint初始化中要根据图中标识
的范围来设置角度的Offset,舵机的实际运动范围等等,下面,我们以右后腿为例,介绍Joint的初始化:
- JOINT_CFG(
- this.ptJoints[RIGHT_BACK_LEG_0],
- RIGHT_BACK_LEG_0,
- 225, //!< offset
- 0, //!< start angle
- 180, //!< end angle
- 180, //!< Max Angular Speed
- 315, //!< Reset Position
- 1024, //!< K
- );
-
复制代码
结合上面的图,我们知道右后腿(RIGHT_BACK_LEG_0,这里的0,1,2表示每个腿由身体一次向外的3个关节),
的运动范围是225°~45°的180度范围。所以,我们将offset配置为225。舵机的实际运动范围就是0°~180°。
这里,我们还配置了最大的角速度为180°/s,关节复位时候关节的角度315°。关于起始角和终止角,这个实际
上是用来限定舵机的安全运动范围的,比如虽然舵机可以0°~180°之间运动,但有时候,机械上并不允许这么
大的运动范围,所以必须要限定一个起始角和终止角。以右后腿为例,为了防止右后腿和右中退产生碰撞,我
们限定右后腿的实际运动范围是45°~135°(90°范围),修改后的初始化如下:
- JOINT_CFG(
- this.ptJoints[RIGHT_BACK_LEG_0],
- RIGHT_BACK_LEG_0,
- 225, //!< offset
- 45, //!< start angle
- 135, //!< end angle
- 180, //!< Max Angular Speed
- 315, //!< Reset Position
- 1024, //!< K
- );
-
复制代码
不幸的是10块钱的舵机线性度太差,所以,我们需要根据安装的实际情况对舵机的角度进行两点矫正,矫正
方法如下:
1、首先将起始角和终止角分别设定为0°和180°,并通过复位位置将舵机运动到第一个点,比如270°的点
- JOINT_CFG(
- this.ptJoints[RIGHT_BACK_LEG_0],
- RIGHT_BACK_LEG_0,
- 225, //!< offset
- 0, //!< start angle
- 180, //!< end angle
- 180, //!< Max Angular Speed
- 270, //!< Reset Position
- 1024, //!< K
- );
-
复制代码
修正offset使得关节物理上到达270°。我的舵机修正的结果如下:
- JOINT_CFG(
- this.ptJoints[RIGHT_BACK_LEG_0],
- RIGHT_BACK_LEG_0,
- 222, //!< offset
- 0, //!< start angle
- 180, //!< end angle
- 180, //!< Max Angular Speed
- 270, //!< Reset Position
- 1024, //!< K
- );
复制代码
每个舵机都是不同的,你需要自己校准。完成上述步骤后,计算出实际的起始角,并更新起始角和终止角的信
息:start_angle = first_angle_point - offset。例如我们第一点是270°,offset是222度,那么起始角就是48°
(48 = 270°- 222),更新配置如下:
- JOINT_CFG(
- this.ptJoints[RIGHT_BACK_LEG_0],
- RIGHT_BACK_LEG_0,
- 222, //!< offset
- 48, //!< start angle
- 180, //!< end angle
- 180, //!< Max Angular Speed
- 270, //!< Reset Position
- 1024, //!< K
- );
复制代码
修改复位值,使关节运动到下一个校准点,比如0°,这个时候,这里的K就发挥作用了,修改比例K来调整实际
的物理位置,使关节运动到0°。至此,我们就完成了一个关节的校准,我的校准结果如下:
- JOINT_CFG(
- this.ptJoints[RIGHT_BACK_LEG_0],
- RIGHT_BACK_LEG_0,
- 222, //!< offset
- 48, //!< start angle
- 138, //!< end angle
- 180, //!< Max Angular Speed
- 315, //!< Reset Position
- 900, //!< K
- );
复制代码
也许你已经意识到了,这个校准真TMD的坑啊……18个舵机都要这么校准……而且离开量角器……用肉眼看角度有
多苦逼你可以想象的吧?而且10块钱的舵机还有温票啊……温票啊……漂啊……啊……如果你和我一样处女座,喜
欢精确——恭喜你……对了对了——忘记给你说了,机械上有个概念叫做回程差……也就是说,你从不同的方向运
动到同一个角度实际上停下来的位置是不同的……这种情况下,你只能祈祷,舵机不要坏,我不用再换一个……
到了这里,大约用了4个小时,你就可以完成全部18个舵机的校准。这下我们可以很开心的通过JOINT的接口来
指挥关节运动到指定的角度了,这里的角度参考图上的坐标系,不用担心实际舵机自己的坐标系,接口如下:
- //! \name joint interface
- //! @{
- DEF_INTERFACE(i_joint_t)
- bool (*Init) (joint_t *ptJoint, const joint_cfg_t *ptCFG);
- void (*Finish) (joint_t *ptJoint);
- bool (*Start) (joint_t *ptJoint);
- bool (*Stop) (joint_t *ptJoint);
- const joint_cfg_t *(*Info) (joint_t *ptJoint);
- bool (*TurnTo) (joint_t *ptJoint, int32_t nAngle, int32_t nSpeed);
- bool (*TurnToInTime) (joint_t *ptJoint, int32_t nAngle, uint32_t wTime);
- struct {
- bool (*Set) (joint_t *ptJoint, int32_t nAngle);
- int32_t (*Get) (joint_t *ptJoint);
- } Angle;
- struct {
- bool (*Set) (joint_t *ptJoint, int32_t nSpeed);
- int32_t (*Get) (joint_t *ptJoint);
- } AngularSpeed;
- void (*TimerServiceRoutine)(void);
- struct {
- bool (*Register) (joint_t *ptJoint, DELEGATE_HANDLE *ptHandler);
- bool (*Unregister) (joint_t *ptJoint, DELEGATE_HANDLE *ptHandler);
- }ActionCompleteEvent;
- END_DEF_INTERFACE(i_joint_t)
- //! @}
- extern const i_joint_t JOINT;
复制代码
这里,我们可以直接用JOINT.TurnTo() 方法来将关节以指定的速度运动到指定的绝对角度;也可以使用
JOINT.TurnToInTime()方法将关节在指定的时间内匀速的运动到指定的角度。这里的时间(wTime)单位
是1/8秒。写8或者(1<<JOINT_TIME_UNIT_RESOLUTION) 就是1秒。另外,你也可以通过JOINT.Angle.Set()
来指定关节的角度,通过JOINT.Angle.Get()来实时获取当前的角度。这里需要说明下,以上介绍的方法,
并不会立即生效,一定要调用JOINT.Start() 让新的设置生效,当然你也可以随时调用JOINT.Stop()来个
急刹车。
最后,补充说明下JOINT.TurnTo()是速度插补算法,JOINT.TurnToInTime() 是时间插补算法,认真说来
时间插补算法更有用,但实际上时间插补算法是建立在速度插补算法之上的,大家可以参考我的源代码。
这里的速度插补算法产生的是匀速运动,如果你想产生一个S型加减速,可以自己实现一个,我个人觉得
这对时间插补算法应该是没有影响的——如果你封装的好的话。
好,言归正传,我们来说说cerebel咋用。首先你要定义18个Joint,然后通过CEREBEL_CFG对他们初始化,
实际上,我们辛辛苦苦校准好的舵机信息就在cerebel服务的初始化函数里面:
- NO_INIT static joint_t s_tJoints[18];
- ...
- static void spider_init(void)
- {
- //! initialize servo service
- SERVO.Init ();
- SERVO.Start ();
-
- //! initialize cerebel layer
- CEREBEL_CFG(
- s_tJoints,
- UBOUND(s_tJoints),
- );
- ...
- }
复制代码
接下来,我们就可以用ACTION_CFG和ACTION来设计舵机动作了,这里就着这两个宏的定义,介绍下各个参数
的意义:
- #define ACTION(__MSK, __AUTO, __TIME, ...) \
- { \
- (__MSK), \
- (__AUTO), \
- (__TIME), \
- .nAngles = __VA_ARGS__, \
- }
- #define ACTION_CFG(...) \
- do { \
- static cerebel_action_t tActions[] = {__VA_ARGS__}; \
- CEREBEL.Action.Move(tActions, UBOUND(tActions)); \
- } while(false)
复制代码
从代码里很容易知道ACTION_CFG并没有什么神秘的,只是用了C99对可变参数宏的一个技巧,也就是"..."对应
__VA_ARGS__。这个宏定义了一个静态的照片(Actions)数组,并调用了CEREBEL.Action.Move方法。
ACTION()有三个参数,分别是:
__MSK: 用以指定后面的角度配置列表中哪些角度配置是有效的,具体参考template\interface.h里面的joint_msk_t
__AUTO: 用以指定当前Action是否立即生效(true表示立即生效,false则要调用CEREBEL.Start()才会生效)
__TIME: 时间插补算法参数,单位是1/8秒。简单说就是多长时间内匀速完成这个Action。
... : 这个就是具体的角度配置明细表了,我们看一个例子:
- ACTION_CFG(
- ACTION(
- TRI_LEGS_L1_MSK | TRI_LEGS_L2_MSK,
- true, //!< start automatically
- 1 << JOINT_TIME_UNIT_RESOLUTION, //!< Use 1s
- {
- [LEFT_FRONT_LEG_1] = 180,
- [LEFT_BACK_LEG_1] = 180,
- [RIGHT_MIDDLE_LEG_1] = 0,
- [LEFT_FRONT_LEG_2] = 90,
- [LEFT_BACK_LEG_2] = 90,
- [RIGHT_MIDDLE_LEG_2] = 90,
- }
- ),
- );
复制代码
这个ACTION涉及到三条腿(左前,左后,右中三条腿组成的三角形,TRI_LEG_Ln, 这里n取0,1,2),动作立即
生效,1秒钟内匀速完成。后面花括号里面是具体每个关节的角度信息,需要注意的是,这里的关节是与前面的MSK
相对应的,例如TRI_LEGS_L1_MSK 和TRI_LEGS_L2_MSK的实际内容是:
- typedef enum {
- ...
- TRI_LEGS_L1_MSK = ( LEFT_FRONT_LEG_1_MSK |
- LEFT_BACK_LEG_1_MSK |
- RIGHT_MIDDLE_LEG_1_MSK ),
- TRI_LEGS_L2_MSK = ( LEFT_FRONT_LEG_2_MSK |
- LEFT_BACK_LEG_2_MSK |
- RIGHT_MIDDLE_LEG_2_MSK ),
- ...
- ) joint_msk_t;
-
复制代码
OK,到了这里,小伙伴们,平台已经搭建完成,请愉(tong)快(ku)的(de)玩(bei)耍(nue)吧。硬件
坏了,舵机烧了,我去愉快的画圈圈去了……我靠……^%^*+#€£><#{&$@
工程模板需要在IAR7.x下编译,单击这里下载:
特别说明,工程文件在“SpiderRobot_Template\application\template\build_iar”下面
- 2014-8-30
a. 经过一天的冲刺,终于完成了蜘蛛每一个舵机的校准——真心累啊
心得:10块钱的舵机,一致性真心差,还有温漂……你让他运动90度(不是运动到90度),不同的舵机会走出
完全不同的角度来……不得不用了线性补偿算法,这是今天一天的成果……累死人啊……如果大家以后玩这个套
件,每一套都要自己辛苦校准的。
- do {
- NO_INIT static joint_t s_tJoint[18];
- NO_INIT static DELEGATE_HANDLE s_tHandler;
- // SERVO.Angle(RIGHT_BACK_LEG_2, 90);
- JOINT_CFG(
- s_tJoint[LEFT_BACK_LEG_2],
- LEFT_BACK_LEG_2,
- 355, //!< offset
- 50, //!< start angle
- 140, //!< end angle
- 180, //!< Max Angular Speed
- 90, //!< Reset Position
- 680, //!< K
- );
- JOINT_CFG(
- s_tJoint[LEFT_MIDDLE_LEG_2],
- LEFT_MIDDLE_LEG_2,
- 353, //!< offset
- 52, //!< start angle
- 142, //!< end angle
- 180, //!< Max Angular Speed
- 90, //!< Reset Position
- 660, //!< K
- );
- JOINT_CFG(
- s_tJoint[LEFT_FRONT_LEG_2],
- LEFT_FRONT_LEG_2,
- 353, //!< offset
- 52, //!< start angle
- 142, //!< end angle
- 180, //!< Max Angular Speed
- 90, //!< Reset Position
- 680, //!< K
- );
- JOINT_CFG(
- s_tJoint[RIGHT_BACK_LEG_2],
- RIGHT_BACK_LEG_2,
- 355, //!< offset
- 50, //!< start angle
- 140, //!< end angle
- 180, //!< Max Angular Speed
- 90, //!< Reset Position
- 780, //!< K
- );
- JOINT_CFG(
- s_tJoint[RIGHT_MIDDLE_LEG_2],
- RIGHT_MIDDLE_LEG_2,
- 0, //!< offset
- 45, //!< start angle
- 135, //!< end angle
- 180, //!< Max Angular Speed
- 90, //!< Reset Position
- 860, //!< K
- );
- JOINT_CFG(
- s_tJoint[RIGHT_FRONT_LEG_2],
- RIGHT_FRONT_LEG_2,
- 354, //!< offset
- 51, //!< start angle
- 141, //!< end angle
- 180, //!< Max Angular Speed
- 90, //!< Reset Position
- 840, //!< K
- );
- JOINT_CFG(
- s_tJoint[RIGHT_BACK_LEG_1],
- RIGHT_BACK_LEG_1,
- 275, //!< offset
- 40, //!< start angle
- 180, //!< end angle
- 180, //!< Max Angular Speed
- 0, //!< Reset Position
- 1100, //!< K
- );
- JOINT_CFG(
- s_tJoint[RIGHT_MIDDLE_LEG_1],
- RIGHT_MIDDLE_LEG_1,
- 275, //!< offset
- 40, //!< start angle
- 180, //!< end angle
- 180, //!< Max Angular Speed
- 0, //!< Reset Position
- 1024, //!< K
- );
- JOINT_CFG(
- s_tJoint[RIGHT_FRONT_LEG_1],
- RIGHT_FRONT_LEG_1,
- 260, //!< offset
- 55, //!< start angle
- 180, //!< end angle
- 180, //!< Max Angular Speed
- 0, //!< Reset Position
- 970, //!< K
- );
- JOINT_CFG(
- s_tJoint[RIGHT_BACK_LEG_0],
- RIGHT_BACK_LEG_0,
- 222, //!< offset
- 48, //!< start angle
- 138, //!< end angle
- 180, //!< Max Angular Speed
- 315, //!< Reset Position
- 900, //!< K
- );
-
- JOINT_CFG(
- s_tJoint[RIGHT_MIDDLE_LEG_0],
- RIGHT_MIDDLE_LEG_0,
- 260, //!< offset
- 55, //!< start angle
- 145, //!< end angle
- 180, //!< Max Angular Speed
- 0, //!< Reset Position
- 850, //!< K
- );
- JOINT_CFG(
- s_tJoint[RIGHT_FRONT_LEG_0],
- RIGHT_FRONT_LEG_0,
- 313, //!< offset
- 47, //!< start angle
- 137, //!< end angle
- 180, //!< Max Angular Speed
- 45, //!< Reset Position
- 920, //!< K
- );
- JOINT_CFG(
- s_tJoint[LEFT_FRONT_LEG_0],
- LEFT_FRONT_LEG_0,
- 40, //!< offset
- 50, //!< start angle
- 140, //!< end angle
- 180, //!< Max Angular Speed
- 135, //!< Reset Position
- 890, //!< K
- );
- JOINT_CFG(
- s_tJoint[LEFT_MIDDLE_LEG_0],
- LEFT_MIDDLE_LEG_0,
- 80, //!< offset
- 55, //!< start angle
- 145, //!< end angle
- 180, //!< Max Angular Speed
- 180, //!< Reset Position
- 920, //!< K
- );
- JOINT_CFG(
- s_tJoint[LEFT_BACK_LEG_0],
- LEFT_BACK_LEG_0,
- 142, //!< offset
- 38, //!< start angle
- 128, //!< end angle
- 180, //!< Max Angular Speed
- 225, //!< Reset Position
- 1130, //!< K
- );
- JOINT_CFG(
- s_tJoint[LEFT_BACK_LEG_1],
- LEFT_BACK_LEG_1,
- 105, //!< offset
- 20, //!< start angle
- 110, //!< end angle
- 180, //!< Max Angular Speed
- 180, //!< Reset Position
- 1100, //!< K
- );
- JOINT_CFG(
- s_tJoint[LEFT_MIDDLE_LEG_1],
- LEFT_MIDDLE_LEG_1,
- 90, //!< offset
- 45, //!< start angle
- 135, //!< end angle
- 180, //!< Max Angular Speed
- 180, //!< Reset Position
- 950, //!< K
- );
- JOINT_CFG(
- s_tJoint[LEFT_FRONT_LEG_1],
- LEFT_FRONT_LEG_1,
- 80, //!< offset
- 55, //!< start angle
- 145, //!< end angle
- 180, //!< Max Angular Speed
- 180, //!< Reset Position
- 850, //!< K
- );
- } while(false);
复制代码
b. 终于能站起来了……发图庆贺
明日计划:
a. 完成运动的时间插补算法——简单说就是给定每个关节目标角度以及多长时间内到达目标角度,算法会自动
调整角速度使得关节在指定的时间点匀速运动到指定的角度。
b. 借助时间插补算法,我需要采样至少6组舵舵机的运动角度信息(每组18个舵机的角度信息),然后以播放
的形式实现前进的动作。对于后退的动作也需要6组这样的采样点。同理,左转,右转,向左横着走,向右
横着走。愿主保佑我能顺利完成。
- 2014-8-27
a. 更新工程模板
> 修正了舵机控制的BUG
> 增加了一个舵机运动插补和极坐标系映射的服务Joint
Joint服务是一个运动插补的服务,它使得我们可以让指定的舵机以指定的角速度(度/秒)
平滑的运动到指定的绝对角度。每个舵机的运动范围是0~180度,但是随着安装位置的不同
舵机实际上缺乏一个相对同一个坐标系的绝对角度的定位能力。所以,一旦完成了舵机的
安装,我们就可以借助Joint服务来给舵机指定绝对的角度——当然,舵机实际可以运动的
角度范围之差不会超过180度。
- static void servo_demo(void)
- {
- SERVO.Init ();
- SERVO.Start ();
- do {
- NO_INIT static joint_t s_tJoint[18];
- NO_INIT static DELEGATE_HANDLE s_tHandler;
- JOINT_CFG(
- s_tJoint[0],
- LEFT_BACK_LEG_0,
- 45, //!< offset
- 0, //!< start angle
- 180, //!< end angle
- 180, //!< Max Angular Speed
- 135,
- );
- } while(false);
- }
复制代码
这是一个Joint服务的例子,从初始化可以看出,目标舵机是左后腿的第一个关节(LEFT_BACK_LEG_0),
相对蜘蛛的绝对坐标系,这个关节的实际运动角度范围是(45+0°)~(45+180°),最大允许的角速度
是180°/s,复位状态下关节的绝对角度是135°。
这段代码随后在完成初始化后,又命令关节s_tJoint[0]以45°/s的速度平滑的运动到绝对角度45°。
- JOINT.TurnTo(&s_tJoint[0], 45, 45);
复制代码
Joint服务还提供运动完成事件,用户可以注册事件处理程序(一个事件可以同时注册多个事件处理程序):
- //! \brief joint action complete event handler
- static fsm_rt_t joint_action_complete_event_handler(void *pArg, void *pParam)
- {
- joint_t *ptJoint = (joint_t *)pArg;
- static bool s_bFlag = false;
- if (s_bFlag) {
- JOINT.TurnTo(ptJoint, 45, 45);
- } else {
- JOINT.TurnTo(ptJoint, 135, 45);
- }
- s_bFlag = !s_bFlag;
- return fsm_rt_cpl;
- }
- static void servo_demo(void)
- {
- ...
- do {
- ...
- NO_INIT static DELEGATE_HANDLE s_tHandler;
- ...
- delegate_handler_init( &s_tHandler,
- &joint_action_complete_event_handler,
- &s_tJoint[0] );
- JOINT.ActionCompleteEvent.Register(&s_tJoint[0], &s_tHandler);
- } while(false);
- ...
- }
复制代码
这里函数joint_action_complete_event_handler()是s_tJoint[0]的运动完成事件处理函数,我们在这个
事件处理程序里面用了类似乒乓操作的方式,让关节在45°和135°之间来回运动。注册事件需要借助
DELEGATE_HANDLE类型的对象的帮助,我们需要先初始化它,告诉他事件处理函数是什么,要附带
的对象是什么(这里我们把当前的Joint对象作为参数传递给了事件处理程序)。通过register方法,
我们可以很方便的注册事件处理程序。
Joint服务需要两个接口的支持,一个是1024分之一秒的定时中断服务,一个是用来设置指定舵机的角度
的函数。前者我们通过SysTick的中断处理程序来实现,后者我们封装了一个接口适配器:
- ISR(SysTick_Handler)
- {
- static uint32_t s_wCounter;
- s_wCounter++;
- if (!(s_wCounter & (_BV(10) - 1))) {
- /* run code every 1s here, you can add debug code here*/
- }
- JOINT.TimerServiceRoutine();
- }
- /*! \note initialize application
- * \param none
- * \retval true hal initialization succeeded.
- * \retval false hal initialization failed
- */
- ROOT bool app_init(void)
- {
- servo_demo();
- /*! you can put your code here */
- SYSTICK_CFG (
- ENABLE_SYSTICK |
- SYSTICK_SOURCE_SYSCLK |
- ENABLE_SYSTICK_INTERRUPT,
- (PM_GET_SYS_CLK() >> 10)
- );
- ENABLE_GLOBAL_INTERRUPT();
- //! start a new task
- return NEW_STATIC_FSM(DemoTask, REF_STATE(Demo_Init));
- }
- //! \brief interface adapter for joint service
- void joint_set_servo(joint_no_t tID, uint32_t wAngle)
- {
- SERVO.Angle(tID, wAngle);
- }
复制代码
通过这些接口Joint就能很好的为我们服务了。 下一步我们就可以利用Joint服务为每一个舵机建立一个Joint对象
从而提供统一的运动插补和坐标系映射服务。这为我们后面的矢量控制算法,以及PC/Andriod脚本控制平台提供
了准备。
附上Joint服务的接口定义:
- //! \name joint interface
- //! @{
- DEF_INTERFACE(i_joint_t)
- bool (*Init) (joint_t *ptJoint, const joint_cfg_t *ptCFG);
- void (*Finish) (joint_t *ptJoint);
- bool (*TurnTo)(joint_t *ptJoint, int32_t nAngle, int32_t nSpeed);
- struct {
- bool (*Set) (joint_t *ptJoint, int32_t nAngle);
- int32_t (*Get) (joint_t *ptJoint);
- } Angle;
- struct {
- bool (*Set) (joint_t *ptJoint, int32_t nSpeed);
- int32_t (*Get) (joint_t *ptJoint);
- } AngularSpeed;
- void (*TimerServiceRoutine)(void);
- struct {
- bool (*Register) (joint_t *ptJoint, DELEGATE_HANDLE *ptHandler);
- bool (*Unregister) (joint_t *ptJoint, DELEGATE_HANDLE *ptHandler);
- }ActionCompleteEvent;
- END_DEF_INTERFACE(i_joint_t)
- //! @}
复制代码
工程模板需要在IAR7.x下编译,单击这里下载:
特别说明,工程文件在“SpiderRobot_Template\application\template\build_iar”下面
- 2014-8-20
a. 更新了工程模板
> 使用了板载的50MHz外部时钟源
> 在工程模板中增加了SysTick产生1s中断的例子
- ISR(SysTick_Handler)
- {
- static uint32_t s_wCounter;
- s_wCounter++;
- if (!(s_wCounter & (_BV(10) - 1))) {
- /* run code every 1s here, you can add debug code here*/
- }
- }
- /*! \note initialize application
- * \param none
- * \retval true hal initialization succeeded.
- * \retval false hal initialization failed
- */
- bool app_init(void)
- {
- /*! you can put your code here */
- SYSTICK_CFG (
- ENABLE_SYSTICK |
- SYSTICK_SOURCE_SYSCLK |
- ENABLE_SYSTICK_INTERRUPT,
- (PM_GET_SYS_CLK() >> 10)
- );
- ENABLE_GLOBAL_INTERRUPT();
- servo_demo();
- //! start a new task
- return NEW_STATIC_FSM(DemoTask, REF_STATE(Demo_Init));
- }
复制代码
> 在工程模板中增加了三色LED的例子,用以演示状态机调度器的使用
- /*============================ MACROS ========================================*/
- #define TOP (0x01FF)
- /*============================ MACROFIED FUNCTIONS ===========================*/
-
- #define LED_RED_ON() do { GSP_PORTB.OUTCLR |= PB22_MSK; } while(false)
- #define LED_RED_OFF() do { GSP_PORTB.OUTSET |= PB22_MSK; } while(false)
- #define LED_GREEN_ON() do { GSP_PORTE.OUTCLR |= PE26_MSK; } while(false)
- #define LED_GREEN_OFF() do { GSP_PORTE.OUTSET |= PE26_MSK; } while(false)
- #define LED_BLUE_ON() do { GSP_PORTB.OUTCLR |= PB21_MSK; } while(false)
- #define LED_BLUE_OFF() do { GSP_PORTB.OUTSET |= PB21_MSK; } while(false)
- #define RGB(__R, __G, __B) \
- do { \
- set_led_red_gradation(__R); \
- set_led_green_gradation(__G); \
- set_led_blue_gradation(__B); \
- } while(false)
- #define LED_LIGHT 3
- #define LED_BREATH_SPEED 14
- /*! \brief set the 16-level led gradation
- *! \param hwLevel gradation
- *! \return none
- */
- static void set_led_red_gradation(uint16_t hwLevel)
- {
- static uint16_t s_hwCounter = 0;
-
- if (hwLevel >= s_hwCounter) {
- LED_RED_ON();
- } else {
- LED_RED_OFF();
- }
-
- s_hwCounter++;
- s_hwCounter &= TOP;
- }
- /*! \brief set the 16-level led gradation
- *! \param hwLevel gradation
- *! \return none
- */
- static void set_led_green_gradation(uint16_t hwLevel)
- {
- static uint16_t s_hwCounter = 0;
-
- if (hwLevel >= s_hwCounter) {
- LED_GREEN_ON();
- } else {
- LED_GREEN_OFF();
- }
-
- s_hwCounter++;
- s_hwCounter &= TOP;
- }
- /*! \brief set the 16-level led gradation
- *! \param hwLevel gradation
- *! \return none
- */
- static void set_led_blue_gradation(uint16_t hwLevel)
- {
- static uint16_t s_hwCounter = 0;
-
- if (hwLevel >= s_hwCounter) {
- LED_BLUE_ON();
- } else {
- LED_BLUE_OFF();
- }
-
- s_hwCounter++;
- s_hwCounter &= TOP;
- }
- static void breath_led(void)
- {
- static uint16_t s_hwCounter = 0;
- static int16_t s_nGrayRed = 0;
- static int16_t s_nGrayGreen = 0;
- static int16_t s_nGrayBlue = 0;
- s_hwCounter++;
- if (!(s_hwCounter & (_BV(LED_BREATH_SPEED)-1))) {
- s_nGrayRed++;
- if (s_nGrayRed == (TOP >> LED_LIGHT)) {
- s_nGrayRed = 0;
- }
- }
- if (!(s_hwCounter & (_BV(LED_BREATH_SPEED+1)-1))) {
- s_nGrayGreen++;
- if (s_nGrayGreen == (TOP >> LED_LIGHT)) {
- s_nGrayGreen = 0;
- }
- }
- if (!(s_hwCounter & (_BV(LED_BREATH_SPEED + 2)-1))) {
- s_nGrayBlue++;
- if (s_nGrayBlue == (TOP >> LED_LIGHT)) {
- s_nGrayBlue = 0;
- }
- }
- RGB(
- ABS(s_nGrayRed - (TOP >> (LED_LIGHT + 1))),
- ABS(s_nGrayGreen - (TOP >> (LED_LIGHT + 1))),
- ABS(s_nGrayBlue - (TOP >> (LED_LIGHT + 1)))
- );
- }
- /*! state machine implementation */
- IMPLEMENT_FSM(DemoTask)
- //! state: Demo_Init
- PRIVATE STATE(Demo_Init) BEGIN
- /*! put your application service code here */
- GSP_PORTB.DIR |= PB22_MSK | PB21_MSK;
- GSP_PORTE.DIR |= PE26_MSK;
- GSP_PORTB.OUTSET = PB22_MSK | PB21_MSK;
- GSP_PORTE.OUTSET = PE26_MSK;
- IO_CFG(
- {PB22, IO_WORKS_AS_FUNC1}, //!< LED Red
- {PE26, IO_WORKS_AS_FUNC1}, //!< LED Green
- {PB21, IO_WORKS_AS_FUNC1}, //!< LED Blue
- );
- TRANSFER_TO_STATE(Demo_Task);
- REFLEXIVE_STATE;
- END
- //! state: Demo Task
- PRIVATE STATE(Demo_Task) BEGIN
- /*! put your none-blocked task code here */
- breath_led();
- REFLEXIVE_STATE;
- END
- END_IMPLEMENT_FSM
复制代码
工程模板需要在IAR7.x下编译,单击这里下载:
特别说明,工程文件在“SpiderRobot_Template\application\template\build_iar”下面
- 2014-8-16
a. 完成了硬件调试,只有一个地方需要飞下线,还算不错,谢谢大家为我们的团队成员出谋划策,我们从中学习了很多
b. 完成了工程模板的第一个公测版Beta1
我们对舵机进行了封装,提供如下的接口:
- //! servo interface
- //! \name i_servo_t
- //! @{
- DEF_INTERFACE (i_servo_t)
- bool (*Init) (void);
- bool (*Deinit) (void);
- bool (*Finish) (void);
- bool (*Start) (void);
- bool (*Angle) (uint8_t chServoNum, uint32_t wAngle);
- END_DEF_INTERFACE (i_servo_t)
- //! @}
- /*============================ PROTOTYPES ====================================*/
- /*============================ GLOBAL VARIABLES ==============================*/
- extern const i_servo_t SERVO;
复制代码
使用起来也很简单,我们在template.c里面提供了代码范例:
- static void servo_demo(void)
- {
- SERVO.Init ();
-
- for (uint8_t n = 0; n <= 18; n++) {
- SERVO.Angle (n, 90);
- }
-
- SERVO.Start ();
- // SERVO.Angle (0, 90);
- // SERVO.Angle (1, 0);
- // SERVO.Angle (2, 45);
- // SERVO.Angle (3, 10);
- // SERVO.Angle (4, 20);
- // SERVO.Angle (5, 10);
- // SERVO.Angle (6, 15);
- // SERVO.Angle (7, 29);
-
- }
复制代码
我们这次以SDK的形式提供对这个平台的支持,用户将看不到main.c,也看不到main函数,对用户来说,应用所需
所有入口函数我们都提供了,例如硬件初始化,这个函数是main函数实际调用的第一个函数,其返回值决定了SDK默认
的一些底层初始化是否要执行,true表示要执行,false表示不再执行。目前默认的底层硬件初始化只是处理了一些时钟
上的配置,建议这里不要返回false。这个例子里面,我们展示了如何初始化IO,将其配置为对应的PWM功能。关于IO
的配置,请参考io.h。
- /*! \brief hardware initialization
- *! \param none
- *! \retval true run the default initialization
- *! \retval false ignore the default initialization
- */
- ROOT bool ON_HW_INIT(void)
- {
- /*! you can put your code here */
- IO_CFG(
- {PC1, IO_WORKS_AS_FUNC4},
- {PC2, IO_WORKS_AS_FUNC4},
- {PC3, IO_WORKS_AS_FUNC4},
- {PC4, IO_WORKS_AS_FUNC4},
- {PC8, IO_WORKS_AS_FUNC3},
- {PC9, IO_WORKS_AS_FUNC3},
- {PC10, IO_WORKS_AS_FUNC3},
- {PC11, IO_WORKS_AS_FUNC3},
- {PD0, IO_WORKS_AS_FUNC4},
- {PD1, IO_WORKS_AS_FUNC4},
- {PD2, IO_WORKS_AS_FUNC4},
- {PD3, IO_WORKS_AS_FUNC4},
- {PD4, IO_WORKS_AS_FUNC4},
- {PD5, IO_WORKS_AS_FUNC4},
- {PB18, IO_WORKS_AS_FUNC3},
- {PB19, IO_WORKS_AS_FUNC3},
- {PA1, IO_WORKS_AS_FUNC3},
- {PA2, IO_WORKS_AS_FUNC3},
- );
-
- return true;
- }
复制代码
用户另外一个要用到的就是应用初始化app_init。这个app_init是main函数完成所有既定的初始化工作以后,调用的
最后一个初始化函数——也就是用户自己的初始化函数。用户应该在这里做他自己想做的事情,但最后一定要起一个
状态机任务,就像例子里面提供的那样,不然,离开超级循环,大家怎么活?
- //! \brief demo task
- STATIC_FSM(DemoTask)
- PRIVATE STATE(Demo_Init);
- PRIVATE STATE(Demo_Task);
- END_STATIC_FSM
- ...
- /*! \note initialize application
- * \param none
- * \retval true hal initialization succeeded.
- * \retval false hal initialization failed
- */
- bool app_init(void)
- {
- servo_demo();
- //! start a new task
- return NEW_STATIC_FSM(DemoTask, REF_STATE(Demo_Init));
- }
- /*! state machine implementation */
- IMPLEMENT_FSM(DemoTask)
- //! state: Demo_Init
- PRIVATE STATE(Demo_Init) BEGIN
- /*! put your application service code here */
- TRANSFER_TO_STATE(Demo_Task);
- REFLEXIVE_STATE;
- END
- //! state: Demo Task
- PRIVATE STATE(Demo_Task) BEGIN
- /*! put your none-blocked task code here */
- REFLEXIVE_STATE;
- END
- END_IMPLEMENT_FSM
复制代码
工程模板需要在IAR7.x下编译,单击这里下载:
特别说明,工程文件在“SpiderRobot_Template\application\template\build_iar”下面
c. 由于我最近身体不舒服,在家休养,所以动作调试上耽搁了很多,团队的小伙伴很努力,本周稍后应该会有一个简单的
演示。
下一步计划:
a. 发布工程模板Beta2,提供与此次开源直接相关的蜘蛛运动控制相关的模块及其源代码,修正Beta1发现的问题
b. 完成基本的动作调试,考虑要不要重新做一版硬件来解决飞线的问题。
- 2014-8-9
a. 拿到了PCB,组装了下,还蛮好看的,硬件还在调试
b. 完成了K6x的工程模板,需要IAR7.x的支持,争取下周放出公测版
c. 初步完成单爪动作和封装
下一步计划:
a. 尝试用基本的单爪动作组合出所需的运动,比如,横着爬,前进后退等
b. 完成硬件调试
c. 开放工程模板公测
- 2014-8-3
a. PCB 已经送出去,粘贴原理图如下
特别说明,由于本团队硬件能力非常有限,如果发现任何不合理的地方请及时指出,当前硬件设计未经过严格验证
不推荐作为参考设计,仅供本项目第一阶段验证和测试使用。
b. Software Framework 基本完成
目前暂时基于K20开发了HAL层。已经调试完成。
c. 蜘蛛的运动控制部分正在测试,近几天可以完成基本的单爪运动状态机封装。
下一步计划:
a. 完成蜘蛛运动抽象层的底层部分,即爪子的行为模式封装(比如爪子的弯曲,爪子的收缩),为高层运动模式做准备
(比如,横着走,比如前后走)
b. 完成K6x的Software Framework扩展
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
|