2006:61 PB 2007:061 TH M MASTE A S T E RR’S 'S T H ESIS ESIS Motion Control for Mobile Robots Konrad R.
CZECH TECHNICAL UNIVERSITY IN PRAGUE FACULTY OF ELECTRICAL ENGINEERING DEPARTMENT OF CONTROL ENGINEERING DIPLOMA THESIS Motion Control for Mobile Robots Depart ment of Control Engineering Depart ment of Space Science Kiruna Space Campus ERASMUS MUNDUS SPACE MASTER PROGRAM Prague, 2007 Konrad R.
Declaration of authorship: I declare, that I wrote this diploma thesis myself only with the help of the literature, on-line materials, projects and others examples which are available for educational purposes. Prague, 29.05.2007 Konrad R.
Abstract This diploma thesis is focused on brushless DC motors, how they work and how to control them using phase tables. It describes the internals of existing motion control library (PXMC) and provides documentation of its elements, which were published under GPL license. Additionally it presents extensions of PXMC library, which were made to control two brushless motors with help of Renesas’ H8S/2638 microcontroller.
Table of Contents: 1. Introduction.............................................................................................................................6 2. Terminology and abbreviations. ............................................................................................8 3. Brushless DC motors. ............................................................................................................10 3.1. Overview. ....................................................................
7. Testing and documentation of the code. ..............................................................................65 7.1. Introduction....................................................................................................................65 7.2. Command processor (CMD_Proc) and serial line.........................................................65 7.3. Documentation. ..............................................................................................................67 8.
1. Introduction Motors are widely used in many aspects of our life. They serve in different trivial tasks like rotation of wheels in toys up to complicated works demanding very high level of accuracy like for example in military and space applications or humanoid robots.
Finally, even the best software and libraries are useless without good documentation and examples how to use them. Because of that, later in this document there is described the whole PXMC and how to use it, to meet desired needs. All of above mentioned thing are presented in this document. In the second chapter, I’m discussing all very important terms and abbreviations which can be a key element for proper understanding of the described topics.
2. Terminology and abbreviations. Below are presented the most important terms and abbreviations which are later used in this document. 0x – It denotes that we are using hexadecimal number. For example: 0xff means 255 in decimal system, 0x1f means 31 (in decimal system). AC – Alternating Current Commutation – “the action of applying currents or voltages to the proper electrical motor phases so as to produce optimum motor torque at a motor's shaft”1.
Servo – shortcut of Servomechanism – a special motor that typically includes a velocity and/or position feedback device. Sinusoidal current wave – It is a graphical or mathematical representation of changes in the current, which has the shape of a sinus function.
3. Brushless DC motors. 3.1. Overview. A brushless DC motors, very often denoted by shortcut BLDC (BrushLess Direct Current), are popular synchronous electric motors widely used in industry, especially in Appliances, Automotive, Aerospace, Consumer, Medical, Industrial Automation Equipment and Instrumentation. Characteristic property of this motor kind is that instead of brushes for commutation it uses electronically-controlled commutated system.
Fig. 3.2-1. Basic schematics of brushless motor. The basic schematic of a brushless motor is shown on the picture 3.2.1. First of all, brushless motors don't have windings on the rotor. The meaning of this is that here the rotating part is permanent magnet and the windings are placed on the stator poles. Additionally for proper functioning we need something what can automatically reverse the current. This can be achieved in two different ways.
The above presented differences in arrangement change the speed and torque inversely proportional to the factor of: rule in the motor selection. . Of course the arrangement of the windings doesn't have crucial Fig.3.2-3. Coils and poles inside brushless motor. As presented on the figure nr 3.2-3 as a typical brushless motor has three sets of coils called “phases”. This motor has also 2 poles. In normal case the rotor has four or six poles with corresponding higher number of stator poles.
Explanation of this figure is quite short and easy. As we know from previous pictures, we consider situation when we have only three phases. This means we can move stator filed only with resolution of 60o. Let’s start with a difference in angle between the rotor and the stator field equal to 120o and wait till the rotor rotates by 60o. As the result we will get the difference equal only to 60o.
Of course presented in above figure situation due to some non-linearity effects is very hard to realize. The effect of non-linearity can be observable when the motor is running very slowly as a slight kick at the commutation points. There is also a second drawback. Namely, the nonlinearity and ripple in the torque tend to produce a velocity modulation in the load.
The small example how the Hall Sensor can be used to read the rotation of the rotor is presented on the figure 3.3-1. Fig. 3.3-1. Example how we can read impulses from Hall Sensor. 3.4. Incremental encoders. Incremental encoder is a device which is used to measure the speed and a position. The general idea of this tool is to converts motion into a sequence of digital pulses. Later, counting these pulses we are able to estimate the relative or absolute position and the speed of the movement.
At this point small explanation about IRC and its channels should be given. Firstly couple of words about IRC. IRC is just a rotary and relative sensor which works in a similar way as was described in previous paragraph. Secondly we need to ask about one essential thing. How do we know in which direction our motor is rotating? The answer to this question may get closer if we look at the following graph 3.4-2: Fig. 3.4-2. Pulses generated in channels during rotation.
3.5. General work of brushless motor. As we know from the previous sections, to make the brushless motor rotating we need to put on the three windings currents with shifted phases. In the easiest case, when we have 3-phases motor the shift in the phases is equal to 120o. To fulfill this requirement, in most cases we will need to use some microcontroller to control the motor. This approach provides to a first problem.
Looking at the above example of discretization on the figure 3.5-1 and thinking little bit, we will find out another very important problem: it is impossible to put to the pins negative and positive values at the same time. In other words, we can assume that the voltage levels on the pins now are negative or positive, but we can't have them both. How to solve it? The solution is also quit easy. We just need to shift maximum negative values to be equal to zero.
Fig. 3.5-2. Position of the motor and reading from HAL sensor. I think it is good idea to explain little bit how we can rotate the motor in desired direction using table presented on the figure 3.5-2. Thus, if we know from hall sensors that we are in phase I and we want to rotate the motor into one direction all we need is just to apply positive or negative voltages according to values shown in the table.
Fig. 3.6-1. Brushless motor which was used by me. First of all we calculated the length of phase tables. We assumed that the amplitude of the sinusoid wave will be equal to 0x3fff. Making the maximum equal to 0x7fff and the minimum equal to 0 we were able to keep all levels inside two bytes (denoted as short in C). The rest calculations were made exactly as described in the subsection 3.
4. H8S/2638 microcontroller. 4.1. Overview. H8S/2638 is microcomputer unit (MCU) employed by Renesas Technology. In general it is 32-bit architecture unit with sixteen 16-bit general registers which can be used as 8-bit registers or as eight 32-bit registers. The maximum clock speed of this microcontroller is 20MHz what is comparable with the maximum speed of Intel's 80286 microprocessor.
Fig. 4.1-2. The internal structure of H8S/2638. Fig. 4.1-3. Pins available in H8S/2638.
4.2. PWM description. Pulse Width Modulation (PWM) is a method of a current or voltage signal regulation. It bases on a change of the impulse’s width with constant amplitude. H8S/2638 provides two 10-bit PWM channels with maximum 16 pulse outputs. Each channel has 10-bit counter and cycle register. Duty and output polarity can be set up for each output independent. Additionally there are five operating clocks and we can choose one of them. What is important, all PWM channels can work as I/O ports.
Fig. 4.2-2. PWM channel 2 in H8S/2638. PWMOCR1 and PWMOCR2 are used to select which PWM outputs should be enabled and which should be disabled. Selecting proper bits we can enable or disable corresponding PWM output. PWPR1 and PWPR2 are useful for changing polarity of PWM outputs. Polarity can be direct or inverse. Thanks PWCR1 and PWCR1 we can decide whether the PWCNT counter is enabled or not. The same register allows us also to select the clock for corresponding channel.
After short description of all registers we can shortly explain how PWM works inside H8S/2638. So, at the beginning, user has to select which PWM he is going to use. He also needs to set up proper polarity – default it is set as direct. Then, using PWCR we need to select proper clock source – for example ф which is the fastest one. Next step is to set PWM frequency with help of PWCYR. When we do all of these we can switch on the counter using once again PWCR.
In the case of second channel, the situation is little bit different. This is due to the differences in the architecture of the microcontroller. We can see it very clearly comparing two pictures nr 42.1 and nr 4.2-2. In the first channel we have only four buffer registers and four duty registers PWDTR1A, PWDTR1C, PWDTR1E and PWDTR1G. In the second channel there are still present only four buffer registers but there are also all eight duty registers from PWDTR2A till PWDTR2H.
Independent interrupt vector address has big advantage, because in this case we don't have to worry about identification of the source. All interrupts are controlled by the interrupt controller, which has two control modes. The highest priority has NMI interrupt and this can not be changed. To others interrupts we can assign eight priority levels. For external interrupts we can detect falling, raising or both edges. This last is not true for NMI, where we can detect only raising or falling edge.
Channels 0 and 3 are almost identical. This means both of them have the same interrupt sources, the same number of general and buffer registers. Only one difference is with the possibilities to set up the count clock. At this point I should mention that it is possible to count clock's ticks in two different ways. First method is with use of internal clock. Here we have several frequencies like: ф, ф /4, ф /16, ф /64, ф /256, ф /1024 and ф /4096.
In the following lines, I'm not going to go into details about several registers which are need to be set up properly, but I'll try to shortly explain mentioned above buffer operation mode, synchronous operation mode, phase counting mode and cascaded operation. It is important to understand all of them in proper way if we want to fully use this microcontroller. I don't describe PWM because in general it uses standard PWM approach and two available modes differ only in details.
5. PXMC library. 5.1. Introduction. PXMC is portable library to control various types of motors. Its main task or aim is to allow user/developer to control different motors installed on different boards which can have also different microcontrollers. In more general we can say it is a multi platform code, initially written by Pavel Pisa for stepper and brushless motors. Nowadays it can work for DC motors with IRC feedback, controlled by H8S/2638 microcontroller.
platform. Secondly, developer must have at least some basic experience with motors and microcontrollers. This is due to the fact, that there exist so many different motors, that it is impossible to write support for all of them. Additionally, there will be always needed to make some minor changes in the library's code, because on different hardware the connection will be less or more different, because they depend mostly on the functionality of the board.
5.2. Preparation of the programming environment. In this subsection I'll shortly present how to prepare programming environment for PXMC under Linux operating system. Firstly, we need to download three packages: binutils-2.16 gcc-3.4.3 newlib-1.14.0 All of above “programs” are under GPL license and can be free used even for commercial purposes. The question which can arise at this moment is, why above packages are so old? For example current (31.03.07) stable version of gcc is 4.1.2.
When the configuration will be finished, we write in standard way: make and then make install. As the result we will get binary file called: h8300-coff-gcc, which in this case is our desired compiler for H8S/2638 microcontroller. Next step is to get a copy of the PXMC library and to do it we need to have account on the server. If it is like that, then we just need to type: darcs get @rtime.felk.cvut.cz:/var/repos/pxmc Of course instead of we should put our login name.
Fig. 5.3.1-1. The structure of PXMC library. Fig. 5.3.1-2. Files with dependencies in PXMC library.
5.3.2. General work of PXMC. Before we go into descriptions of several files, which belong to PXMC library, we need to get some information how PXMC is working in general. On the figure 5.3.2-1 we can see the internal structure of PXMC and the most important variables and flags. Fig. 5.3.2-1. Internal structure of PXMC. So, let’s start with IRC. This component makes the measurements of the DC motor, which later could be used by do_inp.
here definitions of all flags and definitions of the most functions which can be accessed from PXMC. Now, lets try to look little bit more into details. We start from flags. All of them, which are available in PXMC, are presented on the figure nr 5.3.3-1, and in the following lines I'll try to introduce them. The first, PXMS_ENI_b (Enable Input) enables input IRC updates. It means that if this flag is set up, functions which pointer is kept in pxms_do_inp will be executed.
PXMS_CQF_b states whether the command queue is full or not. If it is full we can't give any new command. This flag is still not implemented and you can find only its definition in pxmc.h file. Maybe it is used by some other standalone library, but at the time when I wrote this document I didn’t have information about it. PXMS_PHA_b signalizes whether the phases in phase tables are aligned (flag is enabled) or not (flag is disabled).
Let’s go further. If we want to check whether some flag is set or not, we need to check pxms_flg. This is a bit field where the flags are stored in pxmc structure. Of course, in this case, we can't use above names of flags, but we have to change the last letter from “b” to “m”, for example: PXMS_ENI_m, PXMS_ENR_m and so one. This last need is due to the fact, that one flag uses only one bit and if we want to spare memory, we can keep all of them only in one byte or integer.
The advantage of the above equation is that it gives possibility to operate with help of fixed point arithmetic, which increases controller precision and speed of calculations. Secondly, as was already mentioned and shown in above formula, some values are given in so called IRC units. Small example, we have phase table with length of 2048 elements what is equal to 360o. To get 90o we need to divide 2048 by 4, and as the result we will get 512. This is 90o in IRC units.
pxms_md pxms_ms pxms_ma pxms_inp_info pxms_out_info pxms_ene pxms_erc pxms_p pxms_i pxms_d pxms_s1 pxms_s2 pxms_me pxms_foi pxms_fod pxms_tmp pxms_ptirc pxms_ptper pxms_ptofs pxms_ptshift This field stores the maximal difference between actual and required position. If the difference will be greater than this value, then error will be generated: the flag PXMS_ERR will be enabled in pxms_flg and the flag PXMS_E_MAXPD will be stored in pxms_errno. This value should be given in IRC units.
pxms_ptvang pxms_ptindx pxms_ptptr1 pxms_ptptr2 pxms_ptptr3 pxms_ptamp pxms_pwm1cor pxms_pwm2cor pxms_pwm3cor pxms_errno pxms_cfg pxms_ep pxms_gen_st pxms_gen_info pxms_hal This value is an angle between rotor and direction of magnetic field. The optimal value for steeper motors is 0o and for brushless motors it is 90o. It should be given using IRC units. This is an index to phase table arrays, which shows which element from the phase table should be send to PWM output.
In the following lines I will describe shortly configuration flags for a motor described by pxms_state structure. All these flags are available in PXMC library and they are presented on the picture nr 5.3.3-4. Unfortunately I didn't have opportunity to test them myself, because in most cases they were just set by people with bigger experience than me. PXMS_CFG_HDIR_b decides about the initial rotation direction of the motor.
First one, *ptr is used to store information about speed and power sent to the output. The*buff is used mainly to store a profile of speed generator. The *end pointer shows the end of the buffer. Please see PXMC_DEB.C subsection to get little bit more information about debugging. Other very important thinks are error flags. We know from the table in point 5.3.3 that pxms_state structure has field called pxms_errno, which keeps last error code. All error flags are presented on the picture nr 5.3.
pxmc_state_t *pxmc_main_arr[] = {&mcsLeft}; pxmc_state_list_t pxmc_main_list = { pxml_arr:pxmc_main_arr, pxml_cnt:(sizeof(pxmc_main_arr)/sizeof(pxmc_main_arr[0])) }; The “mcsLeft” was defined as pxmc_state_t. 5.3.4. PXMC_BASE.H In this file there is defined so called “controllers general interface”, what is just the basic functionality of the PXMC library.
Fig. 5.3.5-1. General structure of PID controller. PID used by PXMC can be seen on figure 5.3.2-1. The efficiency and performance of PID controller depend on three constants: proportional (pxms_p), integration (pxms_i) and derivative (pxms_d). Because of that it is very important to set these variables properly. To do this without use of identification and advanced mathematics, we can use so called Ziegler-Nichols Method of PID tuning2.
pxmc_dbg_gnr pxmc_dbgset This function is seen from outside of the PXMC library and in fact it prepares all necessary elements for storing the speed generator profile. This function sets debugging options for a given motor. Nowadays it is possible only to switch on or off debugging. It is also possible to give as a parameter a pointer to a function for debugging. This function sets PXMS_DBG_b flag automatically so we don't need to worry about it. *- function is not accessible from outside of the library.
pxmc_trp_gend pxmc_trp_gend1* pxmc_trp_gdu10* pxmc_trp_gdu20* pxmc_trp_gdu30* pxmc_trp_gdd10* pxmc_trp_gdd20* pxmc_trp_gdd30* pxmc_spd_gi pxmc_spd_gd10* pxmc_spd_gd20* pxmc_spdnext_gi pxmc_stop_gi pxmc_spdnext_gd* pxmc_spdnext_gend* Changes request position to new factor, what should finalize the use of trapezoid generator. This function is temporarily not working due to pxms_gen_tep call. Sets request speed to zero and than changes generator to pxmc_nop_gd.
5.3.10. PXMC_HH_BASIC.C At begin of the description of this file, it should be clearly mentioned that this file has couple of mistakes and probably it will not work properly. Moreover, because here are calls to fields inside pxmc_state structure which don't exists, it seems that it should be impossible to compile this file. Name of pole pxmc_hh_gi* pxmc_hh_gd10* pxmc_hh_gd20* pxmc_get_hh_gi_4axis* Short description This function is responsible for “Hard Home” generator initialization.
In this subsection I will present only constants for run time phase table generation which are defined in pxmc_internal.h. All functions which predefinitions can be found here will be or already were described in above or below subsections. PXMC_PTPROF_DEFAULT states that we are going to use a standard or default phase table. The phase table has in this case triangular shape. PXMC_PTPROF_SIN decides that our phase table will have sinusoidal shape. PXMC_PTPROF_TRIANG.
them during compilation or linking. Exactly the same situation was with H8S/2638 which I used. Name of pole pxmc_ptvang_deg2irc pxmc_init_ptable_sin pxmc_init_ptable_sin3ph pxmc_init_ptable_sin3phup pxmc_init_ptable_triang pxmc_init_ptable_trapez pxmc_init_ptable Short description This function converts phase shift from degrees to IRC units. Mainly it is used to calculate properly pxms_ptvang in pxmc_state structure. It generates sinusoidal phase table for a given motor.
Fig. 5.3.13-3. Phase tables generated with pxmc_init_ptable_sin3fup. Fig. 5.3.13-4. Phase tables generated with pxmc_init_ptable_trapez. Fig. 5.3.13-4. Phase tables generated with pxmc_init_ptable_triang. 5.4. How to start work with the PXMC. Nowadays, the way of starting to work z PXMC is quit simple and easy. Firstly, we need to include to our project or application pxmc.h file and additionally pxmcbsp.h. First file gives us access to all general PXMC functions.
bldctest for hi_cpu2 board we can also call function: pxmc_set_default_functions(pxmc_state_t *mcs, pxmc_motor_kind_e motor). The first parameter is a pointer to a pxmc_state structure which contains all necessary information about the motor. Second parameter is a value describing which kind of the motor we are going to use in mcs. Thanks this function it shouldn’t be a problem to have two kinds of motors connected to the board – for example one can be brushless motor and second a stepper motor.
6. Adding Board Support Package (BSP) for BLDC on H8S/2638. 6.1. Introduction. As was mentioned in section 5.1, the basic aim of PXMC library is/was to create easy to use and extendable hardware independent code for motion control. At begin of my work with PXMC, the situation looked quite different from above wishes. There was no separation of the code, no modularity, and no external debug tool. The code was hard to understand and what is the worst it was very hard to use.
Another improvement is that we decided to create one standard for all compilations. In other words, now always when we compile PXMC we get two libraries: pxmc pxmcbsp First of them has all “standard” and total hardware independent PXMC functions described in point 5.3. Second library (PXMC Board Support) has our functions, which can be hardware dependent and/or others functions which shouldn't be a part of standard PXMC library.
6.4. Work with hi_cpu2 board. During getting experience with PXMC library I got one of the tasks to make hi_cpu2 board working with brushless motors. This board has H8S/2638 microcontroller, which was described in 3rd section. Thanks that it should be very easy to port most of the code to the robot, which later was designed for Eurobot 2007 competition. Fig. 6.4-1. Hi_cpu2 board. The whole source code of driver which I wrote consists from two files: bldctest.h bldctest.c The bldctest.
const unsigned char eurobot_bdc_hal_pos_table[8]= { [0]=0xff, [5]=0, //1 0 1 = 5 [1]=1, //0 0 1 = 1 [3]=2, //0 1 1 = 3 [2]=3, //0 1 0 = 2 [6]=4, //1 1 0 = 6 [4]=5, //1 0 0 = 4 [7]=0xff, }; Another mentioned structure was pxms_state. In this case I gave it the name mcs_left and theoretically it should represent the left motor. As the default I assumed that the position of the motor should be automatically updated – flag PXMS_ENI_m. Functions for input, output, controller and hardware update are standard one.
pxms_me:PWM_MAX<<8, //6144 pxms_ptirc:bldc_ptirc, // IRC count per phase table pxms_ptper:bldc_ptper, // Number of periods per table pxms_ptshift:0, // Shift of generated phase curves pxms_ptvang:bldc_ptirc/4, // Angle (in irc) between rotor and stator mag. fld.
interupt_dbg* index_mark_isr_1* index_mark_isr* init_pwm* init_irc* init_hal* init_sampling* set_irq* motor_do_input* motor_do_output* A/a. This routine is called in debug mode to store some debug information about the motor. The pointer to debug function is stored in: pxms_do_deb. This function sets up PXMS_PHA_b flag when the “index mark” will be detected. Because it is interrupt routine, it is switched off after above flag is set up. Detection of “index mark” is done by TPU. It can be use only once.
Last two files: Makefile and Makefile.omk have descriptions of the rules for compilation and are used by make command. In Makefile.omk we should list all files which we use in our driver. For example: default_CONFIG = CONFIG_PXMC_VARIANT=bldctest lib_LIBRARIES = pxmcbsp pxmcbsp_SOURCES = bldctest.c pt.c renamed_include_HEADERS += bldctest.h->pxmcbsp.h renamed_include_HEADERS += pxmc_config_h8mirosot.h>pxmc_config.
The general idea is that, if we know the speeds of the wheels – we can read it from PXMC – then we can calculate the difference in speed between two wheels. This allows calculating by which amount in degrees the robot rotated. Additionally, knowing the perimeters of the wheels we can calculate how far they “drove”.
table in an element shown by hall value the number 1 and so on, till we rotate the motor by 360o. If it goes about detection of “index mark”, the situation is little bit more complicated. Namely position of the index mark is strict and its detection should be very accurate. To achieve this we need to use little bit more advanced technology – interrupt. This is mostly due to fact that interrupts work almost immediately. We have two possibilities: we can use TPU or IRQ to detect it.
snd=strchr(snd,':')+1; int whichIDX=atoi(snd); if(whichIDX<0) { pwm1 = (((unsigned long)pwm1*(unsigned int)ene) >> (15+5)); pwm2 = (((unsigned long)pwm2*(unsigned int)ene) >> (15+5)); pwm3 = (((unsigned long)pwm3*(unsigned int)ene) >> (15+5)); } else { whichIDX%=mcs->pxms_ptirc; pwm1 = (((unsigned long)mcs->pxms_ptptr1[whichIDX]*(unsigned int)ene) >> (15+5)); pwm2 = (((unsigned long)mcs->pxms_ptptr2[whichIDX]*(unsigned int)ene) >> (15+5)); pwm3 = (((unsigned long)mcs->pxms_ptptr3[whichIDX]*(unsigned int)ene
Now I will write couple of words about HalDetector. After uploading the driver with above function and compilation of the main program we can call it by typing: ./haldetector Next step is that we need to choose proper band rate, node to RS-232 device and the length of phase tables. If we want to use phase tables which are “included” to the driver and uploaded to the microcontroller, we need to select the “Use on board phase table(s) ” checkbox. Then we just click on the button start and wait.
int int int int int int int int writeport(int fd, char *chars); readport(int fd, char *result); getbaud(int fd); allocateMemory(); deallocateMemory(); openDevice(); closeDevice(); generatePhaseTables(); int detection(short pos_pha[], \ short *nr_of_pha,\ unsigned short hal_tab[]); Now, fd is just a file descriptor of the device which is used to the serial communication. The variable phaseTableLen keeps the value taken from the “Phase table len.” text field, which is visible on the picture 6.
7. Testing and documentation of the code. 7.1. Introduction. The testing and debugging of the code were not easy tasks. This was mostly due to the lack of good debugger and debugging functions for brushless motor. Fortunately there was one solution to this problem. Namely, it is possible to send commands and get responses from the microcontroller using serial line and tools like: gtkterm. The use of serial line is described in the next subsection. Another task was to write and generate the documentation.
int cmd_do_something(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[]) { printf("Hello world!\n"); return 0; } Then we create its description by adding following line: cmd_des_t const cmd_des_something={0, 0,"SOMETHING","do some command", cmd_do_something,{(char*)&cmd_list}}; And at the end we must add it to the command list. We can do it very easily by typing: cmd_des_t const *cmd_list_default[]={ &cmd_des_something, NULL }; Of course we can place here several others function.
7.3. Documentation. Documentation for bldctest.c and for bldc.c was generated automatically with help of script written in Perl, called: kernel-doc4. Exactly the same script is used to generate the documentation for kernel sources and because of that there are couples of rules which are important to keep in mind during creation of documentation.
'funcname()' - function '$ENVVAR' - environmental variable '&struct_name' - name of a structure (up to two words including 'struct') '@parameter' - name of a parameter '%CONST' - name of a constant. Finally when the description will be finished, we just type: ./kernel-doc -html somefile.c > output.html In this way we can generate different kinds of documentation: html, docbook, text or man. The documentation of bldctest.c and bldc.c are attached in Appendix A.
8. Conclusions. The general conclusions from my work are not simple task, so I think the best would be if I present my own opinion about every part or element on which I gained some new experience. Firstly, my knowledge about motors was/is not too big, but personally I think that brushless DC motors represent one of the most powerful and useful group of motors.
without having a contact with the authors, could very easy learn and test different properties of PXMC. It would also allow for better understanding of different components and functions which are or will be implemented in the library. Fig. 8-1. The full configuration of hi_cpu2 board and Connected brushless motor. At the end I would like to underline, that the whole work which I made for this thesis brought me really a lot of fun and new experience, which I hope to use in the future. Fig. 8-2.
9. Sources. (1) Renesans Technology - “H8S/2639, H8S/2638,H8S/2636, H8S/2630, H8S/2635 Group Hardware Manual” *online+ URL: http://documentation.renesas.com/eng/products/mpumcu/rej09b0103_h8s2639.pdf (2) Maxon - Maxon EC motor catalog and documentation URL: http://pdf.directindustry.de (3) Parker Motion&Control – “Brushless Motors – Engineering Reference” URL: http://www.parkermotion.com/catalog/catalogA/SectionA.
Appendix A Here is presented the whole documentation for the PXMC source code files, which were created during my work on this thesis. All of below functions and description were copied directly form html files generated by ./kernel-doc tool. A.1 The documentation for bldctest.
Function unsigned char hal_read (struct pxmc_state * mcs) Arguments mcs Motion controller state information Description This function reads and returns hall sensor value. A.2 The documentation for bldctest.c: Function int pxmc_initialize ( void) Arguments void no arguments Description This function initializes all subsystems necessary for proper work of pxmc. There are switched on: pwm, hall sensors read, irc updates, sampling period is set up and the irq for index mark detection.
Function bool pxmc_set_default_functions (pxmc_state_t * mcs, pxmc_motor_kind_e motor) Arguments mcs Motion controller state information motor Kind of motor which we are going to use -> see header for full list of supported motors Description This function sets up defaults pointers to control functions for a given motor. The default configuration depends on the motor kind.
Function void interupt_controller_and_output () Arguments Description The function is used to call pxms_do_con and pxms_do_out functions for all motors present on the board. It's called by pxmc_sfi_isr during every sampling period. Function void interupt_generator () Arguments Description The function is used to call pxms_do_gen functions for all motors present on the board. It's called by pxmc_sfi_isr during every sampling period.
Function void index_mark_isr_2 ( void) Arguments void no arguments Description This interrupt routine works in exactly the same way as index_mark_isr_1. The only one difference is that it works for second motor. Function void index_mark_isr ( void) Arguments void no arguments Description This interrupt routine is used to detect index mark for the first motor. Function uses IRQ as a source information about index mark crossing.
Function void init_irc ( void) Arguments void no arguments Description This function sets up TPU for index mark detection for 1st and 2nd motor. Function void init_hal ( void) Arguments void no arguments Description This function sets up registers and I/O ports in such a way, that the read of hall sensor is possible. Function void init_sampling ( void) Arguments void no arguments Description This function sets up TPU main unit to generate interrupts with sampling frequency: pxmc_sfikhz.
Function void init_irq ( void) Arguments void no arguments Description This function set up IRQ interrupt, by putting index_mark_isr to the interrupt vector table. Function int motor_do_input (struct pxmc_state * mcs) Arguments mcs Motion controller state information Description The function checks weather PXMS_PTI_b flag is enabled and if it is, than it calls pxmc_irc_16bit_commindx function to update pxms_ap according to IRC.
Function int tpu_irc_ap2hw (struct pxmc_state * mcs) Arguments mcs Motion controller state information Description The function updates pxms_ptofs and reads IRC. It need to be called if pxms_ap is changed by the application. Function int motor_do_input_test (struct pxmc_state * mcs) Arguments mcs Motion controller state information Description Function works in exactly the same manner as motor_do_input.
A.3 The documentation for brushless.c: Function int cmd_do_quit (cmd_io_t * cmd_io, const struct cmd_des * des, char * * param) Arguments Description It is implementation of quit command. This function/command should make software reset of H8S/2638 by use of a watchdog. Function int cmd_do_setflags (cmd_io_t * cmd_io, const struct cmd_des * des, char * * param) Arguments Description It is implementation of setflags command. This function/command enables PXMS_PTI_b and PXMS_PHA_b flags for 1st motor.
Function int cmd_do_setindex (cmd_io_t * cmd_io, const struct cmd_des * des, char * * param) Arguments Description It is implementation of setindex command. This function/command sets pxms_ptindx for 1st motor by force. The new value of index must be given as parameter by calling proper command. Function int cmd_do_setvang (cmd_io_t * cmd_io, const struct cmd_des * des, char * * param) Arguments Description It is implementation of setvang command.
Function int cmd_do_nopxmc (cmd_io_t * cmd_io, const struct cmd_des * des, char * * param) Arguments Description It is implementation of nopxmc command. This function/command switches off pxmc for 1st motor. Thanks that, during some tests we can always switch off temporary the motor and avoid its burning. Function int cmd_do_mypwm (cmd_io_t * cmd_io, const struct cmd_des * des, char * * param) Arguments Description It is implementation of x# command.
Function int switchLedsOn () Arguments Description This function switches on all led on the board. Function void unhandled_exception ( void) Arguments void no arguments Description This function signalizes the occurrence of some exception. The signalization is made by switching on and later switching off 1st led. Function void init () Arguments Description This function initializes rc232. This serial line is later used by command processor.
Function int main () Arguments Description This function is a main function of the program. It initializes pxmc, and than in a constant loop it expects commands on rs232 which are later used/sent to command processor.
Appendix B Here is presented the whole documentation for the HalDetector source code files. This documentation was created with Doxygen program and later was little bit modified to make it more readable. HalDetector Class Documentation Form1 Class Reference #include Public Member Functions Form1 (QWidget *parent=0, const char *name=0, WFlags fl=WType_TopLevel) Default constructor of the call. ~Form1 () Default destructor of the class.
QLabel * text Label2 Label with "Baud rate" text. QText Ed it * text Edit 1 TextEdit field where appear results of scanning. QLineEd it * deviceLineEdit 1 Text line where we put the path to device used for communication. QMenuBar * MenuBarEditor The main menu. QPopupMenu * File File menu. QPopupMenu * Help Help menu. QAction * fileQuitAction Pointer to function called after File->Quit menu click. QAction * helpAboutAction Pointer to function called after Help->About menu click.
void aboutMenuFileClicked () Function called after Help->About menu click. Private Member Functions int initport (int fd) Initializes given port. int writeport (int fd, char *chars) Write given string to a device. int readport (int fd , char *result) Read string from a device. int getbaud (int fd) Detects Baud Rate on an open device. int allocateMemory () Allocates memory for phase tables. int deallocateMemory () Frees memory. int openDevice () Open given device.
short * ph1 Pointer to 1st phase table. short * ph2 Pointer to 2nd phase table. short * ph3 Pointer to 3rd phase table. bool working Busy flag. Detailed Description The main class of the program. Constructor & Destructor Documentation Form1::Form1 (QWidget * parent = 0, const char * name = 0, WFlags fl = WType_TopLevel) Default constructor of the call. Constructs a Form1 as a child of 'parent', with the name 'name' and widget flags set to 'f'. Form1::~Form1 () Default destructor of the class.
void Form1::startButtonClicked () [protected, slot] Function called after "Start" button click. Start button clicked. According to selections in checkbox, chosen baud rate and selections of device it calls others functions in right order. This function automatically opens and closes given device, allocates and frees memory. void Form1::stopButtonClicked () [protected, slot] Function called after "Stop" button click. Stop button clicked. Function stops detection of the hall position table and index mark.
int Form1::writeport (int fd, char * chars) [private] Write given string to a device. Function writes a string to device pointed by fd descriptor. Parameters: fd descriptor of a device. chars pointer to a char array with a string which should be sent to the device. Returns: 0 if there were no errors. int Form1::readport (int fd, char * result) [private] Read string from a device. Function reads from given device and stores readed string in a char array pointed by result pointer.
int Form1::openDevice () [private] Open given device. Function opens device given in deviceLineEdit1 text line and assigns the fd pointer. Returns: 0 if there were no errors. int Form1::closeDevice () [private] Close opened device. Function closes device pointed by the fd descriptor. Returns: 0 if there were no errors. int Form1::generatePhaseTables () [private] Generates phase tables. Function generates phase tables.