Показаны сообщения с ярлыком MOVIE. Показать все сообщения
Показаны сообщения с ярлыком MOVIE. Показать все сообщения

четверг, 14 марта 2013 г.

AVR32/ASF: ANSI terminal on UART

It's good known goal - to run terminal (with some kind of shell) of one (or all) of the UARTs. This snippet shows how to process input byte from UART and to emulate ANSI terminal behavior:

/**
 * Handle input byte via USART; process it to emulate edit line behaviour.
 * After processing, sets self->response array to 4 possible responses (until
 * one is NULL). sh_task() will send these responses via UART...
 * Each response can be usual ASCIIZ but also can be ANSI ESC codes, so user
 * terminal should be in ANSI TERM mode. Supported:
 * - BS/DEL - delete prev. char
 * - ^U - delete entire line
 * - ^L - clear screen but keep edited line
 * - TAB - changed to SPACE
 * On error sends BEL ('\7')
 */
void handle_input_byte(sh_t *self, uint8_t ch)
{
    switch (ch) {
        case '\r':
            ch = '\n';
        case '\n':
            self->inpos = 0;
            self->inbuf[0] = 0;
            _SETRESP(self, "\r\n", self->promptbuf, NULL, NULL);
        break;

        /* backspace, del */
        case '\b':
        case '\x7f':
            if (self->inpos > 0) {
                self->inpos--;
                self->inbuf[self->inpos] = 0;
                _SETRESP(self, "\b \b", NULL, NULL, NULL);
            } else {
                _SETRESP(self, "\a", NULL, NULL, NULL);
            }
        break;

        /* ^U - del line */
        case 'u' & 0x1f:
            self->inpos = 0;
            self->inbuf[self->inpos] = 0;
            _SETRESP(self, "\x1B[2K\r", self->promptbuf, NULL, NULL);
        break;

        /* ^L - clear screen */
        case 'l' & 0x1f:
            _SETRESP(self, "\x1B[2J\x1B[H", self->promptbuf, self->inbuf, NULL);
        break;

        /* all other chars */
        case '\t':
            ch = ' ';
        default:
            if ((ch >= (uint8_t)' ' && ch <= (uint8_t)'\x7e')
                            || ch >= (uint8_t)'\xa0') {
                // printable
                if (self->inpos < sizeofarray(self->inbuf) - 1) {
                    // in bounds (-2 is for ch, -1 is for '\0')
                    self->inbuf[self->inpos++] = ch;
                    self->inbuf[self->inpos] = 0;
                    _SETRESP(self, self->inbuf + (self->inpos-1), NULL, NULL, NULL);
                } else {
                    _SETRESP(self, "\a", NULL, NULL, NULL);
                }
            } else {
                // non-printable
                _SETRESP(self, "\a", NULL, NULL, NULL);
            }
        break;
    }
}
Nothing special: no support of editing in the middle of the line, only at the end, clearing of line, screen, deleting last char. It generates ANSI ESC sequencies. self is the pointer to special struct with inbuf char buffer and inpos - current position of added bytes, so entered line will be in the inbuf. _SETRESP() is the macros - it sets 4 char pointers to be sent in sh_task() function (sends all 4 or until one of them is NULL) - it's looks similar like yielding of responces in WSGI Python Web application, but limited with 0 to 4 parts only :)
sh_task() is call in main loop and sends these responces, handle_input_byte() is called in UART ISR routine to save input and prepare responces. Using of struct, wrapped all needed resources helps us to avoid global and single shell only, so we can have several shells on several UARTs.
sizeofarray() is trivial macros, returns array items number. Short example how it looks:

ANSI terminal on AVR chip from bapcyk on Vimeo.

пятница, 10 февраля 2012 г.

Low-pass filter

One of the low-pass filters software algorithm is described on http://en.wikipedia.org/wiki/Low-pass_filter. Here is the example of Python implementation:
# Low-pass filter
import random

RC = 0.05 # time constant (inertion)
DT = 0.02 # sampling time

A = DT/( RC + DT)
#A = 0.45
xk_1 = 0
print "Measured;Filtered"
for i in xrange(0, 200):
    xm = random.randint(0, 2)
    # Both are equals:
    #xk = A*xm + (1-A)*xk_1
    xk = xk_1 + A * (xm - xk_1)
    print "%d;%f" % (xm, xk)
    xk_1 = xk
With RC (tau) we can control inertia of the filter
RC=0.5
RC=0.05


Here is the example how looks low-pass filter with tilt angles (F-16 seems to be more stable):

HMC6343 demo 1 from bapcyk on Vimeo.



If you try to filtering tilt angles then you can see funny effect: turning of 3D model! It's happens due to error in sensor data which filter try to smooth, see image:


Near the scale edges error seems to be small, but angles may be, for ex., 10°, 350°, and filter will smooth their to 10°, 20°, 30°... 340°. And you can see rotation of the model on the screen.
One of the approach to avoid this problem is to normalize angles. For example, 10°, 350° may be converted to 10°, -10°. After such normalization angles great then 360° should be normalized to canonical range. Algorithm is easy:
absdiff = abs(v1 - v0)
if absdiff > 180.:
  d = 360. - absdiff
  if v0 > v1:
    v1 = v0 + d
  else:
    v1 = v0 - d
And after filtering to avoid values great then 360° we can use something like this:
if abs(v) >= 360.:
  v = v % 360.