2024年7月

The objective of this article is to provide the reader with available PDF viewer alternatives on Ubuntu 20.04 Focal Fossa Linux.

In this tutorial you will learn:

  • Evince PDF Viewer
  • Okular PDF Viewer
  • Atril PDF Viewer
  • Adobe Reader PDF Viewer
  • MuPDF PDF Viewer
  • Zathura PDF viewer
  • GNU gv PDF Viewer

PDF viewer list on Ubuntu 20.04 Focal Fossa Linux

PDF viewer list on Ubuntu 20.04 Focal Fossa Linux

Software Requirements and Conventions Used

Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Installed Ubuntu 20.04 or upgraded Ubuntu 20.04 Focal Fossa
Software N/A
Other Privileged access to your Linux system as root or via the sudo command.
Conventions # – requires given linux commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux commands to be executed as a regular non-privileged user

PDF viewer alternatives on Ubuntu 20.04 Focal Fossa Linux

  1. Evince PDF Viewer

    default PDF viewer on Ubuntu 20.04 GNOME desktop

    Evince a.k.a Document Viewer is a default PDF viewer on Ubuntu 20.04 GNOME Desktop

    Installation:

    $ sudo apt install evince


  2. Atril PDF Viewer

    default PDF viewer on Ubuntu 20.04 MATE desktop

    Atril is a default PDF viewer on Ubuntu 20.04 MATE desktop

    Installation:

    $ sudo apt install atril
  3. Okular PDF Viewer

    default PDF viewer on Ubuntu 20.04 KDE Plasma desktop

    Okular is a default PDF viewer on Ubuntu 20.04 KDE Plasma Desktop

    Installation:

    $ sudo apt install okular
  4. Adobe Reader

    Adobe Reader is a proprietary PDF viewer

    Adobe Reader is a proprietary PDF viewer available via external 3rd party package. Adobe Reader is no longer supported on the Linux platform hence is obsolete and not recommended for the installation.

    Installation:

    Follow our guide on how to install Adobe Reader on Ubuntu 20.04 Linux.

  5. MuPDF PDF Viewer

    MuPDF is a extremely lightweight PDF viewer that supports a PDF, XPS, and EPUB formats

    MuPDF is a extremely lightweight PDF viewer that supports a PDF, XPS, and EPUB formats.

    Installation:

    $ sudo apt install mupdf


  6. Zathura PDF Viewer

    Zathura is a free, plugin-based document viewer application. Available plugins include PDF, PostScript and DjVu

    Zathura is a free, plugin-based document viewer application. Available plugins include PDF, PostScript and DjVu.

    Installation:

    $ sudo apt install zathura
  7. GNU gv PDF Viewer

    GNU gv is a powerful PostScript and PDF document viewer

    GNU gv is a powerful PostScript and PDF document viewer developed by the GNU Project.

    Installation:

    $ sudo apt install gv

开源飞控:

一、 PIX4

1、官网

https://px4.io/

2、github

https://github.com/PX4/PX4-Autopilot

3、 开源硬件平台: Pixhawk 4、开源飞控软件: PX4 Autopilot

5、地面站软件: QGroundControl



二、 APM

1、官网:

       https://ardupilot.org/

2、github

https://github.com/ArduPilot

3、 开源硬件平台: Ardupilot Mega

4、 开源飞控软件: APM(ArduPilot), APM现在也兼容、支持 Pixhawk硬件平台

5、 地面站软件: Mission Planner

6、 地面站软件: APM Planner 2.0



三、Bitcraze

1、官网

https://www.bitcraze.io/

2、github

https://github.com/bitcraze

3、Crazyflie Quadcopter



四、Paparazzi UAV

1、官网

https://wiki.paparazziuav.org/wiki/Main_Page

2、github

https://github.com/paparazzi/paparazzi/releases



