scrapy 运行 no module named win32api

标 签: python

在用scrapy写爬虫时,使用命令:

scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-sample1.html

时,报错如果下:

scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-sample1.html
2018-08-30 09:34:39 [scrapy.utils.log] INFO: Scrapy 1.5.1 started (bot: scrapybot)
2018-08-30 09:34:39 [scrapy.utils.log] INFO: Versions: lxml 4.2.4.0, libxml2 2.9.5, cssselect 1.0.3, parsel 1.5.0, w3lib 1.19.0, Twisted 18.7.0, Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)], pyOpenSSL 18.0.0 (OpenSSL 1.1.0i  14 Aug 2018), cryptography 2.3.1, Platform Windows-10-10.0.17134-SP0
2018-08-30 09:34:39 [scrapy.crawler] INFO: Overridden settings: {'DUPEFILTER_CLASS': 'scrapy.dupefilters.BaseDupeFilter', 'LOGSTATS_INTERVAL': 0}
2018-08-30 09:34:39 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole']
Traceback (most recent call last):
  File "c:\python36\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "c:\python36\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Python36\Scripts\scrapy.exe\__main__.py", line 9, in <module>
  File "c:\python36\lib\site-packages\scrapy\cmdline.py", line 150, in execute
    _run_print_help(parser, _run_command, cmd, args, opts)
  File "c:\python36\lib\site-packages\scrapy\cmdline.py", line 90, in _run_print_help
    func(*a, **kw)
  File "c:\python36\lib\site-packages\scrapy\cmdline.py", line 157, in _run_command
    cmd.run(args, opts)
  File "c:\python36\lib\site-packages\scrapy\commands\shell.py", line 67, in run
    crawler.engine = crawler._create_engine()
  File "c:\python36\lib\site-packages\scrapy\crawler.py", line 105, in _create_engine
    return ExecutionEngine(self, lambda _: self.stop())
  File "c:\python36\lib\site-packages\scrapy\core\engine.py", line 69, in __init__
    self.downloader = downloader_cls(crawler)
  File "c:\python36\lib\site-packages\scrapy\core\downloader\__init__.py", line 88, in __init__
    self.middleware = DownloaderMiddlewareManager.from_crawler(crawler)
  File "c:\python36\lib\site-packages\scrapy\middleware.py", line 58, in from_crawler
    return cls.from_settings(crawler.settings, crawler)
  File "c:\python36\lib\site-packages\scrapy\middleware.py", line 34, in from_settings
    mwcls = load_object(clspath)
  File "c:\python36\lib\site-packages\scrapy\utils\misc.py", line 44, in load_object
    mod = import_module(module)
  File "c:\python36\lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "c:\python36\lib\site-packages\scrapy\downloadermiddlewares\retry.py", line 20, in <module>
    from twisted.web.client import ResponseFailed
  File "c:\python36\lib\site-packages\twisted\web\client.py", line 41, in <module>
    from twisted.internet.endpoints import HostnameEndpoint, wrapClientTLS
  File "c:\python36\lib\site-packages\twisted\internet\endpoints.py", line 41, in <module>
    from twisted.internet.stdio import StandardIO, PipeAddress
  File "c:\python36\lib\site-packages\twisted\internet\stdio.py", line 30, in <module>
    from twisted.internet import _win32stdio
  File "c:\python36\lib\site-packages\twisted\internet\_win32stdio.py", line 9, in <module>
    import win32api
ModuleNotFoundError: No module named 'win32api'

看错误就知道是因为没有win32api,所以下一个安装,应该就没有什么问题了。

安装文件名为 pywin32,安装的方法有两种,安装方法如下:

1.就是直接用pip安装,这个很方便,在linux或者window上都行,命令如下:

pip3 install pywin32

2.就是下载pywin32程序,然后安装就好了,下载地址如下

pywin32下载

进入页面后,选择版本,一直都选择最新的pywin32的版本,点击版本进去就,选择操作系统和python版本,下载安装

就好了

