<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>随心录</title>
  
  <link href="/blog/atom.xml" rel="self"/>
  
  <link href="/blog/"/>
  <updated>2017-10-21T10:09:50.000Z</updated>
  <id>/blog/</id>
  
  <author>
    <name>随心录Plus</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>树莓派之语音识别与语音合成</title>
    <link href="/blog/2017/10/07/%E6%A0%91%E8%8E%93%E6%B4%BE%E4%B9%8B%E8%AF%AD%E9%9F%B3%E8%AF%86%E5%88%AB%E4%B8%8E%E8%AF%AD%E9%9F%B3%E5%90%88%E6%88%90/"/>
    <id>/blog/2017/10/07/树莓派之语音识别与语音合成/</id>
    <published>2017-10-07T13:45:20.000Z</published>
    <updated>2017-10-21T10:09:50.000Z</updated>
    
    <content type="html"><![CDATA[<p>　　入手树莓派也有两年有余了，其实有很多有趣的想法，比如智能小车，智能感知，智能捕捉等等，也买了不少传感器件，组装小车的配件都买了，买组件的激情到是很高，但缺少了去实现动力<em>（是懒吧）</em>，也就一直尘封着，偶尔翻出来见见光之后就又再次封装了起来！</p>
<p>　　偶尔的一次看到了 <a href="http://yuyin.baidu.com/" target="_blank" rel="external">百度语音-永久免费智能语音开放平台</a> 感觉挻有趣的，于是决定搞起，至于动力，也许看过 <a href="/blog/2017/10/07/树莓派之-RGB-LED-跑马灯/">树莓派之 RGB LED 跑马灯</a> 就会明白，就不在累述，也是分享中的其中一个示例，此示例整体来说实现相对比较容易，百度语音也已为 Python 提供了在线访问的 <a href="http://yuyin.baidu.com/sdk" target="_blank" rel="external"> RestApi SDK</a>，所以需要我们自己来实现的内容相对还是比较少的。同时小米也推出了自己的 <a href="https://shuidi.mi.com/" target="_blank" rel="external">水滴平台</a> <em>[水滴平台为可以落地的小米全生态硬件产品提供语音服务，使用它可以为硬件设备提供功能，使用户能够以更直观的方式使用语音与设备进行交互。]</em> 我也算是个米粉，这里就不多说了，有兴趣的同学可以了解一下 ^_^  。</p>
<p>　　<strong>软件工程师的工作不是写程序， 而是合理使用工具解决问题</strong>，对此个人是比较认同的，术业有专攻，我们只需专注于做自己想做的一块，其余的就由专业的人去完成。于 Python 而言，其提供了很强大类库供我们去使用以及去定制化自己需要的！<br><a id="more"></a></p>
<p>　　说了这么多，先让我们了解一下此次示例使用的元件 树莓派、<del>USB 声卡</del>、百度语音 API、开发语言是 Python <em>（由于没有 USB 声卡，只好在笔记本上进行了演示，查看资料说树莓派端对 <code>pyaudio</code> 并不兼容，可以用 <code>arecord</code> 进行录音，目前为止还未在树莓派上做测试，当前也就只有按照 Win10 测试过程来讲了）</em>。<br><img src="/blog/2017/10/07/树莓派之语音识别与语音合成/images/RaspberryPi-speech-synthesis.jpg" alt=""></p>
<p>　　首先需要配置 百度语音 SDK 类库，执行 <code>sudo pip install baidu-aip</code> ，具体使用可以查看官方 <a href="http://yuyin.baidu.com/docs/asr/190" target="_blank" rel="external">在线语音识别 Python SDK 文档</a> ；执行 <code>sudo apt-get install python-wave*</code> 安装 wave 类库，执行 <code>sudo pip install pyaudio</code> 安装 pyaudio 类库 <em>（Windows系统f需要使用 pip 执行）</em>，相关环境安装好后，就可以编写代码啦。<br>　<br>　　本示例分为<strong>语音识别</strong>和<strong>语音合成</strong>以及<strong>本地录音</strong>功能，先了解一下文件目录结构：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">|——test.py           # 测试文件</div><div class="line">|——speech            # 语音 API 包目录</div><div class="line">|  |——__init__.py    # 语音 API 导出类</div><div class="line">|  |——rpi_record.py  # 本地录音 API</div><div class="line">|  |——rpi_speech.py  # 百度语音识别、语音合成功能封装</div></pre></td></tr></table></figure></p>
<p>　<br>　　来看一下 <code>rpi_speech.py</code> 文件，下面代码中的常量APP_ID 在百度云控制台中创建，常量 API_KEY 与 SECRET_KEY 是在创建完毕应用后，系统分配给用户的，均为字符串，用于标识用户，为访问做签名验证，可在 AI 服务控制台中的 <a href="http://yuyin.baidu.com/app" target="_blank" rel="external">应用列表</a> 中查看，如果还没有应用则需要先<strong>创建新应用</strong>，具体示例代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#!/usr/bin/env python</span></div><div class="line"><span class="comment"># -*- coding: utf-8 -*-</span></div><div class="line"></div><div class="line"><span class="string">"""</span></div><div class="line"><span class="string">  百度语音功能封装</span></div><div class="line"><span class="string">"""</span></div><div class="line"></div><div class="line"><span class="keyword">import</span> sys</div><div class="line"></div><div class="line"><span class="comment"># 引入百度 Speech SDK</span></div><div class="line"><span class="keyword">from</span> aip <span class="keyword">import</span> AipSpeech</div><div class="line"></div><div class="line"><span class="comment"># 定义常量</span></div><div class="line">APP_ID = <span class="string">'你的 App ID'</span></div><div class="line">API_KEY = <span class="string">'你的 Api Key'</span></div><div class="line">SECRET_KEY = <span class="string">'你的 Secret Key'</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">speech</span><span class="params">(file_path)</span>:</span></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">    语音识别</span></div><div class="line"><span class="string">    ---</span></div><div class="line"><span class="string">    *file_path 音频路径*</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">    原始语音的录音格式目前只支持评测 8k/16k 采样率 16bit 位深的单声道语音</span></div><div class="line"><span class="string">    压缩格式支持：pcm（不压缩）、wav、amr</span></div><div class="line"><span class="string">    系统支持语言种类：中文（zh）、粤语（ct）、英文（en）</span></div><div class="line"><span class="string">    """</span></div><div class="line">    print(file_path, <span class="string">"开始语音识别"</span>)</div><div class="line"></div><div class="line">    file_stream = _get_file_content(file_path)</div><div class="line">    result = speechs(file_stream)</div><div class="line"></div><div class="line">    print(<span class="string">"语音识别结束"</span>)</div><div class="line"></div><div class="line">    <span class="keyword">return</span> result</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">speechs</span><span class="params">(file_stream)</span>:</span></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">    语音识别</span></div><div class="line"><span class="string">    ---</span></div><div class="line"><span class="string">    *file_stream 音频流*</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">    原始语音的录音格式目前只支持评测 8k/16k 采样率 16bit 位深的单声道语音</span></div><div class="line"><span class="string">    压缩格式支持：pcm（不压缩）、wav、amr</span></div><div class="line"><span class="string">    系统支持语言种类：中文（zh）、粤语（ct）、英文（en）</span></div><div class="line"><span class="string">    """</span></div><div class="line"></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">     初始化AipSpeech对象</span></div><div class="line"><span class="string">    """</span></div><div class="line">    baiduAipSpeech = AipSpeech(APP_ID, API_KEY, SECRET_KEY)</div><div class="line">    <span class="comment"># 在线请求百度语音识别</span></div><div class="line">    result = baiduAipSpeech.asr(file_stream, <span class="string">"wav"</span>, <span class="number">16000</span>, &#123;<span class="string">'lan'</span>: <span class="string">'zh'</span>&#125;)</div><div class="line"></div><div class="line">    <span class="keyword">return</span> result</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">_get_file_content</span><span class="params">(file_path)</span>:</span></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">     读取文件</span></div><div class="line"><span class="string">    """</span></div><div class="line">    <span class="keyword">with</span> open(file_path, <span class="string">'rb'</span>) <span class="keyword">as</span> fp:</div><div class="line">        <span class="keyword">return</span> fp.read()</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">synthesis</span><span class="params">(text, file_path)</span>:</span></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">    语音合成</span></div><div class="line"><span class="string">    ----</span></div><div class="line"><span class="string">    *text 需要合成语音的文字*</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">    *file_path 保存语音合成文件路径*</span></div><div class="line"><span class="string">    """</span></div><div class="line"></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">     初始化AipSpeech对象</span></div><div class="line"><span class="string">    """</span></div><div class="line">    baiduAipSpeech = AipSpeech(APP_ID, API_KEY, SECRET_KEY)</div><div class="line"></div><div class="line">    print(<span class="string">"开始语音合成"</span>)</div><div class="line"></div><div class="line">    result = baiduAipSpeech.synthesis(</div><div class="line">        text, <span class="string">'zh'</span>, <span class="number">1</span>, &#123;<span class="string">"spd"</span>: <span class="number">5</span>, <span class="string">"per"</span>: <span class="number">4</span>, <span class="string">"pit"</span>: <span class="number">5</span>&#125;)</div><div class="line"></div><div class="line">    print(<span class="string">"语音合成结束"</span>)</div><div class="line"></div><div class="line">    <span class="comment"># 识别正确返回语音二进制 错误则返回dict 参照下面错误码</span></div><div class="line">    <span class="keyword">if</span> <span class="keyword">not</span> isinstance(result, dict):</div><div class="line">        <span class="keyword">with</span> open(file_path, <span class="string">'wb'</span>) <span class="keyword">as</span> f:</div><div class="line">            f.write(result)</div><div class="line"></div><div class="line">        print(file_path, <span class="string">",语音合成保存成功"</span>)</div><div class="line">        <span class="keyword">return</span> <span class="keyword">True</span></div><div class="line"></div><div class="line">    print(result, <span class="string">",语音保存失败"</span>)</div><div class="line">    <span class="keyword">return</span> <span class="keyword">False</span></div></pre></td></tr></table></figure></p>
<p>　<br>　　接下来是  <code>rpi_record.py</code> 文件，本地录音 API，本示例是使用 <code>pyaudio</code> 类库实现的，具体示例代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#!/usr/bin/env python</span></div><div class="line"><span class="comment"># -*- coding: utf-8 -*-</span></div><div class="line"></div><div class="line"><span class="string">"""</span></div><div class="line"><span class="string">本地录音 API</span></div><div class="line"><span class="string">"""</span></div><div class="line"></div><div class="line"><span class="keyword">import</span> base64</div><div class="line"><span class="keyword">import</span> datetime</div><div class="line"><span class="keyword">import</span> os</div><div class="line"><span class="keyword">import</span> sys</div><div class="line"><span class="keyword">import</span> time</div><div class="line"><span class="keyword">import</span> wave</div><div class="line"></div><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">from</span> pyaudio <span class="keyword">import</span> PyAudio, paInt16</div><div class="line"></div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">RpiApiRecord</span><span class="params">()</span>:</span></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">        本地录音 API</span></div><div class="line"><span class="string">        ---</span></div><div class="line"><span class="string">        原始语音的录音格式目前只支持评测 8k/16k 采样率 16bit 位深的单声道语音</span></div><div class="line"><span class="string">        压缩格式支持：pcm（不压缩）、wav、amr</span></div><div class="line"><span class="string">        系统支持语言种类：中文（zh）、粤语（ct）、英文（en）</span></div><div class="line"><span class="string">    """</span></div><div class="line"></div><div class="line">    __NUM_SAMPLES = <span class="number">2000</span>      <span class="comment"># pyAudio内部缓存的块的大小</span></div><div class="line">    __SAMPLING_RATE = <span class="number">16000</span>   <span class="comment"># 取样频率</span></div><div class="line">    __LEVEL = <span class="number">2000</span>            <span class="comment"># 声音保存的阈值</span></div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, compressed_fromat=<span class="string">".wav"</span>)</span>:</span></div><div class="line">        <span class="string">"""</span></div><div class="line"><span class="string">        *compressed_fromat 压缩格式支持：pcm（不压缩）、wav、amr*</span></div><div class="line"><span class="string">        """</span></div><div class="line">        self.__compressed_fromat = compressed_fromat</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__save_wave_file</span><span class="params">(self, file_patch, data)</span>:</span></div><div class="line">        <span class="string">"""将data中的数据保存到名为filename的WAV文件中"""</span></div><div class="line">        wf = wave.open(file_patch, <span class="string">'wb'</span>)</div><div class="line">        wf.setnchannels(<span class="number">1</span>)</div><div class="line">        wf.setsampwidth(<span class="number">2</span>)</div><div class="line">        wf.setframerate(self.__SAMPLING_RATE)</div><div class="line">        wf.writeframes(<span class="string">b""</span>.join(data))</div><div class="line">        wf.close()</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">def</span> <span class="title">record</span><span class="params">(self, total_time=<span class="number">5</span>)</span>:</span></div><div class="line">        <span class="string">"""</span></div><div class="line"><span class="string">        开启声音输入</span></div><div class="line"><span class="string">        ----</span></div><div class="line"><span class="string">        *total_time 录音时长，单位秒，默认5秒*</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">        返回结果：音频路径</span></div><div class="line"><span class="string">        """</span></div><div class="line"></div><div class="line">        save_buffer = []</div><div class="line">        first = <span class="keyword">True</span></div><div class="line">        begin_time = <span class="number">0</span></div><div class="line">        temp = <span class="number">0</span></div><div class="line"></div><div class="line">        pa = PyAudio()</div><div class="line">        stream = pa.open(format=paInt16, channels=<span class="number">1</span>, rate=self.__SAMPLING_RATE, input=<span class="keyword">True</span>,</div><div class="line">                         frames_per_buffer=self.__NUM_SAMPLES)</div><div class="line"></div><div class="line">        <span class="keyword">while</span> <span class="keyword">True</span>:</div><div class="line">            <span class="keyword">if</span> first:</div><div class="line">                <span class="comment"># 读入NUM_SAMPLES个取样</span></div><div class="line">                string_auto_data = stream.read(self.__NUM_SAMPLES)</div><div class="line"></div><div class="line">                <span class="comment"># 将读入的数据转换为数组</span></div><div class="line">                audio_data = np.fromstring(string_auto_data, dtype=np.long)</div><div class="line">                temp = np.max(audio_data)</div><div class="line">                print(temp)</div><div class="line"></div><div class="line">            <span class="keyword">if</span> temp &gt; self.__LEVEL <span class="keyword">and</span> first:</div><div class="line">                first = <span class="keyword">False</span></div><div class="line">                temp = <span class="number">0</span></div><div class="line">                print(<span class="string">"检测到信号，五秒后开始"</span>)</div><div class="line">                <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>, <span class="number">6</span>, <span class="number">1</span>):</div><div class="line">                    print(i, <span class="string">"s"</span>)</div><div class="line">                    time.sleep(<span class="number">1</span>)</div><div class="line"></div><div class="line">                print(<span class="string">'开始录音,计时'</span>, total_time, <span class="string">'秒'</span>)</div><div class="line">                begin_time = time.time()</div><div class="line"></div><div class="line">            <span class="keyword">if</span> first:</div><div class="line">                <span class="keyword">continue</span></div><div class="line"></div><div class="line">            <span class="comment"># NUM_SAMPLES 取样</span></div><div class="line">            string_auto_data = stream.read(self.__NUM_SAMPLES)</div><div class="line"></div><div class="line">            save_buffer.append(string_auto_data)</div><div class="line"></div><div class="line">            time_count = time.time() - begin_time</div><div class="line">            print(<span class="string">"录音进行中，第"</span>, time_count, <span class="string">"s"</span>)</div><div class="line">            <span class="keyword">if</span> time_count &gt; total_time:</div><div class="line">                <span class="string">"""</span></div><div class="line"><span class="string">                压缩格式支持</span></div><div class="line"><span class="string">                pcm（不压缩）、wav、amr</span></div><div class="line"><span class="string">                """</span></div><div class="line">                file_path = sys.path[<span class="number">0</span>] + <span class="string">"\\"</span> + datetime.datetime.now().strftime(</div><div class="line">                    <span class="string">"%Y-%m-%d_%H_%M_%S"</span>) + self.__compressed_fromat</div><div class="line"></div><div class="line">                self.__save_wave_file(file_path, save_buffer)</div><div class="line">                save_buffer = []</div><div class="line">                first = <span class="keyword">True</span></div><div class="line"></div><div class="line">                print(file_path, <span class="string">"保存成功正在进行语音识别"</span>)</div><div class="line"></div><div class="line">                <span class="keyword">return</span> file_path</div></pre></td></tr></table></figure></p>
<p>　<br>　　然后就是导出类文件 <code>__init__.py</code>，具体示例代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#!/usr/bin/env python</span></div><div class="line"><span class="comment"># -*- coding: utf-8 -*-</span></div><div class="line"><span class="string">"""</span></div><div class="line"><span class="string">音频 API</span></div><div class="line"><span class="string">"""</span></div><div class="line"></div><div class="line"><span class="keyword">from</span> .rpi_record <span class="keyword">import</span> RpiApiRecord</div><div class="line"><span class="keyword">from</span> .rpi_speech <span class="keyword">import</span> speech, speechs</div><div class="line"></div><div class="line">__version__ = <span class="string">"0.0.0.1"</span></div></pre></td></tr></table></figure></p>
<p>　<br>　　最后就是见证奇迹的时刻了，是不是有些激动，创建 <code>test.py</code> 文件，具体示例代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#!/usr/bin/env python</span></div><div class="line"><span class="comment"># -*- coding: utf-8 -*-</span></div><div class="line"><span class="keyword">import</span> datetime</div><div class="line"><span class="keyword">import</span> sys</div><div class="line"></div><div class="line"><span class="keyword">from</span> speech <span class="keyword">import</span> RpiApiRecord, rpi_speech</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">test_speech</span><span class="params">()</span>:</span></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">    百度语音识别功能</span></div><div class="line"><span class="string">    ----</span></div><div class="line"><span class="string">    *返回：语音识别的结果*</span></div><div class="line"><span class="string">    """</span></div><div class="line">    file_path = sys.path[<span class="number">0</span>] + <span class="string">"\\2017-09-22_09_37_45.wav"</span></div><div class="line">    <span class="string">"""调用百度语音识别接口，接收语音识别结果"""</span></div><div class="line">    result = rpi_speech.speech(file_path)</div><div class="line"></div><div class="line">    print(result)</div><div class="line">    <span class="keyword">return</span> result</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">test_speechs</span><span class="params">()</span>:</span></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">    测试本地录音，百度语音识别功能</span></div><div class="line"><span class="string">    ----</span></div><div class="line"><span class="string">    *返回：语音识别的结果*</span></div><div class="line"><span class="string">    """</span></div><div class="line">    <span class="comment"># 初始化 本地录音PAI RpiApiRecord</span></div><div class="line">    api_record = RpiApiRecord(<span class="string">".wav"</span>)</div><div class="line"></div><div class="line">    <span class="string">"""接收本地录音存放地址"""</span></div><div class="line">    file_path = api_record.record(<span class="number">10</span>)</div><div class="line"></div><div class="line">    <span class="string">"""调用百度语音识别接口，接收语音识别结果"""</span></div><div class="line">    result = rpi_speech.speech(file_path)</div><div class="line"></div><div class="line">    print(result)</div><div class="line">    <span class="keyword">return</span> result</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">test_synthesis</span><span class="params">()</span>:</span></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">    测试百度语音合成功能</span></div><div class="line"><span class="string">    ----</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">    *返回：语音合成文件路径*</span></div><div class="line"><span class="string">    """</span></div><div class="line">    <span class="string">"""保存语音合成文件路径"""</span></div><div class="line">    file_path = sys.path[<span class="number">0</span>] + <span class="string">"\\"</span> + datetime.datetime.now().strftime(</div><div class="line">        <span class="string">"%Y-%m-%d_%H_%M_%S"</span>) + <span class="string">".wav"</span></div><div class="line"></div><div class="line">    result = rpi_speech.synthesis(<span class="string">"你好吗，最近过得怎么样呢，嘿嘿！"</span>, file_path)</div><div class="line">    print(<span class="string">"语音合成结果："</span>, result)</div><div class="line"></div><div class="line">    <span class="keyword">return</span> file_path</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">test_synthesis_speech</span><span class="params">()</span>:</span></div><div class="line">    <span class="string">"""</span></div><div class="line"><span class="string">    百度语音合成后，使用百度语音识别</span></div><div class="line"><span class="string">    """</span></div><div class="line">    file_path = test_synthesis()</div><div class="line"></div><div class="line">    <span class="string">"""调用百度语音识别接口，接收语音识别结果"""</span></div><div class="line">    result = rpi_speech.speech(file_path)</div><div class="line"></div><div class="line">    print(result)</div><div class="line"></div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</div><div class="line">    print(<span class="string">"进入 main 方法"</span>)</div><div class="line"></div><div class="line">    <span class="comment"># test_speech()</span></div><div class="line"></div><div class="line">    test_speechs()</div><div class="line"></div><div class="line">    <span class="comment"># test_synthesis()</span></div><div class="line"></div><div class="line">    <span class="comment"># test_synthesis_speech() # 这个示例并没有成功，总是返回错误码：3301（请上传清晰的音频），不知道是不是因为百度对音频做了处理</span></div><div class="line"></div><div class="line">    print(<span class="string">"离开 main 方法"</span>)</div></pre></td></tr></table></figure></p>
<p>　<br>　　最基础的语音识别是不是感觉挻容易实现，其实可以在此基础上做些扩展，比如当前我想的，可以通过声音定位声源，测试声距，通过测定声源位置，启动并驱动电机，使摄像头捕捉人像并跟踪，同时摄像头也可以识别出人脸等，是不是很有画面感呢！再者还可以实现人机对话，声音感知等等，越想是不是越激动啦，过程还是需要自己动手去实现，乐趣更多的还是在实践的过程中 ^_^。<br>　<br><em>参考文档：</em></p>
<ul>
<li><em><a href="https://www.urlteam.org/2016/05/python语音智能对话聊天机器人，linux树莓派双平台兼容/" target="_blank" rel="external">python语音智能对话聊天机器人，linux&amp;&amp;树莓派双平台兼容</a></em></li>
<li><em><a href="http://yuyin.baidu.com/docs/asr/190" target="_blank" rel="external">百度在线语音识别 Python SDK 文档</a></em></li>
<li><em><a href="http://yuyin.baidu.com/docs/tts/196" target="_blank" rel="external">百度在线语音合成 Python SDK 文档</a></em></li>
</ul>
<p><em>文中图片引用：</em></p>
<ul>
<li><em><a href="https://www.raspberrypi.org/" target="_blank" rel="external">Raspberr Pi 官网</a></em></li>
<li><em><a href="http://yuyin.baidu.com/" target="_blank" rel="external">百度语言</a></em></li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;　　入手树莓派也有两年有余了，其实有很多有趣的想法，比如智能小车，智能感知，智能捕捉等等，也买了不少传感器件，组装小车的配件都买了，买组件的激情到是很高，但缺少了去实现动力&lt;em&gt;（是懒吧）&lt;/em&gt;，也就一直尘封着，偶尔翻出来见见光之后就又再次封装了起来！&lt;/p&gt;
&lt;p&gt;　　偶尔的一次看到了 &lt;a href=&quot;http://yuyin.baidu.com/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;百度语音-永久免费智能语音开放平台&lt;/a&gt; 感觉挻有趣的，于是决定搞起，至于动力，也许看过 &lt;a href=&quot;/blog/2017/10/07/树莓派之-RGB-LED-跑马灯/&quot;&gt;树莓派之 RGB LED 跑马灯&lt;/a&gt; 就会明白，就不在累述，也是分享中的其中一个示例，此示例整体来说实现相对比较容易，百度语音也已为 Python 提供了在线访问的 &lt;a href=&quot;http://yuyin.baidu.com/sdk&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt; RestApi SDK&lt;/a&gt;，所以需要我们自己来实现的内容相对还是比较少的。同时小米也推出了自己的 &lt;a href=&quot;https://shuidi.mi.com/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;水滴平台&lt;/a&gt; &lt;em&gt;[水滴平台为可以落地的小米全生态硬件产品提供语音服务，使用它可以为硬件设备提供功能，使用户能够以更直观的方式使用语音与设备进行交互。]&lt;/em&gt; 我也算是个米粉，这里就不多说了，有兴趣的同学可以了解一下 ^_^  。&lt;/p&gt;
&lt;p&gt;　　&lt;strong&gt;软件工程师的工作不是写程序， 而是合理使用工具解决问题&lt;/strong&gt;，对此个人是比较认同的，术业有专攻，我们只需专注于做自己想做的一块，其余的就由专业的人去完成。于 Python 而言，其提供了很强大类库供我们去使用以及去定制化自己需要的！&lt;br&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="Raspberry Pi" scheme="/blog/tags/Raspberry-Pi/"/>
    
      <category term="Python" scheme="/blog/tags/Python/"/>
    
      <category term="Speech" scheme="/blog/tags/Speech/"/>
    
  </entry>
  
  <entry>
    <title>树莓派之 RGB LED 跑马灯</title>
    <link href="/blog/2017/10/07/%E6%A0%91%E8%8E%93%E6%B4%BE%E4%B9%8B-RGB-LED-%E8%B7%91%E9%A9%AC%E7%81%AF/"/>
    <id>/blog/2017/10/07/树莓派之-RGB-LED-跑马灯/</id>
    <published>2017-10-07T06:48:21.000Z</published>
    <updated>2017-10-21T10:09:24.000Z</updated>
    
    <content type="html"><![CDATA[<p>  　　很早之前就有写过使用 Arduino 开发板（<code>C++</code>） 和 树莓派的 GPIO（<code>Python</code>） 控制 LED 灯相关示例，只是比较的零碎，完全是个人兴趣驱动，当时过程中遇到的一些问题，也没有很好的记录下来，由于当时比较懒吧<em>（不过，现在仍是依旧）</em>。</p>
<p>  　　最近由于工作需要，于是乎又拾起了兴趣，拼凑了一个相对比较完善的示例，过程中也入了一些坑，由于对 RGB 全彩 LED  特性不是很了解，特别在调试时，用了不少时间，真的是眼睛快被闪瞎了！</p>
<p>  　　之所以能更加完善，完全是因为需要为组内来一场生动的分享<em>（是不是真的生动，我也无从而知了）</em>，分享主题为 <strong>趣玩 Python</strong>，Python 还能玩 LED？嗯，是的，既然是趣玩，当然是拿些大家不太熟悉，但又不太陌生的东东来玩玩吖，于是乎我拿出了百分之一百二精力，一个月的时间里，时常搞到凌晨一二点，第二天又需早早爬起来上班，当然啦，该示例只是其中之一，其实在较早的时候，这样的作息也属于常态，<strong>加班</strong>几乎成为了程序员的代名词，问我累不累，不，怎么会累呢，一切为工作！哈哈，价值观还可以吧！其实更多的是习惯了这样的生活，也就不觉得怎样了！<br><a id="more"></a></p>
<p>  　　好了，回归正题，先了解一下，示例中使用的元件 <a href="https://www.raspberrypi.org/" target="_blank" rel="external">树莓派</a>、<a href="https://baike.baidu.com/item/RGB%20Led/7977166?fr=aladdin" target="_blank" rel="external">RGB LED</a>、220Ω <a href="https://baike.baidu.com/item/电阻器/10614576?fr=aladdin&amp;fromid=3315365&amp;fromtitle=电阻" target="_blank" rel="external">电阻</a>、<a href="https://baike.baidu.com/item/面包板/4703361?fr=aladdin" target="_blank" rel="external">面包板</a>，公母<a href="https://baike.baidu.com/item/杜邦线/197049?fr=aladdin" target="_blank" rel="external">杜邦线</a>，开发语言是 <a href="https://www.python.org/" target="_blank" rel="external">Python</a> <em>（Python 分 2.X 版本 和  3.X 版本，语法上是有区别的，示例使用的 Python3.X 版本）</em>，不得不说，这是我做过的 PPT 中最好看和最满意的了。<br><img src="/blog/2017/10/07/树莓派之-RGB-LED-跑马灯/images/GPIO-RGB-LED.jpg" alt=""><br> 　<br> 　　了解过 <strong>树莓派</strong> 的同学应该知道，树莓派之所以很畅销，个人认识最大的原因是树莓派集成了 丰富的 <strong>GPIO</strong>（General Purpose Input-Output），它们是程序与外部世界对话的窗口，增强了趣味性。再有就是强大的开源社区以及第三方对树莓派大力支持，这也是当下最有趣味的板子之一。本示例是使用 Python，树莓派搭载的系统是基于 Debian Stretch 的 <a href="https://www.raspberrypi.org/downloads/raspbian/" target="_blank" rel="external">Raspbian</a>，Python 和 Linux 有者强大的开源社区。掌握了这两样工具的工具（元工具），网上遍地是趁手的兵器。先让我们了解一下树莓派的 <a href="http://shumeipai.nxez.com/raspberry-pi-pins-version-40" target="_blank" rel="external">GPIO 引脚</a>。<br><img src="/blog/2017/10/07/树莓派之-RGB-LED-跑马灯/images/RaspberryPi-GPIO.jpg" alt=""></p>
<p>　　RGB LED 多元的特性，可以通过程序实现色彩绚丽灯光效果，不过，在使用之前需要先确认一下手中的 RGB LED 是共阴还是共阳，所谓共阴就是公共端接负极 <code>-</code>，而共阳就是公共端接正极 <code>+</code>，一般商品介绍上会有说明，或者如果看到 RGB LED 的引脚有 GND 字样，说明是共阴的，也可以自行测试；这点很重要，这会影响接下来的灯光效果实现及调试。调试时建议串连一个 220Ω 的电阻，防止因电流过大而烧坏了 RGB LED。</p>
<p>　　 首先确保树莓派安装了 Python3.X ，一般系统会自带 Pthon2.7 以及 RPi.GPIO 模块程序包<em>（该包提供了一个在 Raspberry Pi 中控制  GPIO 的类）</em>，如果未安装，则执行 <code>sudo apt-get install python3</code> 进行安装 Python3，执行 <code>sudo apt-get install RPi.GPIO</code> 安装 RPi.GPIO 模块程序包<em>（Python 是区分大小写的，你没看错，就是 <code>RPi.GPIO</code> ，<code>i</code> 是小写的，写错了会报错的）</em>，必要的软件安装好，就可以愉快的编码了。</p>
<p>　　开始之前还是需要再了解一下 <a href="https://baike.baidu.com/item/脉冲宽度调制/10813756?fr=aladdin&amp;fromid=3034961&amp;fromtitle=PWM" target="_blank" rel="external">PWM</a>，PWM 脉冲宽度调制的英文缩写，在一个脉冲循环内，通电时间相对于总时间所占的比例叫<a href="https://baike.baidu.com/item/占空比/3652044?fr=aladdin" target="_blank" rel="external">占空比</a>，方波的占空比为50%，占空比为0.5，说明正电平所占时间为0.5个周期。是不是似懂非懂，在本示例只需要知道 PWM 可以控制 RGB LED 亮度即可，但真正做一个产品时，对相关知识点不能完全明白的掌握，会遇到不少麻烦，也是会有很大的风险的。</p>
<p>　　相信很多同学对<strong>万能充电器</strong>，在熟悉不过了，此时就不得不说那时是 <strong>诺基亚</strong> 王朝，是否还记得高中时为了给手机充器，不得不像防贼似的防着班主任，话说你的东东有没有被班主任撞见过呢！对，该示例就是实现那迷人的万能充电器里面的跑马灯，嗯，那我们开始吧，执行 <code>sudo nano led.py</code> 创建一个名称为 <code>led.py</code> 文件， 将下面的代码复制到该文件中保存，执行 <code>sudo python led.py</code> 就可以看到效果了，聪明的你对 RGB LED 的接线应该不在话下吧，具体示例代码如下：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#!/usr/bin/env python</span></div><div class="line"><span class="comment"># -*- coding: utf-8 -*-</span></div><div class="line"></div><div class="line"><span class="keyword">import</span> RPi.GPIO <span class="keyword">as</span> GPIO</div><div class="line"><span class="keyword">import</span> time</div><div class="line"><span class="keyword">import</span> random</div><div class="line"></div><div class="line"><span class="comment"># 指定引脚 共阴LED（R、G、B、-）</span></div><div class="line">R, G, B, GND = <span class="number">11</span>, <span class="number">13</span>, <span class="number">15</span>, <span class="number">9</span></div><div class="line"></div><div class="line"><span class="comment"># BOARD 编码方式</span></div><div class="line">GPIO.setmode(GPIO.BOARD)</div><div class="line"></div><div class="line"><span class="comment"># 设置引脚为输出模式</span></div><div class="line">GPIO.setup(R, GPIO.OUT)</div><div class="line">GPIO.setup(G, GPIO.OUT)</div><div class="line">GPIO.setup(B, GPIO.OUT)</div><div class="line"></div><div class="line"><span class="comment"># PWM 来制作呼吸灯效果，创建频率为 70HZ 的 PWM 实例</span></div><div class="line">pwmR = GPIO.PWM(R, <span class="number">70</span>)</div><div class="line">pwmG = GPIO.PWM(G, <span class="number">70</span>)</div><div class="line">pwmB = GPIO.PWM(B, <span class="number">70</span>)</div><div class="line"></div><div class="line"><span class="comment"># 开始脉宽调制，参数范围为： (0.0 &lt;= dc &lt;= 100.0)</span></div><div class="line"><span class="comment"># 共阴时，方波的占空比 100 代表全亮，0 代表全暗</span></div><div class="line"><span class="comment"># 共阳时，方波的占空比 100 代表全暗，0 代表全亮</span></div><div class="line">pwmR.start(<span class="number">50</span>)</div><div class="line">pwmG.start(<span class="number">50</span>)</div><div class="line">pwmB.start(<span class="number">50</span>)</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">open_led</span><span class="params">()</span>:</span></div><div class="line">    <span class="string">"""开启 LED"""</span></div><div class="line">    <span class="keyword">try</span>:</div><div class="line">        count = <span class="number">0</span></div><div class="line">        <span class="keyword">while</span> <span class="keyword">True</span>:</div><div class="line">            count = count + <span class="number">1</span></div><div class="line">            <span class="keyword">if</span> count &gt; <span class="number">1</span>:</div><div class="line">                <span class="keyword">return</span></div><div class="line"></div><div class="line">            t = <span class="number">0.4</span></div><div class="line"></div><div class="line">            <span class="comment"># 红色灯全亮，绿灯，蓝灯全暗（红色）</span></div><div class="line">            set_change_duty_cycle(<span class="number">100</span>, <span class="number">0</span>, <span class="number">0</span>, t)</div><div class="line"></div><div class="line">            <span class="comment"># 绿色灯全亮，红灯，蓝灯全暗（绿色）</span></div><div class="line">            set_change_duty_cycle(<span class="number">0</span>, <span class="number">100</span>, <span class="number">0</span>, t)</div><div class="line"></div><div class="line">            <span class="comment"># 蓝色灯全亮，红灯，绿灯全暗（蓝色）</span></div><div class="line">            set_change_duty_cycle(<span class="number">0</span>, <span class="number">0</span>, <span class="number">100</span>, t)</div><div class="line"></div><div class="line">            <span class="comment"># 红灯，绿灯全亮，蓝灯全暗（黄色）</span></div><div class="line">            set_change_duty_cycle(<span class="number">100</span>, <span class="number">100</span>, <span class="number">0</span>, t)</div><div class="line"></div><div class="line">            <span class="comment"># 红灯，蓝灯全亮，绿灯全暗（洋红色）</span></div><div class="line">            set_change_duty_cycle(<span class="number">100</span>, <span class="number">0</span>, <span class="number">100</span>, t)</div><div class="line"></div><div class="line">            <span class="comment"># 绿灯，蓝灯全亮，红灯全暗（青色）</span></div><div class="line">            set_change_duty_cycle(<span class="number">0</span>, <span class="number">100</span>, <span class="number">100</span>, t)</div><div class="line"></div><div class="line">            <span class="comment"># 红灯，绿灯，蓝灯全亮（白色）</span></div><div class="line">            set_change_duty_cycle(<span class="number">100</span>, <span class="number">100</span>, <span class="number">100</span>, t)</div><div class="line"></div><div class="line">            <span class="comment"># 调整红绿蓝LED的各个颜色的亮度组合出各种颜色</span></div><div class="line">            for_set_change_duty_cycle()</div><div class="line"></div><div class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</div><div class="line">        print(e)</div><div class="line">    <span class="keyword">finally</span>:</div><div class="line">        stop()</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">set_change_duty_cycle</span><span class="params">(_r, _g, _b, _t)</span>:</span></div><div class="line">    <span class="string">"设置 RGB 亮度"</span></div><div class="line">    pwmR.ChangeDutyCycle(_r)</div><div class="line">    pwmG.ChangeDutyCycle(_g)</div><div class="line">    pwmB.ChangeDutyCycle(_b)</div><div class="line">    time.sleep(_t)</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">set_single_change_duty_cycle</span><span class="params">(_pwm, _l, _t)</span>:</span></div><div class="line">    <span class="string">"""设置单 RGB 亮度"""</span></div><div class="line">    _pwm.ChangeDutyCycle(_l)</div><div class="line">    time.sleep(_t)</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">for_set_change_duty_cycle</span><span class="params">()</span>:</span></div><div class="line">    <span class="string">"设置 RGB 亮度-跑马灯"</span></div><div class="line">    t = <span class="number">0.01</span></div><div class="line"></div><div class="line">    pwmG.ChangeDutyCycle(<span class="number">0</span>)</div><div class="line">    pwmB.ChangeDutyCycle(<span class="number">0</span>)</div><div class="line">    <span class="keyword">for</span> r <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):  <span class="comment"># 红全亮，绿、蓝全暗</span></div><div class="line">        set_single_change_duty_cycle(pwmR, r, t)</div><div class="line">    <span class="keyword">for</span> r <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):  <span class="comment"># 红、绿、蓝全暗</span></div><div class="line">        set_single_change_duty_cycle(pwmR, <span class="number">100</span> - r, t)</div><div class="line"></div><div class="line">    pwmR.ChangeDutyCycle(<span class="number">0</span>)</div><div class="line">    pwmB.ChangeDutyCycle(<span class="number">0</span>)</div><div class="line">    <span class="keyword">for</span> g <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">100</span>, <span class="number">1</span>):  <span class="comment"># 绿全亮，红、蓝全暗</span></div><div class="line">        set_single_change_duty_cycle(pwmG, g, t)</div><div class="line">    <span class="keyword">for</span> g <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">100</span>, <span class="number">1</span>):  <span class="comment"># 红、绿、蓝全暗</span></div><div class="line">        set_single_change_duty_cycle(pwmG, <span class="number">100</span> - g, t)</div><div class="line"></div><div class="line">    pwmR.ChangeDutyCycle(<span class="number">0</span>)</div><div class="line">    pwmG.ChangeDutyCycle(<span class="number">0</span>)</div><div class="line">    <span class="keyword">for</span> b <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):  <span class="comment"># 蓝全亮，红、绿全暗</span></div><div class="line">        set_single_change_duty_cycle(pwmB, b, t)</div><div class="line">    <span class="keyword">for</span> b <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):  <span class="comment"># 红、绿、蓝全暗</span></div><div class="line">        set_single_change_duty_cycle(pwmB, <span class="number">100</span> - b, t)</div><div class="line"></div><div class="line">    count, denominator = <span class="number">0</span>, <span class="number">7</span></div><div class="line">    <span class="keyword">for</span> n <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">10</span>):</div><div class="line">        print(n)</div><div class="line">        count += <span class="number">1</span></div><div class="line">        <span class="keyword">if</span> count % denominator == <span class="number">0</span>:  <span class="comment"># 红全亮，绿、蓝全暗</span></div><div class="line">            <span class="keyword">for</span> g <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):</div><div class="line">                set_change_duty_cycle(g, g, <span class="number">100</span> - g, t)</div><div class="line">            <span class="keyword">for</span> g <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):</div><div class="line">                set_single_change_duty_cycle(pwmG, <span class="number">100</span> - g, t)</div><div class="line">        <span class="keyword">if</span> count % denominator == <span class="number">1</span>:  <span class="comment"># 绿全亮，红、蓝全暗</span></div><div class="line">            <span class="keyword">for</span> b <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):</div><div class="line">                set_change_duty_cycle(<span class="number">100</span> - b, b, b, t)</div><div class="line">            <span class="keyword">for</span> b <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):</div><div class="line">                set_single_change_duty_cycle(pwmB, <span class="number">100</span> - b, t)</div><div class="line">        <span class="keyword">if</span> count % denominator == <span class="number">2</span>:  <span class="comment"># 蓝全亮，红、绿全暗</span></div><div class="line">            <span class="keyword">for</span> r <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):</div><div class="line">                set_change_duty_cycle(r, <span class="number">100</span> - r, r, t)</div><div class="line">            <span class="keyword">for</span> r <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):</div><div class="line">                set_single_change_duty_cycle(pwmR, <span class="number">100</span> - r, t)</div><div class="line">        <span class="keyword">if</span> count % denominator == <span class="number">3</span>:  <span class="comment"># 红全亮</span></div><div class="line">            <span class="keyword">for</span> g <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):</div><div class="line">                set_single_change_duty_cycle(pwmR, g, t)</div><div class="line">        <span class="keyword">if</span> count % denominator == <span class="number">4</span>:  <span class="comment"># 绿全亮</span></div><div class="line">            <span class="keyword">for</span> b <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):</div><div class="line">                set_single_change_duty_cycle(pwmG, b, t)</div><div class="line">        <span class="keyword">if</span> count % denominator == <span class="number">5</span>:  <span class="comment"># 红、绿、蓝全暗</span></div><div class="line">            <span class="keyword">for</span> r <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):</div><div class="line">                set_change_duty_cycle(<span class="number">100</span> - r, <span class="number">100</span> - r, <span class="number">100</span> - r, t)</div><div class="line">        <span class="keyword">if</span> count % denominator == <span class="number">6</span>:  <span class="comment"># 红、绿、蓝全暗</span></div><div class="line">            set_change_duty_cycle(<span class="number">50</span>, <span class="number">50</span>, <span class="number">50</span>, t)</div><div class="line">            <span class="keyword">for</span> r <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">61</span>, <span class="number">1</span>):  <span class="comment"># 红、绿、蓝随机</span></div><div class="line">                set_change_duty_cycle(random.choice([<span class="number">0</span>, <span class="number">50</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">100</span>, <span class="number">0</span>, <span class="number">100</span>]), random.choice(</div><div class="line">                    [<span class="number">100</span>, <span class="number">50</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">100</span>, <span class="number">100</span>, <span class="number">0</span>, <span class="number">0</span>]), random.choice([<span class="number">50</span>, <span class="number">50</span>, <span class="number">50</span>, <span class="number">0</span>, <span class="number">100</span>, <span class="number">0</span>, <span class="number">100</span>]), t + <span class="number">0.08</span>)</div><div class="line">            <span class="keyword">for</span> r <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):  <span class="comment"># 红、绿、蓝全暗</span></div><div class="line">                set_change_duty_cycle(<span class="number">100</span> - r, <span class="number">100</span> - r, <span class="number">100</span> - r, t)</div><div class="line"></div><div class="line">    <span class="keyword">for</span> r <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):  <span class="comment"># 红、绿、蓝全暗</span></div><div class="line">        set_change_duty_cycle(<span class="number">100</span> - r, <span class="number">100</span> - r, <span class="number">100</span> - r, t)</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">stop</span><span class="params">()</span>:</span></div><div class="line">    <span class="string">"""停止闪烁，并释放资源"""</span></div><div class="line">    pwmR.stop()</div><div class="line">    pwmG.stop()</div><div class="line">    pwmB.stop()</div><div class="line">    GPIO.cleanup()  <span class="comment"># 防止烧坏板子</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</div><div class="line">    open_led()</div></pre></td></tr></table></figure></p>
<p>　<br><em>参考文档：</em></p>
<ul>
<li><em><a href="http://shumeipai.nxez.com/2017/06/01/raspberry-pi-gpio-control-rgb-color-led-lights.html" target="_blank" rel="external">树莓派GPIO入门：GPIO控制RGB彩色LED灯</a></em></li>
<li><em><a href="http://shumeipai.nxez.com/raspberry-pi-pins-version-40" target="_blank" rel="external">树莓派 40Pin 引脚对照表</a></em></li>
</ul>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;  　　很早之前就有写过使用 Arduino 开发板（&lt;code&gt;C++&lt;/code&gt;） 和 树莓派的 GPIO（&lt;code&gt;Python&lt;/code&gt;） 控制 LED 灯相关示例，只是比较的零碎，完全是个人兴趣驱动，当时过程中遇到的一些问题，也没有很好的记录下来，由于当时比较懒吧&lt;em&gt;（不过，现在仍是依旧）&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;  　　最近由于工作需要，于是乎又拾起了兴趣，拼凑了一个相对比较完善的示例，过程中也入了一些坑，由于对 RGB 全彩 LED  特性不是很了解，特别在调试时，用了不少时间，真的是眼睛快被闪瞎了！&lt;/p&gt;
&lt;p&gt;  　　之所以能更加完善，完全是因为需要为组内来一场生动的分享&lt;em&gt;（是不是真的生动，我也无从而知了）&lt;/em&gt;，分享主题为 &lt;strong&gt;趣玩 Python&lt;/strong&gt;，Python 还能玩 LED？嗯，是的，既然是趣玩，当然是拿些大家不太熟悉，但又不太陌生的东东来玩玩吖，于是乎我拿出了百分之一百二精力，一个月的时间里，时常搞到凌晨一二点，第二天又需早早爬起来上班，当然啦，该示例只是其中之一，其实在较早的时候，这样的作息也属于常态，&lt;strong&gt;加班&lt;/strong&gt;几乎成为了程序员的代名词，问我累不累，不，怎么会累呢，一切为工作！哈哈，价值观还可以吧！其实更多的是习惯了这样的生活，也就不觉得怎样了！&lt;br&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="Raspberry Pi" scheme="/blog/tags/Raspberry-Pi/"/>
    
      <category term="Python" scheme="/blog/tags/Python/"/>
    
      <category term="RGB LED" scheme="/blog/tags/RGB-LED/"/>
    
  </entry>
  
  <entry>
    <title>树莓派搭建 GitLab</title>
    <link href="/blog/2017/10/05/%E8%8E%93%E6%B4%BE%E6%90%AD%E5%BB%BA-GitLab/"/>
    <id>/blog/2017/10/05/莓派搭建-GitLab/</id>
    <published>2017-10-05T12:43:35.000Z</published>
    <updated>2017-10-21T10:09:11.000Z</updated>
    
    <content type="html"><![CDATA[<p>　　不记得是什么时候，在树莓派上搭建了供个人使用的 Git 仓库，不是 GitLab 或者是其他 Git 管理平台，就是最原生的 Git 服务，也不觉得有什么奇怪，就这样使用了很久 ：)</p>
<p>　　八天国庆假期，少了往年游玩的激情，也没有其他什么事情，整日宅在自己的小窝里躲避风和雨，省得过于清闲而又浮想翩翩，于是乎想利用树莓派搭建 GIT 管理平台；当下最为流行开源平台为 GitLab 吧，日常工作中几乎每天与其打交道（无外乎最多的就是 pull、push 吧，偶尔配置一二，算不上熟络）。<br><a id="more"></a></p>
<h2 id="首先让我们先了解安装-GitLab-的需求"><a href="#首先让我们先了解安装-GitLab-的需求" class="headerlink" title="首先让我们先了解安装 GitLab 的需求"></a>首先让我们先了解安装 <a href="https://docs.gitlab.com.cn/ce/install/requirements.html#gitlab" target="_blank" rel="external">GitLab 的需求</a></h2><h5 id="操作系统"><a href="#操作系统" class="headerlink" title="操作系统"></a>操作系统</h5><ul>
<li>GitLab 是专为 Unix 操作系统开发的。 GitLab 不可 运行在 Windows 操作系统上，而且近期也没有考虑支持 Windows。可以在 Linux 虚拟机上或者 Docker 上来安装 GitLab。</li>
</ul>
<h5 id="CPU"><a href="#CPU" class="headerlink" title="CPU"></a>CPU</h5><ul>
<li>1 核心 CPU 最多支持100个用户，所有的 Workers 和后台任务都在同一个核心工作这将导致 GitLab 服务响应会有点缓慢。</li>
<li>2核心 支持500用户，这也是 <strong>官方推荐</strong> 的最低标准。<br>…</li>
</ul>
<h5 id="Memory"><a href="#Memory" class="headerlink" title="Memory"></a>Memory</h5><ul>
<li>1GB 物理内存 + 3GB 交换分区 是最低的要求，但我们 强烈反对 使用这样的配置。 查看下面 <a href="https://docs.gitlab.com.cn/ce/install/requirements.html#unicorn-workers" target="_blank" rel="external">Unicorn Workers</a> 章节获取更多建议。</li>
<li>2GB 物理内存 + 2GB 交换分区 支持100用户，但服务响应会很慢。</li>
<li>4GB 物理内存 支持100用户，也是 <strong>官方推荐</strong> 的配置。<br>…</li>
</ul>
<h2 id="再来了解-树莓派-配置"><a href="#再来了解-树莓派-配置" class="headerlink" title="再来了解 树莓派 配置"></a>再来了解 <a href="https://www.raspberrypi.org/blog/raspberry-pi-3-on-sale/" target="_blank" rel="external">树莓派</a> 配置</h2><h5 id="系统"><a href="#系统" class="headerlink" title="系统"></a>系统</h5><ul>
<li>基于 Debian Stretch 的 <a href="https://www.raspberrypi.org/downloads/raspbian/" target="_blank" rel="external">Raspbian</a></li>
</ul>
<h5 id="CPU-1"><a href="#CPU-1" class="headerlink" title="CPU"></a>CPU</h5><ul>
<li>四核 1.2GHz 64位 ARM Cortex-A53 CPU</li>
</ul>
<h5 id="Memory-1"><a href="#Memory-1" class="headerlink" title="Memory"></a>Memory</h5><ul>
<li>1GB RAM</li>
</ul>
<h5 id="Other"><a href="#Other" class="headerlink" title="Other"></a>Other</h5><ul>
<li>BCM43438 无线局域网和蓝牙低功耗（BLE）</li>
</ul>
<h2 id="GitLab-安装"><a href="#GitLab-安装" class="headerlink" title="GitLab 安装"></a>GitLab 安装</h2><p>　　嗯，是的，官方推荐的最低配置是 CPU 2核，4G 物理内存，能正常访问 GitLab 而不会太缓慢，这点很重要，在调试过程中也被这个坑了良久；而能运行 GitLab 最低配置是 CPU 1核，内存 1G  + 3GB 交换分区 （比 1G 还小的内存估计也不好找了吧），嗯，是的，是能运行，在不考虑性能的前提下，而且也很是考验使用者的耐心，堪比 2G 时代的速度，不多说了，忍，自行体会吧！</p>
<p>　　了解了软硬件的需求，接下来按照 <a href="https://www.gitlab.com.cn/installation/" target="_blank" rel="external">官方文档</a> 进行安装 GitLab ，这一步应该没什么问题，要选择对应的系统版本，我的硬件是树莓派，选择的 <a href="https://www.gitlab.com.cn/installation/#raspberry-pi-2" target="_blank" rel="external">raspberry-pi-2</a> 版本，安装到最后应该会看到打印的 GitLab 官方 Logo ，此时说明已经安装完成。</p>
<blockquote>
<p>如果在安装中下载过慢，可以直接使用迅雷加速下载对应的版本 <a href="https://packages.gitlab.com/gitlab/" target="_blank" rel="external">GitLab 安装文件</a>，然后上传到系统中安装路径中进行安装，如 Debian 文件路径 <code>/var/cache/apt/archives/partial</code>。</p>
</blockquote>
<h2 id="GitLab-配置"><a href="#GitLab-配置" class="headerlink" title="GitLab 配置"></a>GitLab 配置</h2><p>接下来就对 GitLab 进行必要的配置，访问地址、存储地址等，打开 GitLab 配置文件【<a href="http://docs.gitlab.com/omnibus/settings/configuration.html" target="_blank" rel="external">官方配置文档</a>】<br>　　<code>sudo nano /etc/gitlab/gitlab.rb</code></p>
<p>1、配置 <a href="https://docs.gitlab.com.cn/omnibus/settings/configuration.html#configuring-the-external-url-for-gitlab" target="_blank" rel="external">GitLab 域名</a>，启用 HTTPS 时，防火墙必须打开端口 443 以允许入站 HTTPS 流量，可以使用 <a href="http://shumeipai.nxez.com/2014/06/09/simple-raspberry-pi-ufw-firewall-settings.html" target="_blank" rel="external">防火墙配置工具</a> 进行管理。<br>　　<code>external_url &#39;https://192.168.2.222&#39;</code> # 我配置的是 HTTPS 请求，此处换成你对应的域名或 IP 地址</p>
<p>2、将 HTTP 重定向到 HTTPS， 默认情况下，当您以 <code>https</code> 开头指定一个 <code>external_url</code> 时，Nginx 将不再侦听端口 80 上未加密的 HTTP 流量。如果要将所有 HTTP 流量重定向到 HTTPS，您可以使用该 redirect_http_to_https 设置。<br>　　<code>nginx[&#39;enable&#39;] = true</code> # 开启代理<br>　　<code>nginx[&#39;redirect_http_to_https&#39;] = true</code> # 开启将 HTTP 重定向到 HTTPS<br>　　<code>nginx[&#39;redirect_http_to_https_port&#39;] = 80</code> # 将 HTTP 80 端口重定向到 HTTPS </p>
<p>3、更改 SSL 证书位置，首先你需要有证书，如你是域名或者是公网 IP，很多网友推荐免费的 <a href="https://letsencrypt.org/" target="_blank" rel="external">Let’s Encrypt</a>，不过有效期为90天，过期后需要再次申请，也提供了在线 <a href="https://gethttpsforfree.com/" target="_blank" rel="external">免费获取HTTPS证书</a>，如果对于生成私钥不熟悉，可以<a href="http://web.chacuo.net/netsslcsr/" target="_blank" rel="external">在线生成私钥</a>；由于我是局域网 IP 不能申请免费证书，就使用自签的证书，然后将自签的证书手动安装到电脑根证书中，当然 Chrome 并不承认自签证书有效，而此时 IE 是承认自签证书是有效的。<br>　　<code>nginx[&#39;ssl_certificate&#39;] = &quot;/etc/gitlab/ssl/192.168.2.222.crt&quot;</code><br>　　<code>nginx[&#39;ssl_certificate_key&#39;] = &quot;/etc/gitlab/ssl/192.168.2.222.key&quot;</code></p>
<p>4、GitLab 电子邮件服务器 <a href="https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/smtp.md" target="_blank" rel="external">SMTP 配置</a>，我使用的 QQ 个人邮箱，首先要开启邮件 <a href="http://service.mail.qq.com/cgi-bin/help?subtype=1&amp;&amp;id=28&amp;&amp;no=371" target="_blank" rel="external">POP3/SMTP</a> 服务或者是 <a href="http://service.mail.qq.com/cgi-bin/help?subtype=1&amp;&amp;id=28&amp;&amp;no=371" target="_blank" rel="external">IMAP/SMTP</a> 服务，并获取 <a href="http://service.mail.qq.com/cgi-bin/help?subtype=1&amp;&amp;id=28&amp;&amp;no=1001256" target="_blank" rel="external">授权码</a>。</p>
<p>　　<code>gitlab_rails[&#39;smtp_enable&#39;] = true</code> # 开启 smtp<br>　　<code>gitlab_rails[&#39;smtp_address&#39;] = &quot;smtp.qq.com&quot;</code> # smtp 服务器地址<br>　　<code>gitlab_rails[&#39;smtp_port&#39;] = 465</code> # smtp 服务器端口<br>　　<code>gitlab_rails[&#39;smtp_user_name&#39;] = &quot;demo@qq.com&quot;</code> # 邮箱地址<br>　　<code>gitlab_rails[&#39;smtp_password&#39;] = &quot;授权码&quot;</code> # 申请的授权码<br>　　<code>gitlab_rails[&#39;smtp_authentication&#39;] = &quot;login&quot;</code><br>　　<code>gitlab_rails[&#39;smtp_enable_starttls_auto&#39;] = true</code><br>　　<code>gitlab_rails[&#39;smtp_tls&#39;] = true</code> # 启用 tls</p>
<p>　　<code>gitlab_rails[&#39;gitlab_email_enabled&#39;] = true</code><br>　　<code>gitlab_rails[&#39;gitlab_email_from&#39;] = &quot;demo@qq.com&quot;</code> # 发送人地址<br>　　<code>gitlab_rails[&#39;gitlab_email_display_name&#39;] = &quot;demo-GitLab&quot;</code> # 邮件发送人<br>　　<code>gitlab_rails[&#39;gitlab_email_reply_to&#39;] = &quot;demo@qq.com&quot;</code> # 回复邮件地址<br>　　<code>gitlab_rails[&#39;gitlab_email_subject_suffix&#39;] = &quot;demo&quot;</code> # 邮件主题后缀，没有发现在哪里呈现</p>
<ul>
<li>测试 SMTP 配置，可以验证 GitLab 使用 Rails 控制台正确发送电子邮件的能力。在 GitLab 服务器上，执行 <code>sudo gitlab-ctl reconfigure</code>重新生成配置，再执行<code>gitlab-rails console</code> 进入控制台。然后，可以在控制台提示符下输入以下命令，使 GitLab 发送测试电子邮件 <code>Notify.test_email(&#39;demo.test@qq.com&#39;, &#39;Message Subject&#39;, &#39;Message Body&#39;).deliver_now</code>。</li>
</ul>
<p>5、可选项，配置非默认目录来存储 Git 数据<br>默认的文件路径为：<code>/var/opt/gitlab/git-data/repositories</code></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">git_data_dirs(&#123;</div><div class="line">  <span class="string">"default"</span>: &#123;</div><div class="line">    "path": "/home/git/code" # 此换成你的地址， git 数据会保存在该地址 repositories 文件夹中</div><div class="line">  &#125;</div><div class="line">&#125;)</div></pre></td></tr></table></figure>
<p>6、可选项，如果需要调整Unicorn超时或工作人员数量<br>　　<code>unicorn[&#39;worker_processes&#39;] = 2</code> # 最低要求 <a href="https://docs.gitlab.com.cn/ce/install/requirements.html#unicorn-workers" target="_blank" rel="external">worker_processes</a> 为2，以便网页编辑器正常工作<br>　　<code>unicorn[&#39;worker_timeout&#39;] = 80</code> # 超时 80s，即使这样，还是时常 502，知道有多慢了吧</p>
<hr>
<p>目前为止所有前期工作已准备完毕，可以愉快的访问了 GtiLab 了 ^_^</p>
<blockquote>
<p><em><strong>提示：</strong>操作 Git 代码库，可以直接使用 GitLab 提供的 SSH <code>git@192.168.2.222:rpi/raspberry.git</code> 和 HTTPS <code>https://192.168.2.222/rpi/raspberry.git</code>。</em><br><em>另一种，直接访问 Git 服务，此方式支持外网直接访问，但需要对路由器做端口转发配置，非默认端口访问方式 <code>ssh://git@公网IP:22200/home/git/code/repositories/rpi/raspberry.git</code></em></p>
</blockquote>
<hr>
<h2 id="维护命令"><a href="#维护命令" class="headerlink" title="维护命令"></a>维护命令</h2><ul>
<li>修改任何配置文件后都要输入如下命令使配置生效（或者是修复权限设置）：<br><code>sudo gitlab-ctl reconfigure</code></li>
<li>页面缓存清除：<br><code>sudo gitlab-rake cache:clear RAILS_ENV=production</code></li>
<li>GtiLab 各组件启动：<br><code>sudo gitlab-ctl start</code></li>
<li>GtiLab 各组件停止：<br><code>sudo gitlab-ctl stop</code></li>
<li>GtiLab 各组件重启：<br><code>sudo gitlab-ctl restart</code></li>
<li>禁用 GtiLab 开机自启动：<br><code>sudo systemctl disable gitlab-runsvdir</code></li>
<li>启用 GtiLab 开机自启动：<br><code>sudo systemctl enable gitlab-runsvdir</code></li>
<li>查看 GtiLab 运行状态：<br><code>sudo gitlab-ctl status</code></li>
</ul>
<hr>
<h2 id="遇到的问题"><a href="#遇到的问题" class="headerlink" title="遇到的问题"></a>遇到的问题</h2><h4 id="1、Unicorn-默认端口为-8080，若有端口冲突，调整-Unicorn-端口。"><a href="#1、Unicorn-默认端口为-8080，若有端口冲突，调整-Unicorn-端口。" class="headerlink" title="1、Unicorn 默认端口为 8080，若有端口冲突，调整 Unicorn 端口。"></a>1、Unicorn 默认端口为 8080，若有端口冲突，调整 Unicorn 端口。</h4><p>　　<code>unicorn[&#39;listen&#39;] = &#39;127.0.0.1&#39;</code><br>　　<code>unicorn[&#39;port&#39;] = 8082</code><br>　　<code>gitlab_workhorse[&#39;auth_backend&#39;] = &quot;http://localhost:8082&quot;</code> # 这里是否需要调整，有些不太确定了</p>
<h4 id="2、502网关错误，这个问题排查了良久，后来发现内存不足，导致-GitLab-相关组件启动缓慢，或者启动后树莓派出现假死状态。"><a href="#2、502网关错误，这个问题排查了良久，后来发现内存不足，导致-GitLab-相关组件启动缓慢，或者启动后树莓派出现假死状态。" class="headerlink" title="2、502网关错误，这个问题排查了良久，后来发现内存不足，导致 GitLab  相关组件启动缓慢，或者启动后树莓派出现假死状态。"></a>2、502网关错误，这个问题排查了良久，后来发现内存不足，导致 GitLab  相关组件启动缓慢，或者启动后树莓派出现假死状态。</h4><p><img src="/blog/2017/10/05/莓派搭建-GitLab/images/GitLab502.png" alt=""></p>
<ul>
<li><p><strong>症状：</strong>访问 GitLab 未等待就直接返回 502，或者请求处理等待无响应，同时对树莓派发出的指令也无响应，树莓派处于假死状态，只好断电重启，就这样弄了 n 次。</p>
</li>
<li><p><strong>解决方案：</strong>对于个体用户来说，GitLab 显得有些臃肿，同时硬件也是硬伤，只能软件上来解决，在文章上半部分有提到 GitLab 对硬件最低要求是 <strong>1GB 物理内存 + 3GB 交换分区</strong>，查看树莓派的当前的交换分区只有 100M 完全不满足最低要求，然后就创建 4G 的交换分区，嗯，真的好了，GitLab 可以正常访问，并且树莓派也再未出现假死状态。</p>
</li>
<li><p><strong>创建交换分区</strong></p>
<ul>
<li><p>用dd命令创建一个 4G 的文件，它将在 /var/swapfile 路径创建一个名为 swapfile 、大小为 4G 的分区文件，该分区文件拥有1024000个扇区（block)，每个扇区大小为 4K 。<br><code>sudo dd if=/dev/zero of=/var/swapfile bs=4k count=1000k</code></p>
</li>
<li><p>将新创建的文件创建为 Linux Swap 交换区文件：<br><code>sudo mkswap /var/swapfile</code></p>
</li>
<li><p>把新建的交换区加入的交换内存：<br><code>sudo swapon /var/swapfile</code></p>
</li>
<li><p>确认交换分区是否挂载成功：<br><code>sudo swapon -s</code> # 查看交换分区<br><code>free -h</code> # 当前内存使用情况</p>
</li>
<li><p>如果需要每次启动时激活当前交换分区，编辑 <code>sudo nano /etc/fstab</code>，添加一行命令：<br><code>/var/swapfile swap swap defaults 0 0</code></p>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>SWAP 分区即虚拟内存，它可以突破物理内存的限制，增加运行内存，也就是我们平时所说的 RAM，<a href="https://en.wikipedia.org/wiki/Swappiness" target="_blank" rel="external">Swappiness</a> 是一个 Linux 内核参数, 它控制了换出运行时内存的相对权重，默认值是60，可以的取值范围是0-100，建议修改10（不过，没有感觉到有什么不同）</p>
<ul>
<li><p>查看你的系统里面的 swappiness：<br><code>sudo cat /proc/sys/vm/swappiness</code> # 不出意外的话，你应该看到是 60</p>
</li>
<li><p>修改 swappiness 值为 10：<br><code>sudo sysctl vm.swappiness=10</code></p>
</li>
<li><p>即时生效：<br><code>sudo sysctl -p</code></p>
</li>
<li><p>重启保留当前配置，编辑配置文件 <code>sudo nano /etc/sysctl.conf</code> 添加一行命令：<br><code>vm.swappiness=30</code></p>
</li>
</ul>
</li>
<li><p>最后，重启树莓派查看配置是否正常：<br><code>sudo restart</code></p>
</li>
</ul>
<p>　<br><em>居然感冒了，上次应该是去年的时候吧，嗯，天气冷了，注意保暖  ^_^</em></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;　　不记得是什么时候，在树莓派上搭建了供个人使用的 Git 仓库，不是 GitLab 或者是其他 Git 管理平台，就是最原生的 Git 服务，也不觉得有什么奇怪，就这样使用了很久 ：)&lt;/p&gt;
&lt;p&gt;　　八天国庆假期，少了往年游玩的激情，也没有其他什么事情，整日宅在自己的小窝里躲避风和雨，省得过于清闲而又浮想翩翩，于是乎想利用树莓派搭建 GIT 管理平台；当下最为流行开源平台为 GitLab 吧，日常工作中几乎每天与其打交道（无外乎最多的就是 pull、push 吧，偶尔配置一二，算不上熟络）。&lt;br&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="Raspberry Pi" scheme="/blog/tags/Raspberry-Pi/"/>
    
      <category term="Git" scheme="/blog/tags/Git/"/>
    
      <category term="GitLab" scheme="/blog/tags/GitLab/"/>
    
  </entry>
  
  <entry>
    <title>Hello World</title>
    <link href="/blog/2017/08/25/hello-world/"/>
    <id>/blog/2017/08/25/hello-world/</id>
    <published>2017-08-25T03:02:02.000Z</published>
    <updated>2017-10-21T09:58:22.000Z</updated>
    
    <content type="html"><![CDATA[<p>Hello World.<br>学过编程的同学，也许在熟悉不过了， 相信对大多数同学来说，它是一切的开始 ，也成为了惯例 : )</p>
<p>较早之前就有搭建博客想法，但对于写点东西都要绞尽脑汁也挤不出几句的我来说，也就没有太多动力了，域名、ECS 也就闲置了。</p>
<p>也许是有些清闲，就又开始倒弄起来了，也许是机缘巧合，有些网友推荐 <a href="https://hexo.io/zh-cn/" target="_blank" rel="external">Hexo</a>，了解后感觉还不错，就使用了。</p>
<p>使用到现在（其实也没用过几次），基本的需求也都满足，支持 <a href="https://help.github.com/categories/writing-on-github/" target="_blank" rel="external">GitHub Flavored Markdown</a>  标记语言，也比较有趣；也有一些<a href="https://hexo.io/themes/" target="_blank" rel="external">主题</a>可供选择（我使用的是 <a href="https://github.com/pinggod/hexo-theme-apollo" target="_blank" rel="external">hexo-theme-apollo</a>），对于有些想法，又不想动手花太多时间的同学，也许是个不错的选择。<br><a id="more"></a><br><em>注：<a href="https://hexo.io/zh-cn/docs/" target="_blank" rel="external">Hexo 官网文档</a> 和   <a href="https://github.com/hexojs/hexo" target="_blank" rel="external">GitHub</a>  中的安装命令有些不一样，如果安装进行不下去时，可以参考一下  <a href="https://github.com/hexojs/hexo" target="_blank" rel="external">GitHub</a> 。</em></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Hello World.&lt;br&gt;学过编程的同学，也许在熟悉不过了， 相信对大多数同学来说，它是一切的开始 ，也成为了惯例 : )&lt;/p&gt;
&lt;p&gt;较早之前就有搭建博客想法，但对于写点东西都要绞尽脑汁也挤不出几句的我来说，也就没有太多动力了，域名、ECS 也就闲置了。&lt;/p&gt;
&lt;p&gt;也许是有些清闲，就又开始倒弄起来了，也许是机缘巧合，有些网友推荐 &lt;a href=&quot;https://hexo.io/zh-cn/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Hexo&lt;/a&gt;，了解后感觉还不错，就使用了。&lt;/p&gt;
&lt;p&gt;使用到现在（其实也没用过几次），基本的需求也都满足，支持 &lt;a href=&quot;https://help.github.com/categories/writing-on-github/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;GitHub Flavored Markdown&lt;/a&gt;  标记语言，也比较有趣；也有一些&lt;a href=&quot;https://hexo.io/themes/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;主题&lt;/a&gt;可供选择（我使用的是 &lt;a href=&quot;https://github.com/pinggod/hexo-theme-apollo&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;hexo-theme-apollo&lt;/a&gt;），对于有些想法，又不想动手花太多时间的同学，也许是个不错的选择。&lt;br&gt;&lt;/p&gt;
    
    </summary>
    
    
  </entry>
  
</feed>