Serial.print(millis());
Serial.print(",");
Serial.print(gyr.x);
Serial.print(",");
Serial.print(gyr.y);
Serial.print(",");
Serial.print(gyr.z);
Serial.print(",");
Serial.print(gValue.x);
Serial.print(",");
Serial.print(gValue.y);
Serial.print(",");
Serial.print(gValue.z);
Serial.print(",");
Serial.print(magValue.x);
Serial.print(",");
Serial.print(magValue.y);
Serial.print(",");
Serial.print(magValue.z);
Serial.println(temp);



一、XYZ数据: points.csv

     

1.1,1.2,1.3
2.1,2.2,2.3
3.1,3.2,3.3
4.1,4.2,4.3




一、Python绘制脚本: plot_3D.py


from    mpl_toolkits.mplot3d import Axes3D

import  matplotlib.pyplot as plt
import  pandas  as  pd



points = pd.read_csv('points.csv')
frame = pd.DataFrame(points)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

x = frame.iloc[:,0]
y = frame.iloc[:,1]
z = frame.iloc[:,2]

#  x   y   z  
# 1.1,1.2,1.3
# 2.1,2.2,2.3
# 3.1,3.2,3.3
# 4.1,4.2,4.3

ax.scatter(x, y, z, c='r', marker='o')

plt.show()













          我第一次接触数字磁强计是在2009年的夏天。当时,与许多Arduino 初学者一样,我更关心编写 I2C/SPI 驱动程序,而不是了解设备本身。几个月后,我买了一部 iPhone 4,并发现每次使用使用手机内部磁力计的指南针应用程序时都需要校准。因此,我开始感兴趣为什么需要这一步以及如何完成它。在这篇文章中,我将尝试通过一个实际的例子来解释一种实现方法。它本质上就是这里描述的方法,但有更多的细节和参考资料。

https://teslabs.com/articles/magnetometer-calibration/





A digital triple-axis magnetometer sold nowadays. Source: Sparkfun (CC-BY-NC-SA)


基本概念

          在开始之前,我们有必要明确几个概念。我们需要对地球磁场有一个基本的了解,这似乎是合乎逻辑的,因为这是我们想要测量的。此外,二次曲面(如球体或椭球面)的基础知识将变得很重要。 在这里讨论二次曲面可能有点尴尬,但很快就能理解。


地球磁场

           在地球上的任何位置,磁场都可以局部表示为一个恒定的三维矢量 ()。这个向量可以用三个性质来表征。首先,磁场强度或大小(),通常以纳特斯拉 (nT) 为单位,大约范围是 25000 nT 至 65000 nT。其次,磁倾角 (I),如果指向上方则为负值(最大 -90°),如果指向下方则为正值(最大 90°)。第三,磁偏角(D)测量磁场相对于地理北方的偏差,向东为正。



Magnetic field frame of reference. Source: Wikimedia Commons


利用上图中的参考系,地球磁场矢量h0可表示为:



给定一个地理点,可以使用 WMM 模型来获取 F、I 和 D 的预期值。为了计算罗盘上的地理北,磁偏角特别有用。




WMM 2015.0 intensity, inclination and declination maps. Source: NOAA/NGDC & CIRES


二次曲面

         二次曲面是所有能够用 x、y 和 z 的二次多项式表示的曲面。它们包括常见的表面,例如球体、椭圆体、抛物面等。二次曲面 S 的一般隐式方程由下式给出:

 


式(2)可以写成半矩阵形式,这对我们的问题特别有用:

             


磁力计测量

         首先,我们假设我们处于无磁干扰的环境中,并且我们有一个理想的 3 轴磁力计。在这些条件下,以任意方向获得的磁力计读数 h 将由以下公式给出:

通过这种方式查看磁力计样本,我们可以从几何角度看待这个问题。下面的交互式图表显示了一个计算示例。



失真源

        现实生活中没有什么是完美的,环境也不是没有干扰的。正如本出版物中详细介绍的那样,测量失真源主要有两类:仪器误差和磁干扰。在接下来的部分中,我们将简要介绍它们,最后介绍测量模型。


仪器错误

          仪器误差对于每台设备都是独一无二的,并且是恒定的。它们可以由三个部分建模而成。首先是比例因子,可以将其建模为对角矩阵:




磁场干扰

        




      






import sysimport numpy as npfrom scipy import linalgclass Magnetometer(object):    ''' Magnetometer class with calibration capabilities.        Parameters        ----------        sensor : str            Sensor to use.        bus : int            Bus where the sensor is attached.        F : float (optional)            Expected earth magnetic field intensity, default=1.    '''    # available sensors    _sensors = {'ak8975c': SensorAK8975C}    def __init__(self, sensor, bus, F=1.):        # sensor        if sensor not in self._sensors:            raise NotImplementedError('Sensor %s not available' % sensor)        self.sensor = self._sensors[sensor](bus)        # initialize values        self.F   = F        self.b   = np.zeros([3, 1])        self.A_1 = np.eye(3)    def read(self):        ''' Get a sample.            Returns            -------            s : list                The sample in uT, [x,y,z] (corrected if performed calibration).        '''        s = np.array(self.sensor.read()).reshape(3, 1)        s = np.dot(self.A_1, s - self.b)        return [s[0,0], s[1,0], s[2,0]]    def calibrate(self):        ''' Performs calibration. '''        print('Collecting samples (Ctrl-C to stop and perform calibration)')        try:            s = []            n = 0            while True:                s.append(self.sensor.read())                n += 1                sys.stdout.write('\rTotal: %d' % n)                sys.stdout.flush()        except KeyboardInterrupt:            pass        # ellipsoid fit        s = np.array(s).T        M, n, d = self.__ellipsoid_fit(s)        # calibration parameters        # note: some implementations of sqrtm return complex type, taking real        M_1 = linalg.inv(M)        self.b = -np.dot(M_1, n)        self.A_1 = np.real(self.F / np.sqrt(np.dot(n.T, np.dot(M_1, n)) - d) *                           linalg.sqrtm(M))    def __ellipsoid_fit(self, s):        ''' Estimate ellipsoid parameters from a set of points.            Parameters            ----------            s : array_like              The samples (M,N) where M=3 (x,y,z) and N=number of samples.            Returns            -------            M, n, d : array_like, array_like, float              The ellipsoid parameters M, n, d.            References            ----------            .. [1] Qingde Li; Griffiths, J.G., "Least squares ellipsoid specific               fitting," in Geometric Modeling and Processing, 2004.               Proceedings, vol., no., pp.335-340, 2004        '''        # D (samples)        D = np.array([s[0]**2., s[1]**2., s[2]**2.,                      2.*s[1]*s[2], 2.*s[0]*s[2], 2.*s[0]*s[1],                      2.*s[0], 2.*s[1], 2.*s[2], np.ones_like(s[0])])        # S, S_11, S_12, S_21, S_22 (eq. 11)        S = np.dot(D, D.T)        S_11 = S[:6,:6]        S_12 = S[:6,6:]        S_21 = S[6:,:6]        S_22 = S[6:,6:]        # C (Eq. 8, k=4)        C = np.array([[-1,  1,  1,  0,  0,  0],                      [ 1, -1,  1,  0,  0,  0],                      [ 1,  1, -1,  0,  0,  0],                      [ 0,  0,  0, -4,  0,  0],                      [ 0,  0,  0,  0, -4,  0],                      [ 0,  0,  0,  0,  0, -4]])        # v_1 (eq. 15, solution)        E = np.dot(linalg.inv(C),                   S_11 - np.dot(S_12, np.dot(linalg.inv(S_22), S_21)))        E_w, E_v = np.linalg.eig(E)        v_1 = E_v[:, np.argmax(E_w)]        if v_1[0] < 0: v_1 = -v_1        # v_2 (eq. 13, solution)        v_2 = np.dot(np.dot(-np.linalg.inv(S_22), S_21), v_1)        # quadric-form parameters        M = np.array([[v_1[0], v_1[3], v_1[4]],                      [v_1[3], v_1[1], v_1[5]],                      [v_1[4], v_1[5], v_1[2]]])        n = np.array([[v_2[0]],                      [v_2[1]],                      [v_2[2]]])        d = v_2[3]