后台编程 / 评 论 (0) / 热度 (220℃) / 2018-08-30 / 阅读全文  / MaWei

sublime 自定义注释

标 签:

    使用sublime的时候,有没有在什么地方加几行代码,然后得标注一下什么时候改过的,谁改过的,所以要注释一下.

    如果每次手动写,很麻烦,有没有一种方法自动生成,肯定是有的.方法如下:

    1.首先得新建一个 snippert ,可以理解为注释模板吧,路径为菜单栏上的 tools->developer->new snippet,会打开一个新

页面,注意的是保存文件名要以 .sublime-snippet 的后缀才行, 里面有如下代码:

<snippet>
 <content><![CDATA[
Hello, ${1:this} is a ${2:snippet}.
]]></content>
 <!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
 <!-- <tabTrigger>hello</tabTrigger> -->
 <!-- Optional: Set a scope to limit where the snippet will trigger -->
 <!-- <scope>source.python</scope> -->
</snippet>

    里面主要的配置有两项:

        CDATA[],这里面就是你的注释模板,

        <!-- <tabTrigger>hello</tabTrigger> --> 这项是触发的快捷键

    我的配置如下,也可以自己修改自己喜欢的:

<snippet>
 <content><![CDATA[
  \/*****@Start***@MaWei:${1:f7}*****${2}**********@Start*********\/
  \/*****@End*****@MaWei:${1:f7}*****${2}**********@End*******\/
]]></content>
 <!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
 <tabTrigger>des</tabTrigger>
 <!-- Optional: Set a scope to limit where the snippet will trigger -->
 <!-- <scope>source.python</scope> -->
</snippet>

    复制的时候把反斜杠去了,在想要注释的地方输入des然后回车或者tab都行,就会生成这个注释模板了,然后按F7,生成当前时间

在生成时间这个地方,我参考了很多少地方,都没有找到很少的解决方法,网上都是这么写的,应该是自动生成的,

可不知道我就是没有办法自动生成,得按快捷键才行,如果有那个大神知道,可以告诉我一下,QQ:1123265518.

    2.生成时间的方法为新建一个sublime 的插件,在菜单栏上的 tools->developer->new plugin,在里面添加如下代码:

import datetime, getpass
import sublime, sublime_plugin
class AddDateTimeStampCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        self.view.run_command("insert_snippet", { "contents": "%s" %  datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") } )
class AddDateStampCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        self.view.run_command("insert_snippet", { "contents": "%s" %  datetime.datetime.now().strftime("%Y-%m-%d") } )
class AddTimeStampCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        self.view.run_command("insert_snippet", { "contents": "%s" %  datetime.datetime.now().strftime("%H:%M:%S") } )

然后点击保存,名字随便.但名字后缀为.py

    3.最后是添加快捷键,打开自定义快捷键配置, Preferences->key bludings,在里面添加如下:

{ "keys": ["f7"], "command": "add_date_time_stamp" },

 注意前面一条是否有,号结尾.

Python / 评 论 (0) / 热度 (257℃) / 2018-11-28 / 阅读全文  / MaWei

sublime 快捷键插入当前时间

标 签: wamp

    在使用sublime开发的时候,有时候要注释一下开发时间,用手写有点坑,所以就想怎么用快捷生成,费话不多说,方法如下:

    1.添加一个插件,在菜单栏选择, tools->developer->new plugin,然后会打开一个页面,在里面输入如下代码:(注意保存文件时,后缀名为.py)

import sublime
import sublime_plugin
import time
version_format_time = "%Y-%m-%d %H:%M:%S"
version_format_day = "%Y-%m-%d" 
version_pattern = "[0-9]{4}\-[0-9]{2}\-[0-9]{2}_[0-9]{2}\.[0-9]{2}\.[0-9]{2}"
class insert_datetimeCommand(sublime_plugin.TextCommand):
  def run(self, edit):
    sels = self.view.sel()
    for sel in sels:
      if not self.view.find_all(version_pattern):
        self.view.replace(edit, sel, time.strftime(version_format_time))
        return
      region = sublime.Region(0, self.view.size())
      results = self.view.find_all(version_pattern)
      for result in results:
        self.view.replace(edit, result, time.strftime(version_format_time))

class InsertDateCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        sel = self.view.sel();
        for s in sel:
            self.view.replace(edit, s, time.strftime(version_format_day))

    2.添加快捷键,也是在菜单栏选择, Preferences->key bludings,打开一个自定义快捷键,在里面的 [ ] 里面添加如下代码:

 { "keys": ["f5"], "command": "insert_datetime" },
 { "keys": ["f6"], "command": "insert_date" },

    要注意的是,如果里面有,添加在最尾行的时候,前面一行后面有没有,号,如果没有得加上,不然就报错了,

    这个设置的快捷键为 F5 ,F6,F5为时间到秒, F6为时间到天,如果需要改成最它快捷键,自己改.

Python / 评 论 (0) / 热度 (107℃) / 2018-07-20 / 阅读全文  / MaWei

laravel composer 安装

标 签:

    现在lavavel 一键下载安装包已经没有了,得git一堆东西自己打包,我自己搞了很久,没有搞定,没有什么文档

最后没有办法,只能用composer,但composer下载很慢,但composer请求地址改成中国就好了,下面就来说说composer

安装 lavavel 方法:

    1.第一步就是把你的php安装目录加入系统环境里面,如果不会,那自己百度了

    2.下载composer,可以下载安装包,但安装包安装composer后,下载 lavavel ,下载地址:

https://getcomposer.org/download/

在页面找到 Composer-Setup.exe ,或者 用命令行安装,页面里都有.但这两种方法我都试,结果项目下载到别的地方了,

路径不在你项目,如果是widown在你用户目录里

    C:\Users\MaWei\AppData\Roaming\Composer

 我找了很久,不知道怎么解决,只是把composer安装你的项目里,但这肯定不行的,如果有知道怎么解决可以告诉我的一下,QQ:1123265518

    3.所以我不推荐新手用上面 2 的方法,如果有大神可以告诉上面的方法解决办法,谢谢了,我后来用的方法也是在这个下载页面,在下面一点,

有个 manual download, 手动下载,找到 Latest Snapshot ,点击下载,下载的文件名是 compser.phar ,保存在你的网站根目录

    4.在你的网站根目录里面新建一个 composer.json 文件,里面写入如下的内容:

{
    "name": "laravel/laravel",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "type": "project",
    "require": {
        "php": ">=7.0.0",
        "laravel/framework": "5.5.*"
    },
    "config": {
        "preferred-install": "dist"
    },
    "repositories": {
        "packagist": {
            "type": "composer",
            "url": "https://packagist.phpcomposer.com"
        }
    }
}

上面的配置项我就不一一说明了,看key就明白了.

    5.现在就可以直接创建lavavel项目,命令如下:

php composer.phar create-project laravel/laravel 项目名 --prefer-dist

    6.完成后就可以看到你的根目录创建一个项目,名字就是刚刚创的项目名

    7.注意的是,php的路径要加入系统变量里,加入进去后就可以输入命令

php -v

可以看到php的版本,注意的事,lavavel 5.5的版本要php7版本以上

PHP / 评 论 (0) / 热度 (172℃) / 2018-04-23 / 阅读全文  / MaWei

shell脚本变量定义

标 签:

shell脚本系统变量的定义:

$1 表示获取第一个参数
$0 脚本名
$* 所有的参数
$@ 所有的参数
$# 参数的个数
$$ 当前进程的PID
$! 上一个后台进程的PID
$? 上一个命令的返回值 0表示成功

read -p '提示:' 变量名
     -t 5 表示等待5秒
     -n 2 表示取两个字符
     
     
A = $(执行命令)


Linux / 评 论 (0) / 热度 (113℃) / 2018-04-02 / 阅读全文  / MaWei

Centos7网络配置

标 签:

    在centos7之前的版本查看ip配置命令为:

ifconfig

    然而在centos7之后的版本,这个命令没有了,改为ip命令,ip命令详情如下:

ip  [选项]  操作对象{link|addr|route...}

# ip link show                  # 显示网络接口信息
# ip link set eth0 upi          # 开启网卡
# ip link set eth0 down         # 关闭网卡
# ip link set eth0 promisc on   # 开启网卡的混合模式
# ip link set eth0 promisc offi # 关闭网卡的混个模式
# ip link set eth0 txqueuelen 1200    # 设置网卡队列长度
# ip link set eth0 mtu 1400     # 设置网卡最大传输单元
# ip addr show                  # 显示网卡IP信息
# ip addr add 192.168.0.1/24 dev eth0 # 设置eth0网卡IP地址192.168.0.1
# ip addr del 192.168.0.1/24 dev eth0 # 删除eth0网卡IP地址

# ip route list                 # 查看路由信息
# ip route add 192.168.4.0/24  via  192.168.0.254 dev eth0 # 设置192.168.4.0网段的网关为192.168.0.254,数据走eth0接口
# ip route add default via  192.168.0.254  dev eth0    # 设置默认网关为192.168.0.254
# ip route del 192.168.4.0/24    # 删除192.168.4.0网段的网关
# ip route del default    # 删除默认路由

    所以查看网络的ip配置情况命令为:

ip addr show

    或者也可以用如下的命令:

nmcli connection show

    所以配置ip地址也可以用这两个方法实现,只是要注意的是,用ip命令配置的ip地址只是临时用的,是不会写入系统的配置文件里面的。而

用nmcli命令是直接写入配置文件的。方法如下:

nmcli connection modify enp0s3 connection.autoconnect yes ipv4.method manual ipv4.address 192.168.1.2/24 \
ipv4.gateway 192.168.1.1 ipv4.dns 114.114.114.114

    autoconnect 是设置开机自动连接
    ipv4.method 是设置手工配置IPV4地址

    另外一种方法就比较麻烦一点,个人不在推荐,那就是直接修改配置文件。配置地址没有变,还是在地方,但注意的是centos7之前的版本网卡

名字一般都叫eth0,而且到centos7了,名字改为了enp0s3这样的,所以要注意别修改错了,命令如下:

cd /etc/sysconfig/network-scripts/

    然后查看当前目录里面对应网卡配置文件,我这里的配置文件为 ifcfg-enp0s3,所以直接用vi命令:

vi ifcfg-enp0s3

    里面的内容如下:

TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=enp0s3
UUID=25074268-9006-456a-b855-ea4dc5ae1805
DEVICE=enp0s3
ONBOOT=yes

    直接在下面添加ipv4的地址信息如下:

TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=enp0s3
UUID=25074268-9006-456a-b855-ea4dc5ae1805
DEVICE=enp0s3
ONBOOT=yes
IPADDR=192.168.1.7
PREFIX=24
GATEWAY=192.168.1.1
DNS1=114.114.114.114

    因为英文要大写,我不太习惯,所以感觉很不方便。直接用上面的命令方便多了。修改完后要重启网络。命令如下:

/etc/init.d/network restart

    centos7还可以用如下的命令重启,命令如下:

ifup enp0s3  #重启网卡enp0s3
ifdown enp0s3 #关闭网上enp0s3


Linux / 评 论 (0) / 热度 (176℃) / 2017-12-06 / 阅读全文  / MaWei

css3立方体动画

标 签:


<!DOCTYPE html>
<html>
  <head>
    <title>09首页</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- Bootstrap -->
    <link href="css/style.css" rel="stylesheet">
    <style type="text/css" media="screen">
    	/*****转动*******/
		.will_rotate{
			width: 150px;
			height: 150px;
			margin: 0 auto;	
			position: relative;
		}
		.rotate_parent, .rotate_parent li {
		    position: absolute;
		    display: block;
		}
		.rotate_parent{
		    position: absolute;
		    display: block;
		    width: 100%;
		    height: 100%;
		    padding: 0;
		    /*margin: -50px 0;*/
		    -webkit-transform-origin: 50px 50px;
		    transform-origin: 50px 50px;
		    -webkit-transform: rotateX(-33.5deg) rotateY(45deg);
		    transform: rotateX(-33.5deg) rotateY(45deg);
		    -webkit-transform-style: preserve-3d;
		     transform-style: preserve-3d; 
		     -webkit-animation: willRotate 3s ease-in-out infinite 2s; 
		     animation: willRotate 3s ease-in-out infinite alternate; 
		     /*animation: name duration timing-function delay iteration-count direction;*/
			    /*name	规定需要绑定到选择器的 keyframe 名称。。*/
			   	/*duration	规定完成动画所花费的时间,以秒或毫秒计。*/
			  	/*timing-function	规定动画的速度曲线。*/
			 	/*delay	规定在动画开始之前的延迟。*/
				/*iteration-count	规定动画应该播放的次数。*/
				/*direction	规定是否应该轮流反向播放动画。*/
		    top: 20%;
		    /*left: 50%;*/
		}

		.rotate_parent .tip_back, .rotate_parent .tip_front, .rotate_parent .tip_left, .rotate_parent .tip_right, .rotate_parent .tip_top {
		    background: radial-gradient(transparent 30%,rgba(126,17,91,.2) 100%);
		}
		.rotate_parent li {
		    width: 100px;
		    height: 100px;
		     transition: -webkit-transform 1s ease-in-out; 
		     transition: transform 1s ease-in-out; 
		}
		.rotate_parent .tip_front {
		    -webkit-transform: translateZ(50px);
		     transform: translateZ(50px); 
		}
		.rotate_parent .tip_back {
		    -webkit-transform:translateZ(-50px);
		    transform:translateZ(-50px);
		}
		.rotate_parent .tip_right {
		    -webkit-transform: rotateY(90deg) translateZ(50px);
		    transform: rotateY(90deg) translateZ(50px);
		}
		.rotate_parent .tip_left {
		    -webkit-transform: rotateY(90deg) translateZ(-50px);
		    transform: rotateY(90deg) translateZ(-50px);
		}
		.rotate_parent .tip_top {
		    -webkit-transform: rotateX(90deg) translateZ(50px);
		    transform: rotateX(90deg) translateZ(50px);
		}
		.rotate_parent .tip_bottom{
		    -webkit-transform: rotateX(90deg) translateZ(-50px);
		    transform: rotateX(90deg) translateZ(-50px);
		}
		.rotate_parent .tip_floor {
		    box-shadow: -300px 0 50px rgba(0,0,0,.3);
		    -webkit-backface-visibility: visible;
		    backface-visibility: visible;
		    width: 110px;
		    height: 110px;
		    left: 295px;
		    background-color: transparent;
		    -webkit-transform: rotateX(90deg) translateZ(-60px);
		    transform: rotateX(90deg) translateZ(-60px);
		}	
    </style>
  </head>
  <body>
		<div class="will_rotate">
			<ul class="rotate_parent">
				<li class="tip_front"></li>
				<li class="tip_back"></li>
				<li class="tip_right"></li>
				<li class="tip_left"></li>
				<li class="tip_top"></li>
				<li class="tip_bottom"></li>
				<li class="tip_floor"></li>
			</ul>
		</div>
	</body>
</html>


CSS / 评 论 (0) / 热度 (162℃) / 2017-10-30 / 阅读全文  / MaWei

发射端 PPM

标 签:

    航模的遥控,也就是发射端,会产生一系列的脉冲波形,这个波形我称它为 PPM,大概不
正确,反正就是个名字,我懒得去百度了。下面说一下给他的编码原理。
    1.PPM  的周期是 20ms,为什么是 20ms ?不能是 100ms ?
原因要从舵机的控制信号说起。发射端发出的电磁波,主要就是控制接收端的舵机和电调的。
电调先不去管他,先说舵机。
舵机的控制信号就是周期 20ms,高电平为 0.5~2.5ms 的脉冲信号。具体的舵机控制,我下
面另外讲。
发现相似之处了吧?他的周期和舵机的周期是一样的。
但是舵机的高电平时间是 0.5ms~2.5ms,剩下的时间都是低电平。
这里啰嗦一下,低电平就是 0~1.3V 电压,高电平一般指 2.7~5V 的电压,大概这个范围。
好了,既然PPM是控制舵机和电调信号,那么周期为20ms的PPM脉冲,能控制几个舵机??
答案很简单:20ms÷2.5ms=8
也就是 PPM 信号,能分为 8 个通道,最多控制 8 个舵机。
有人要问,我这里有个 12 通道的航模遥控,比你的 8 个要多。
回答:12 个通道里面,包括开关通道,如果全部是模拟通道,或者叫比例通道,他最多就 8
个。1 个模拟通道,可以分出 8 个开关通道。
原因:模拟通道是用 16 进制数表示的,开关通道是二进制表示的。1 个 16 进制数=8 个二
进制数。也就是 0xFF=0b11111111
另外说一句,电调和舵机一样,控制他们的脉冲信号是一样一样的。
    2.PPM  怎么编码呢?
PPM 的编码根据你的通道总数来。每个通道固定占用 2.5ms 的时间。
如果你的遥控器就 1 个通道,那么你就让剩余的 20-2.5=17.5ms 的电平都为低电平。
如果遥控器为 4 个通道,那么前面 4*2.5ms 的时间,你自己控制,剩下的时间都为低电平。
要是你的遥控为 8 个通道,那么全部的 20ms 的时间,你都要写代码控制。
    3. 既然每个通道固定占用 2.5ms , 我怎么知道每个通道的数值?
每个模拟通道,都是通过单片机的模拟数值转换,简称数模转换得来的,英文就是 ADC,
A 模拟,D 数字,C 转换。具体的英文单词自己百度。
模数转换,就是把你的摇杆带动的电位器的电阻变化引起的电压变化的模拟量,转换为一个
能用数字表示的电压的值。
这里用 STC 单片机为例子,他有 10 位精度的 ADC,也有 8 位精度的 ADC。
简单来说,10 位精度的 ADC 最大值是 1023,8 位精度的 ADC 最大值是 255。两者可以转
换,没啥区别,10 位精度更高一点,可惜对我们的摇杆来说,8 位精度一般都达不到。
这里以 10 位精度 ADC 作为例子。
当你摇杆摇到最高点时,ADC 值是 1023,摇到最低点,ADC 值是 0,放到中间,ADC 值
是 511。
每个单片机有 8 路 ADC 通道,可以接 4 个摇杆,因为每个摇杆有上下、左右,两个电阻器。
当 ADC=0,每个通道 2.5ms 的脉冲,就是 0.5ms 高电平,2ms 低电平。
当 ADC=1023,每个通道 2.5ms 的脉冲,就是 2.5ms 高单平,0ms 低电平。
如果给个公式,就是 高电平时间=(adc*2)/1024+0.5
    4.舵机的控制脉冲原理
这里说一下舵机,舵机的 20ms 周期脉冲,有 0.5ms 高电平,其他为低电平的时候,舵机摆
臂在最左边。当有 2.5ms 高电平的时候,舵机的摆臂在最右边。
因为舵机的制造精度,当在摆臂最左边的时候,或者在最右边的时候,会出现磨齿轮的现象,
就是齿轮吱吱乱叫,摆臂无法打到 0 度或者 180 度。一般都让舵机的摆臂在 90°角内移动,
也就是给他 1ms~2ms 高电平,而不是 0.5~2.5ms。
舵机发抖是咋回事?
听有人说,我舵机抖舵。为啥呢??舵机是机械装置,他的移动需要时间。
如果给他的控制脉冲,第一个 20ms,让他到 90°的位置,第二个脉冲又让他到 0°的位置,
第三个脉冲又让他去 120°的地方。
他移动的时间远远大于 20ms,所以就在小范围内不停的移来移去,像发抖一样。
电调和舵机不一样,电调没齿轮。电调的控制脉冲为 0.5ms 高,其他低的时候,为 0 油门,
也就是 MOS 管关闭状态。当控制脉冲为 2.5ms 高,其他低的时候,油门全开,也就是 mos
管完全导通。
在中间区域的时候,使用 PWM 调速。PWM 调速下面讲。
    5.PPM  怎么发射出去?
我 PPM 编码做好了,怎么发射出去呢??这个很简单。现在我们都是用的 2.4G 模块,芯片
一般是 NRF24L01 芯片,我这里简称为 24 芯片。
24 芯片有发射和接收两种状态,可以随意转换。
它像电脑的网卡一样,有 IP 地址,也有端口地址。我们的网卡地址,是 4 位 16 进制数,端
口有 65535 个。
24 芯片的通信地址通常是 5 位的 16 进制数,他的端口有 128 个。
发射和接收,通常都有一个对码过程。
    6.对码是什么??
对码简单来说,就是双方定义一下通信地址,和通信用的端口,以及跳频的规则。
当我用短接线短路一下接收的 2 个 IO 口,双方就知道要用默认的地址,默认的端口进行通
信,然后遥控把新的地址、端口和跳频规则发给接收。接收存到单片机的闪存里面,然后用
对码后的规则进行通信。
    7.跳频又是什么鬼??
很多遥控都能自动跳频,什么叫自动跳频呢,为啥要跳频通信?
涉及到一个电磁波干扰的问题。当一个通道里面很多脉冲信号的时候,你这个通道就被严重
干扰了,这个时候,我换个通道,可能就没这么多干扰了,也就能收到信号了。
萝莉的跳频,是 5 跳,我记得大概是从 10 通道开始跳,每次加 20。也就是第一次通信在 10
通道,第二次通信在 30 通道,下面是 50,70,90,再从 10 通道开始循环。
萝莉的跳频是 5 跳,基本 1 秒钟就能循环 n 次,周期非常短。
据说军用的电台,有的跳频周期是 20 年……
    8.再科普一下,为啥不同厂家的遥控和接收不通用呢??
就是对码的规则大家都不一致呗。
如果大家的默认地址,端口,跳频规则都一样,就可以通用了……
我们自己做的遥控和接收,都通用,就是因为规则一样。
上面都是闲话,还没说怎么发射 PPM 信号出去呢。
    9.PPM  信号发射
24 芯片每次最大可以发送 32 个字节的数据,你只要根据你的通道数量,定义不超过 32 个
字节的数组,调用他的发送函数就 OK 了。
为了省心,我都是代码里面设置一个 32 长度的数组,前面几个字节存每个通道的 ADC 值。
然后调用 24 芯片的发送函数就 OK 了。当然,10 位的 ADC 值,要除以 4,变成 8 位的才
行,为啥?一个字节是 8 位的,你发 10 位的 ADC,我会溢出滴。你觉得我溢出也无所谓,
不除以 4 也没关系……反正只要编译器不出错,他自动给你右移 2 位,相当于除以 4 了。
发射的周期是多少呢?当然每 20ms 发一次了。也就是 1 秒钟要发射 50 次。这个非常重要。
每 20ms,必须发送一次,要不接收端的舵机要罢工了……
    10.电压回传的原理是啥?
现在好像电压回传的需求越来越大,为啥这个东西不加进来呢?
原理我简单说一下。24 芯片可以随时转换发射和接收两种状态。
最简单的电压回传,就是遥控先发送摇杆的数值给接收器,然后把 24 芯片设置成接收状态。
接收器收到摇杆信号后,先调整舵机和电调,然后获取电池的电压,把 24 芯片的状态设置
成发射状态, 再把电压值发送给遥控,再把状态切到接收。
遥控收到电压值后,再把 24 芯片换成发射模式。然后重复以上的过程。有跳频的也继续跳。
反正就是这么循环。
中间有个问题,就是操作的流程度和丢包。
每次都在发送和接收之间转换,会让人觉得操作变的不流畅了。
最好是 2 秒或者 5 秒,才转换一次状态,收个电压值就好了。
但是 24 芯片如果离的距离较远,容易丢包。很容易发个电压,我一直收不到。中间如果有
跳频的话,不知道跳到哪个频道了。哈哈。
反正做也不是不能做,就是有点影响操作流畅度。对高手来说,都不是事,关键我不是高手,
嗯嗯嗯……
    11.接收端 PPM  解码
都写这么多了。接收端的 PPM 解码也一起说了吧。
接收端根据自己是几通道的接收器,固定获取 24 芯片发射来的数据的前几位。每一位代表
一个通道。
下面就是把 ADC 值转换为单通道的 PPM 信号。
也就是周期 20ms,高电平 0.5~2.5ms 的脉冲信号。
当 ADC 值是 255 的时候,高电平 2.5ms
当 ADC 值是 0 的时候,高电平 0.5ms
中间的自己算。
每个通道都要这么处理过来。有几个通道要发几个通道的 20ms 脉冲。
舵机和电调,他们的解码方式一样吗?
肯定一样了。那么为啥电调固定 3 通道,什么副翼 1 通道,升降 2 通道之类的。。。。
这个都是大家约定俗成的,你乱改了,别人不看你的说明书,就会接错。所以一般按照这个
来弄。
    12.PWM  信号是啥??
PWM,看英文缩写,就是脉冲、宽度、调制。
PWM 信号主要是用来调节直流电机转速的,不管是无刷还是有刷,都一样。
直流电机调速,我们知道如果降低电压,电机转速肯定会降低,但是快速调压的电路应该非
常复杂,成本也很高。调压都涉及到电感,当快速调压时,电感产生的反电动势,就足够讨
厌了。
啰嗦一句,我知道交流的变频器,要好几百块钱一个,所以变频空调都比较贵,就是变频器
贵。这个价格可以参考直流调压器的价格了。
剩下的一种调速方式,就是 PWM,也是成本最低的,电路最简单的调速方案。他的核心元
件就是 MOS 管,也叫场效应管。
具体的场效应管我就不多讲了,自己百度。
PWM 信号,就是电压时高时低的信号,当高电平的时候,MOS 通电,电机转动;当低电
平的时候,MOS 管不通电,电机依靠惯性转动。
通过 PWM 信号,降低高电平的时间,就可以降低电机的转速。提高高电平的时间,就增加
电机的转速。
电调的作用,很简单,就是把 20ms 周期的 PPM 信号,转为相对应的 PWM 信号。
当 PPM 信号,高电平为 0.5ms,那么 PWM 信号全部都是低电平。
当 PPM 信号,高电平为 2.5ms,那么 PWM 信号全部都是高电平。
当 PPM 信号,高电平为 1.5ms,那么 PWM 信号,高低电平时间各占一半。
其他的自己算。
    13.PWM  信号的频率应该是多少呢?
PWM 调速的时候,通常会产生让人难受的声音。人的耳朵能听到的声音频率在
20HZ~20KHZ 之间。
按原理,如果 PWM 的频率超过 20KHZ,就不会听到 PWM 信号的声音。其实频率过高,
对调速影响很大。具体的频率可以百度…………残念。
有人说 10K~20K 最好,这个应该和电机有关系的,没有啥固定的公式,自己测试吧。
萝莉的 PWM 频率大概是 1KHZ。如果我没记错。
作者的话
以上我自己的理解,肯定错误连篇,误人子弟。毕竟我也是新人啊,接触航模才 3 个月,我
买了一大堆东西,飞机还没做出来,典型的纸上谈兵啊。看我写这么多文字,欢迎大家指正
我的错误,不要爆粗,谢谢!!

作者:浅雪
QQ 群:272416403
2015 年 8 月 3 日

电子基础 / 评 论 (0) / 热度 (196℃) / 2017-06-07 / 阅读全文  / MaWei