Quadlator II第三章
Quadlator II--其他配置和多线程基础
作者:phpbb2/profile.php?mode=viewprofile&u=234"target="_blank">baredog
二,其他配置和多线程基础
现在回过头来看,2003年的时候,为了赶在9月20号的demo前完成制作,拼命赶进度,很多东西不求甚解。正因如此,也走了不少弯路,比如这一章就是。由于当时没有明确开发环境和目标环境的概念,没有明确交叉编译和目标下载、在线调试的概念。浪费了很多时间和精力去配置目标环境。其实有很多是没有必要的。
2.1、配置bash
配置Bash是为了开发者方便,而开发者不必在目标环境(嵌入式系统)上开发,因此不必过分追求目标环境上的界面如何。这些工作放在配置开发PC上更加适合。那么目标环境和开发环境的关系是怎么样的呢?还是一图胜千言那句话,下面的示意图描述了两者间的关系:
图中同样颜色的红色和灰色部分,表明了目标系统和开发系统中必须相同的内容。最关键的就是他们拥有相同的目标库,而其他环境都可以不同,这样在开发环境下写出的代码,通过交叉编译可以生成在目标环境下能够运行的二进制代码。这些代码通过各种手段(无线LAN,蓝牙,CF卡等等)上载到目标环境下,就可以直接被目标环境的Kernel加载。这样的好处是,目标环境根本不需要开发相关的内容(头文件,静态连接库等),只需要最基本的运行时库和kernel,以及最小化的shell就足够了。系统可以做的非常小巧紧凑。目标上的shell仅仅用于应急配置和诊断,以及用于接受编译好的二进制文件所需的一些辅助功能。
因此所谓的配置bash,决不应该是以前写的配置目标系统的bash,而是应该配置开发系统的bash,目标系统仅仅做一些极小的改动就足够了。
Linux下的各种shell中,近年来bash非常流行,已经成为很多Linux发布版本的默认shell。如果稍加配置,就可以支持彩色终端,显示界面比较友好,例如:目录是蓝色的,符号链接或者硬链接是浅兰色,可执行文件是绿色。如果使用远程终端,那么终端软件(ssh或者telnet client)也需要支持ANSI彩色,微软的telnet 从2000后支持,但是不支持ssh协议,国内比较流行的sterm也非常易用。如果用Netterm的话,需要ssh插件。类似的软件还有 Security CRT等等(06年我还看到有人用PuTTY,也是免费的)。如果开发环境的PC上启动了XWindow的XDM,还可以选择用xwin32,Extra X和exceed等远程桌面环境,一个免费的选择是CygWin,同时带有ssh和X。
以下这些内容在高版本的Redhat和Fedora下,全部作为缺省实现了,读者可以跳过这些内容。
在linux下,一个用户登录后bash是这样工作的:
- Step1,首先用户目录下的.bash_profile会被运行。这个文件是一个隐藏文件,它会检查,用户目录下是否有.bashrc文件,如果有的话,就运行之。
- Step2,此后.bashrc文件检查在系统的/etc目录下有没bashrc文件,如果有的话,就执行之。因此所有用户的公共shell配置可以放到/etc/bashrc文件中
- Step3,系统执行/etc/bashrc文件。这个文件中,可以添加一些行,让ls命令的结果以彩色显示,同时也可以在这个文件中更换 更加友好的shell提示符
目标环境仅仅是一个嵌入式系统,为了最小化系统,通常只留有root一个用户,可以自由操作控制整个系统。因此也没有必要预留通常 linux提供的adduser, useradd等命令工具。但是这客观上要求,在目标系统上直接操作时,要格外小心,避免由于简单失误而造成的损失(例如在/下运行了rm -rf *而删除了全部系统)。在开发环境上,可以自由配置bash,下面给出2个开发环境下bash的配置文件的例子:
.bash_profile中加入以下的内容,可以自动运行用户的个人配置
# Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi
.bashrc中加入一下的内容,可以导入系统公共的bash sheel配置给当前用户:
if [ -f /etc/bashrc ]; then . /etc/bashrc fi
这样用户登录后,就会运行公共的bash配置文件/etc/bashrc,此后可以通过编辑/etc/bashrc文件,进行进一步的配置 在/etc/bashrc中加入这样的行:
alias ls='ls -F --color=auto' # ls的结果以彩色显示 alias ll='ls -la --color=auto' # 以ll命令查看文件详细信息(包括大小,日期等) alias la='ls -a --color=auto' # 以la命令查看隐藏文件
以下这个小改动对于目标系统也有一定的必要,可以减少发生无操作这类错误的机会。缺省下titechwire的提示符是一个#号,用户以root身份操作时, 并不能直观的了解当前所在的工作目录。可以通过加入一下内容,来使得提示符显示当前的工作目录信息:
PS1="[u@h W]$ "
这样,用户登录后会显示:
[root@quadlator /root #]
在开发PC上,可以根据个人的习惯,进一步配置开发环境,包括编辑器或者IDE等等。再一些老旧的Linux系统上,如果希望编辑器 VIM显示语法颜色,可以通过在用户目录下增加一个配置文件.exrc,并加入以下内容
syntax on #打开语法彩色显示功能 set ai #打开自动缩进功能
2.2 多线程编程,pthread
RT-Linux的一个重要概念是real time task,主要靠线程来实现。每一个task拥有良好的实时性能,这些task同Linux内核一起,被RT-Linux的内核调度,分配时间片等 CPU资源。Linux本身的一些应用中,如果良好的使用线程,也可以提高效率。有关线程和进程的区别,很多著述中有所介绍。包括从虚拟内存空间等资源上的区别和调度的一些区别。这里有一点可以额外说一句,就是内核模块和用户程序中都可以使用线程。使用方法也没有太大的区别。Linux系统提供了pthread库来提供对多线程的支持。
Quadlator II中使用了多线程来组织控制程序,大体上的结构如下图:
在Quadlator II中,除了嵌入式系统titechwire之外,尚有一台额外的计算机介入系统。机器人的姿态算法等高层计算(实时性要求不高的内容)和基本的用户控制 UI被分离出来移动到这台计算机上。嵌入式系统在这样的分工中,仅仅专门负责最底层的电机控制和各关节物理量的测量。
采用这样的结构后,机器人和高层控制计算机机就可以采取Client/Server体系,机器人为server,高层控制计算机机上为 client。事隔3年后,我再回过头来看这样的体系结构,觉得当时的考虑为了赶时间带有了很大的局限性。现在可以在此深入探讨一下各种架构的优缺点。
首先03年采用上图中的架构,主要考虑如下:
- 机器人要稳定,即使突然网络中断,机器人也不能失控,而要保持现有姿势(刹车)。这样,网络上的高层控制程序由于意外死机等故障,不会对机器人造成跑飞的影响,同时,高层控制程序也可以随时切入和随时撤出。
- 机器然上的程序要短小精干,不负责复杂的控制计算,计算交由上位的高层控制计算机完成。如果一台计算能力不够,还可以投入多台并行处理。机器人上的嵌入系统程序仅仅负责把上位机计算的结果翻译成电压指令,驱动电动机即可。
上述方案的缺点,现在总结下来大概如下:
- 机器人不独立,如果没有高层控制计算机,机器人就不能进行任何动作;
- 未发挥出嵌入式系统的能力,上述的架构,本质上和遥控的概念接近,嵌入式系统的计算能力其实远远超出遥控系统中的单片机。可以把相当实时要求不高的一些计算移到嵌入系统的用户空间部分。
- 无法实现多台机器人协作。这一点在当时尽管由于高昂的制造代价而难以实现,旦在将来应该是一个很广阔的领域。
现在再看看另外一种架构:机器人独立运行,同时以接口的方式实现功能扩展:
(点击放大)
这种形式的架构下,机器人自身是具有高度独立性的。内核模块利用很好的实时性能,提供PID闭环控制:接受命令-->驱动DA-->功率放大后驱动电机-->测量反馈量-->送入DIO。同时有一组事先储存好的预定动作,如起立,向前走,拐弯等等。在用户空间设有一个对实时性能要求不高的基本运动控制模块。它根据更高层的指令,读取这些预定动作,然后将预定动作分解为命令序列发送给内核空间的PID控制模块。
这个架构提供了3个扩展接口,2个软件接口,1个硬件接口。都用绿色标记了出来。其中一个软件接口,允许增加,更新和删除已经存储的预定动作,比如增加一个坐下的动作等等。另外一个软件接口可以提供通过计算机指挥机器人动作的可能。计算机可以发出简单的命令,如:起立,向前走,向右转,再向前走等等;也可以发出连续的运动指令,用来测试新编写的预定动作。剩下一个硬件扩展接口,可以增设遥控接收装置,这样普通的消费者可以通过遥控器简单的控制机器人运动。
这种架构的优点是:
- 机器人独立,可以自行完成一些简单的动作,而不需外界干涉。
- 可以用一台计算机,控制多个机器人。
- 扩展性好。
这种架构的缺点是:
- 对嵌入系统的稳定性要求高,在没有外界控制,或者只有少量外部指示的情况下,要安全稳定地完成整套动作。
- 嵌入式系统的软件部分复杂,编制难度大。
- 一旦机器人上的嵌入系统跑飞或者死机,通过外部手段将无法控制它,必须提供一些安全措施(空气安全开关,或者由遥控器控制的独立通道安全开关)
现在把话题收回来,Quadlator 2实际采用的第一个架构下,机器人大致工作如下:机器人上的程序运行后,就启动server,在网络上监听,等待控制程序连接进来。早期的linux下网络编程,收到连接请求后,往往使用fork的方法,开一个新进程,Quadlator 2没有使用fork,而采用了多线程的方法,单独开一个线程,负责接收网络上控制计算机的计算结果。
如前面所述,Linux下可以使用pthread库来实现多线程。
2.2.1 简单例子,和link出错问题
这里用一个简单的例子来说明pthread的基本用法。在这个例子中,程序启动后,主程序就开出两个独立线程,一个每隔1秒数数,一个每隔两秒,都是数到10就停止:
// thread test program //----------------------------------------------------------------------------- #include #include #include
void task1(int* counter); void task2(int* counter);
int g1=0; int g2=0;
int main(void){ pthread_t thread1, thread2; int ret;
if((ret=pthread_create(&thread1, NULL, (void*)task1, (void*)&g1)) != 0){ perror("can not create thread 1!
"); exit(EXIT_FAILURE); } if((ret=pthread_create(&thread2, NULL, (void*)task2, (void*)&g2)) != 0){ perror("can not create thread 2!
"); exit(EXIT_FAILURE); }
pthread_join(thread2, NULL); pthread_join(thread1, NULL); }
void task1(int* counter){ while(*counter
|