return M, n, d





Example

To conclude this post we will use samples from a real magnetometer, which willallow us to see if the proposed solution behaves as expected. It is important tonote that we will not evaluate the accuracy of our solution, neither otherthings such as how the number of samples or their spatial distribution affectsthe calibration. These are topics that would require further study, out of thescope of this post.

The chosen magnetometer is the one found inside the InvensenseMPU-9150: AK8975C. It is a module thatalso contains an accelerometer and a gyroscope, not required for our purposes. ARaspberry Pi 2 will be used as a host platform, as shown below. This will allowus to quickly code a proof of concept by just using a few lines of Python. Notethat you will need to activate the I2C driver and install python-smbus on theRaspberry Pi (detailshere).




The proposed code for the AK8975C drive is:

import smbus# MPU9150 used registersMPU9150_ADDR                       = 0x68MPU9150_PWR_MGMT_1                 = 0x6BMPU9150_INT_PIN_CFG                = 0x37MPU9150_INT_PIN_CFG_I2C_BYPASS_EN  = 0x02# AK8975C used registersAK8975C_ADDR                       = 0x0CAK8975C_ST1                        = 0x02AK8975C_ST1_DRDY                   = 0x01AK8975C_HXL                        = 0x03AK8975C_CNTL                       = 0x0AAK8975C_CNTL_SINGLE                = 0x01# convert to s16 from two's complementto_s16 = lambda n: n - 0x10000 if n > 0x7FFF else nclass SensorAK8975C(object):    ''' AK8975C Simple Driver.        Parameters        ----------        bus : int            I2C bus number (e.g. 1).    '''    # sensor sensitivity (uT/LSB)    _sensitivity = 0.3    def __init__(self, bus):        self.bus = smbus.SMBus(bus)        # wake up and set bypass for AK8975C        self.bus.write_byte_data(MPU9150_ADDR, MPU9150_PWR_MGMT_1, 0)        self.bus.write_byte_data(MPU9150_ADDR, MPU9150_INT_PIN_CFG,                                 MPU9150_INT_PIN_CFG_I2C_BYPASS_EN)    def __del__(self):        self.bus.close()    def read(self):        ''' Get a sample.            Returns            -------            s : list                The sample in uT, [x, y, z].        '''        # request single shot        self.bus.write_byte_data(AK8975C_ADDR, AK8975C_CNTL,                                               AK8975C_CNTL_SINGLE)        # wait for data ready        r = self.bus.read_byte_data(AK8975C_ADDR, AK8975C_ST1)        while not (r & AK8975C_ST1_DRDY):            r = self.bus.read_byte_data(AK8975C_ADDR, AK8975C_ST1)        # read x, y, z        data = self.bus.read_i2c_block_data(AK8975C_ADDR, AK8975C_HXL, 6)        return [self._sensitivity * to_s16(data[0] | (data[1] << 8)),                self._sensitivity * to_s16(data[2] | (data[3] << 8)),                self._sensitivity * to_s16(data[4] | (data[5] << 8))]

Merging the sensor driver shown above with the code in the previous section willallow us to both sample and calibrate. We can also append the code shown below,which will allow us to store non-calibrated and calibrated samples to thenvisualize the results with any plotting library:

from time import sleepdef collect(fn, fs=10):    ''' Collect magnetometer samples        Parameters        ----------        fn : str            Output file.        fs : int (optional)            Approximate sampling frequency (Hz), default 10 Hz.    '''    print('Collecting [%s]. Ctrl-C to finish' % fn)    with open(fn, 'w') as f:        f.write('x,y,z\n')        try:            while True:                s = m.read()                f.write('%.1f,%.1f,%.1f\n' % (s[0], s[1], s[2]))                sleep(1./fs)        except KeyboardInterrupt: passm = Magnetometer('ak8975c', 1, 46.85)collect('ncal.csv')m.calibrate()

collect('cal.csv')






实际结果显示在以下交互式图表中: