暂时未有相关云产品技术能力~
1 手眼标定的原理基坐标系(base_tree)和相机(camera_tree)两个坐标系属于不同的tree,通过将标签贴到手上,相机识别出标签的position和orention,并通过easy_handeye标定包得到tool0(机械手),进一步得到相对于base的位置关系。即子坐标系(camera_rgb_optical_frame)到父坐标系(base_link)之间的关系。在之后如果摄像头识别到物体的位置(在camera坐标系下),即可通过transform(这种转换关系),转化为base(也就是机器人知道的自己的位置坐标系)坐标系下的位置,这样机器人就通过转化关系得到相机识别到的位置实际在空间中的位置。对于手眼标定,场景主要有以下两种,标定方法标定关系标定区别eye-to-hand,眼在手外这种场景下我们已知机械臂终端end_link与base_link、相机camera_link与识别物体object_link之间的关系需要求解camera_link与base_link之间的变换eye-in-hand,眼在手上这种场景base_link和机械臂各关节joint_link、end_link已经通过URDF发布了只需要求解camera_link与end_link之间的变换。2 准备工作所用系统及硬件版本:Ubuntu18.04(ROS Melodic) UR3机械臂(CB3.12) RealSense D435i 安装ur功能包(Universal_Robots_ROS_Driver驱动) 安装realsense-ros 2.1 安装aruco_roscd ~/ur_ws/src git clone -b melodic-devel https://github.com/pal-robotics/aruco_ros.git cd .. catkin_make 2.2 安装vision_visp / visp_hand2eye_calibrationcd ~/ur_ws/src sudo apt-get install ros-melodic-visp git clone -b melodic-devel https://github.com/lagadic/vision_visp.git cd .. catkin_make --pkg visp_hand2eye_calibration catkin_make 2.3 安装easy_handeyecd ~/ur_ws/src git clone https://github.com/IFL-CAMP/easy_handeye cd .. catkin_make 3 眼在手上3.1 修改标定 launch 文件标定过程需启动ur3机械臂的相关节点,realsense节点,aruco节点,easy_handeye节点,可以写一个 launch 文件同时启动上述节点,也可以分别启动。easy_in_handeye 包中给出了用一个 launch 文件实现的示例,在如下的目录中:~/ur_ws/src/easy_handeye/docs/example_launch/ur5_kinect_calibration.launch,这里只有ur5+kinect的,ur3+realsense的修改即可。在ur5_kinect_calibration.launch基础上进行修改:cd ~/ur_ws/src/easy_handeye/docs/example_launch cp ur5_kinect_calibration.launch ~/ur_ws/src/easy_handeye/easy_handeye/launch/ur3_eye_to_hand_calibration.launch 修改launch文件如下:注意:realsense和ur机械臂最好分开启动,否则会有报错 <launch> <arg name="namespace_prefix" default="ur3_realsense_handeyecalibration" /> <arg name="robot_ip" doc="The IP address of the UR3 robot" /> <arg name="marker_size" doc="Size of the ArUco marker used, in meters" default="0.1" /> <arg name="marker_id" doc="The ID of the ArUco marker used" default="325" /> <!-- 1. start the Realsense435 --> <!-- <include file="$(find realsense2_camera)/launch/rs_camera.launch" /> --> <!-- 2. start ArUco --> <node name="aruco_tracker" pkg="aruco_ros" type="single"> <remap from="/camera_info" to="/camera/color/camera_info" /> <remap from="/image" to="/camera/color/image_raw" /> <param name="image_is_rectified" value="true"/> <param name="marker_size" value="$(arg marker_size)"/> <param name="marker_id" value="$(arg marker_id)"/> <param name="reference_frame" value="camera_color_frame"/> <param name="camera_frame" value="camera_color_frame"/> <param name="marker_frame" value="camera_marker" /> </node> <!-- 3. start the robot --> <!-- <include file="$(find ur_robot_driver)/launch/ur3_bringup.launch"> <arg name="limited" value="true" /> <arg name="robot_ip" value="192.168.56.10" /> </include> <include file="$(find ur3_moveit_config)/launch/ur3_moveit_planning_execution.launch"> <arg name="limited" value="true" /> </include> --> <!-- 4. start easy_handeye --> <include file="$(find easy_handeye)/launch/calibrate.launch" > <arg name="namespace_prefix" value="$(arg namespace_prefix)" /> <arg name="eye_on_hand" value="false" /> <arg name="tracking_base_frame" value="camera_color_frame" /> <arg name="tracking_marker_frame" value="camera_marker" /> <arg name="robot_base_frame" value="base" /> <arg name="robot_effector_frame" value="tool0_controller" /> <arg name="freehand_robot_movement" value="false" /> <arg name="robot_velocity_scaling" value="0.5" /> <arg name="robot_acceleration_scaling" value="0.2" /> </include> </launch> 分析launch文件,这里主要是🌒启动realsense相机,🌒启动ArUco,🌒启动UR3机械臂,🌒启动easy_handeye 四部分:Realsense435节点把rs_camera.launch文件导入ArUco节点修改:/camera_info / /image / reference_frame 和 camera_frame从https://chev.me/arucogen/中下载aruco二维码并打印出来注意: ❤ Dictionary 一定要选 Original ArUco❤ Marker ID 和 Marker size自选,在launch 文件中做相应的修改❤ 打印时注意选择原始大小,否则要测量一下打印出来的真实大小UR3节点这里用了 ur_robot_driver 包,而没有用原始的 ur_bringup 包修改机器人的真实 ipeasy_handeye节点<arg name="eye_on_hand" value="false"/> :眼在手外时,value 为 falsetracking_base_frame :为相机坐标系 camera_color_frame robot_base_frame :为机器人基座坐标系,示例里写的是 base_link,我在 rviz 中查看 base 才是真实的基座坐标系robot_effector_frame:为工具坐标系,因为我安装了 robotiq相机/力传感器和夹爪,所以TCP 改变了3.2 启动 launch 文件,开始标定3.2.1 启动realsenseroslaunch realsense2_camera rs_camera.launch 3.2.2 启动ur机械臂① 启动机械臂roslaunch ur_robot_driver ur3_bringup.launch limited:=true robot_ip:=192.168.56.10② 启动示教器 ③ 启动moveitroslaunch ur3_moveit_config ur3_moveit_planning_execution.launch limited:=true3.2.3 启动手眼标定的其他程序roslaunch easy_handeye ur3_eye_to_hand_calibration.launch3.3 标定launch文件启动后,会出现3个窗口。标定过程:首先打开一个终端,输入rqt,点击菜单栏的 Plugins -> Visulization -> Image View,选择 /aruco_tracker/result 话题。当识别出aruco码时,则可以进行下一步。 在第三个屏幕中点击check starting pose,若检查成功,界面会出现: 0/17,ready to start 在这里插入图片描述 在第三个窗口点击next pose -> plan -> execute,当点完 plan ,出现绿色框,则说明规划成功,然后可以点击 execute让机械臂执行动作 在这里插入图片描述 然后在第二个窗口,点击take sample采样 在这里插入图片描述 然后再次回到第三个窗口使机械臂执行规划动作。 当17个动作执行完成,回到第二个界面,点击compute,然后出现结果的姿态矩阵,然后可以点击save保存 在这里插入图片描述 在这里插入图片描述 4 报错以下的报错主要需要注意3点:① 单独启动ur机械臂和realsense相机,不要放到launch文件里一起启动 ② 三个标定窗口都启动后,注意再打开一个rqt窗口,确定识别出aruco码 ③ 如果有关于opencv的报错,需要升级opencv的版本 pip2 install opencv-python==4.2.0.32 下面是详细的报错信息及解决方法4.1 unused args [limited] for include如果不注释掉lauch文件中ur机械臂启动的部分,会遇到下述问题,所以最好的办法是ur机械臂单独启动报错1: guyue@guyue:~/ur_ws$ roslaunch easy_handeye ur3_eye_to_hand_calibration.launch ... logging to /home/guyue/.ros/log/7697ce46-6c91-11ec-9d22-38fc98e4336a/roslaunch-guyue-23663.log Checking log directory for disk usage. This may take a while. Press Ctrl-C to interrupt Done checking log file disk usage. Usage is <1GB. RLException: unused args [limited] for include of [/home/guyue/ur_ws/src/Universal_Robots_ROS_Driver/ur_robot_driver/launch/ur3_bringup.launch] The traceback for the exception was written to the log file 解决: 将ur机械臂启动中的limited注释 报错2: guyue@guyue:~/ur_ws$ roslaunch easy_handeye ur3_eye_to_hand_calibration.launch ... logging to /home/guyue/.ros/log/ecddcd44-6c91-11ec-9d22-38fc98e4336a/roslaunch-guyue-23704.log Checking log directory for disk usage. This may take a while. Press Ctrl-C to interrupt Done checking log file disk usage. Usage is <1GB. RLException: unused args [limited] for include of [/home/guyue/ur_ws/src/fmauch_universal_robot/ur3_moveit_config/launch/ur3_moveit_planning_execution.launch] The traceback for the exception was written to the log file 解决: 将ur机械臂启动中moveit启动的部分的limited注释 4.2 关于opencv版本的问题报错3: [ WARN] [1641220271.220611210]: normalizeImageIllumination is unimplemented! [ INFO] [1641220271.250652945]: rviz version 1.13.17 [ INFO] [1641220271.250695191]: compiled against Qt version 5.9.5 [ INFO] [1641220271.250704120]: compiled against OGRE version 1.9.0 (Ghadamon) [ INFO] [1641220271.253321240]: Forcing OpenGl version 0. [ INFO] [1641220271.336844200]: Stereo is NOT SUPPORTED [ INFO] [1641220271.336903845]: OpenGL device: Mesa DRI Intel(R) UHD Graphics (CML GT2) [ INFO] [1641220271.336918119]: OpenGl version: 3.0 (GLSL 1.3). Traceback (most recent call last): File "/home/guyue/ur_ws/src/easy_handeye/easy_handeye/scripts/calibrate.py", line 5, in <module> from easy_handeye.handeye_server import HandeyeServer File "/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_server.py", line 13, in <module> from easy_handeye.handeye_calibration_backend_opencv import HandeyeCalibrationBackendOpenCV File "/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_calibration_backend_opencv.py", line 4, in <module> import transforms3d as tfs ImportError: No module named transforms3d [ur3_realsense_handeyecalibration_eye_on_base/easy_handeye_calibration_server-4] process has died [pid 27827, exit code 1, cmd /home/guyue/ur_ws/src/easy_handeye/easy_handeye/scripts/calibrate.py __name:=easy_handeye_calibration_server __log:=/home/guyue/.ros/log/5cfd9712-6ca1-11ec-9d22-38fc98e4336a/ur3_realsense_handeyecalibration_eye_on_base-easy_handeye_calibration_server-4.log]. log file: /home/guyue/.ros/log/5cfd9712-6ca1-11ec-9d22-38fc98e4336a/ur3_realsense_handeyecalibration_eye_on_base-easy_handeye_calibration_server-4*.log arguments: Namespace(quiet=False) unknowns: [] [INFO] [1641220272.193446]: Configuring for calibration with namespace: /ur3_realsense_handeyecalibration_eye_on_base/ [INFO] [1641220272.194252]: Loading parameters for calibration /ur3_realsense_handeyecalibration_eye_on_base/ from the parameters server [INFO] [1641220272.523661]: Loading parameters for calibration ur3_realsense_handeyecalibration_eye_on_base/ from the parameters server [ INFO] [1641220272.533509978]: Loading robot model 'ur3_robot'... [ WARN] [1641220272.579945030]: Kinematics solver doesn't support #attempts anymore, but only a timeout. Please remove the parameter '/robot_description_kinematics/manipulator/kinematics_solver_attempts' from your configuration. [ INFO] [1641220273.754739224]: Ready to take commands for planning group manipulator. [ INFO] [1641220274.520914331]: Loading robot model 'ur3_robot'... [ WARN] [1641220274.558909017]: Kinematics solver doesn't support #attempts anymore, but only a timeout. Please remove the parameter '/robot_description_kinematics/manipulator/kinematics_solver_attempts' from your configuration. [ INFO] [1641220274.701571379]: Starting planning scene monitor 解决: 安装transforms3d guyue@guyue:~$ pip install transforms3d Command 'pip' not found, but can be installed with: sudo apt install python-pip guyue@guyue:~$ sudo apt install python-pip guyue@guyue:~$ pip install transforms3d 报错4: 依然报错 [ WARN] [1641220801.405651818]: normalizeImageIllumination is unimplemented! [ INFO] [1641220801.437421516]: Stereo is NOT SUPPORTED [ INFO] [1641220801.437463026]: OpenGL device: Mesa DRI Intel(R) UHD Graphics (CML GT2) [ INFO] [1641220801.437478491]: OpenGl version: 3.0 (GLSL 1.3). Traceback (most recent call last): File "/home/guyue/ur_ws/src/easy_handeye/easy_handeye/scripts/calibrate.py", line 5, in <module> from easy_handeye.handeye_server import HandeyeServer File "/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_server.py", line 13, in <module> from easy_handeye.handeye_calibration_backend_opencv import HandeyeCalibrationBackendOpenCV File "/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_calibration_backend_opencv.py", line 10, in <module> class HandeyeCalibrationBackendOpenCV(object): File "/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_calibration_backend_opencv.py", line 15, in HandeyeCalibrationBackendOpenCV 'Tsai-Lenz': cv2.CALIB_HAND_EYE_TSAI, AttributeError: 'module' object has no attribute 'CALIB_HAND_EYE_TSAI' [ur3_realsense_handeyecalibration_eye_on_base/easy_handeye_calibration_server-4] process has died [pid 29462, exit code 1, cmd /home/guyue/ur_ws/src/easy_handeye/easy_handeye/scripts/calibrate.py __name:=easy_handeye_calibration_server __log:=/home/guyue/.ros/log/e9da5296-6ca2-11ec-9d22-38fc98e4336a/ur3_realsense_handeyecalibration_eye_on_base-easy_handeye_calibration_server-4.log]. log file: /home/guyue/.ros/log/e9da5296-6ca2-11ec-9d22-38fc98e4336a/ur3_realsense_handeyecalibration_eye_on_base-easy_handeye_calibration_server-4*.log arguments: Namespace(quiet=False) unknowns: [] [INFO] [1641220802.356186]: Configuring for calibration with namespace: /ur3_realsense_handeyecalibration_eye_on_base/ [INFO] [1641220802.356995]: Loading parameters for calibration /ur3_realsense_handeyecalibration_eye_on_base/ from the parameters server [INFO] [1641220802.691195]: Loading parameters for calibration ur3_realsense_handeyecalibration_eye_on_base/ from the parameters server [ INFO] [1641220802.701319432]: Loading robot model 'ur3_robot'... [ WARN] [1641220802.748617616]: Kinematics solver doesn't support #attempts anymore, but only a timeout. Please remove the parameter '/robot_description_kinematics/manipulator/kinematics_solver_attempts' from your configuration. [ INFO] [1641220803.836626902]: Ready to take commands for planning group manipulator. [ INFO] [1641220804.638232086]: Loading robot model 'ur3_robot'... [ WARN] [1641220804.672640533]: Kinematics solver doesn't support #attempts anymore, but only a timeout. Please remove the parameter '/robot_description_kinematics/manipulator/kinematics_solver_attempts' from your configuration. [easy_handeye_calibration_server_robot-3] killing on exit PluginHandler.save_settings() plugin "rqt_easy_handeye/Hand-eye Calibration automatic movement#0" raised an exception: Traceback (most recent call last): File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_handler.py", line 191, in save_settings self._save_settings(plugin_settings, instance_settings) File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_handler_direct.py", line 114, in _save_settings self.emit_save_settings_completed() File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_handler.py", line 207, in emit_save_settings_completed callback(self._instance_id) File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_manager.py", line 459, in _close_application_save_callback self._close_application_shutdown_plugins() File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_manager.py", line 467, in _close_application_shutdown_plugins info['instance_id'], self._close_application_shutdown_callback) File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_manager.py", line 353, in _shutdown_plugin handler.close_signal.disconnect(self.unload_plugin) TypeError: disconnect() failed between 'close_signal' and 'unload_plugin' PluginHandler.save_settings() plugin "rqt_easy_handeye/Hand-eye Calibration#0" raised an exception: Traceback (most recent call last): File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_handler.py", line 191, in save_settings self._save_settings(plugin_settings, instance_settings) File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_handler_direct.py", line 114, in _save_settings self.emit_save_settings_completed() File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_handler.py", line 207, in emit_save_settings_completed callback(self._instance_id) File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_manager.py", line 459, in _close_application_save_callback self._close_application_shutdown_plugins() File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_manager.py", line 467, in _close_application_shutdown_plugins info['instance_id'], self._close_application_shutdown_callback) File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_manager.py", line 353, in _shutdown_plugin handler.close_signal.disconnect(self.unload_plugin) TypeError: disconnect() failed between 'close_signal' and 'unload_plugin' Traceback (most recent call last): File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_manager.py", line 454, in close_application global_settings, perspective_settings, self._close_application_save_callback) File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_manager.py", line 429, in _save_settings self._save_plugin_settings(info['instance_id'], callback) File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_manager.py", line 341, in _save_plugin_settings handler.save_settings(plugin_settings, instance_settings, callback) File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_handler.py", line 195, in save_settings self.emit_save_settings_completed() File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_handler.py", line 202, in emit_save_settings_completed self._call_method_on_all_dock_widgets('save_settings', self.__instance_settings) File "/opt/ros/melodic/lib/python2.7/dist-packages/qt_gui/plugin_handler.py", line 213, in _call_method_on_all_dock_widgets settings = instance_settings.get_settings(name) AttributeError: 'NoneType' object has no attribute 'get_settings' [ur3_realsense_handeyecalibration_eye_on_base/calibration_mover-6] escalating to SIGTERM shutting down processing monitor... ... shutting down processing monitor complete 解决: AttributeError: 'module' object has no attribute'CALIB_HAND_EYE_TSAI' 出现这个问题的原因在于python的opencv版本过低,低版本的opencv中没有手眼标定的函数,因此需要更新opencv版本即可。 pip2 install opencv-python==4.2.0.32 参考: - https://github.com/IFL-CAMP/easy_handeye/issues/78 - https://blog.csdn.net/m0_53621852/article/details/121021402 4.3 关于camera_marker的报错[ERROR] [1641266714.990937]: Error processing request: “camera_marker” passed to lookupTransform argument source_frame does not exist. [‘Traceback (most recent call last):\n’, ’ File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py”, line 632, in _handle_request\n response = convert_return_to_response(self.handler(request), self.response_class)\n’, ’ File “/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_server.py”, line 88, in take_sample\n self.sampler.take_sample()\n’, ’ File “/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_sampler.py”, line 88, in take_sample\n transforms = self._get_transforms()\n’, ’ File “/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_sampler.py”, line 78, in _get_transforms\n Duration(10))\n’, ’ File “/opt/ros/melodic/lib/python2.7/dist-packages/tf2_ros/buffer.py”, line 87, in lookup_transform\n return self.lookup_transform_core(target_frame, source_frame, time)\n’, ‘LookupException: “camera_marker” passed to lookupTransform argument source_frame does not exist. \n’] Traceback (most recent call last): File “/home/guyue/ur_ws/src/easy_handeye/rqt_easy_handeye/src/rqt_easy_handeye/rqt_easy_handeye.py”, line 132, in handle_take_sample sample_list = self.client.take_sample() File “/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_client.py”, line 76, in take_sample return self.take_sample_proxy().samples File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py”, line 442, in call return self.call(*args, *kwds) File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py”, line 522, in call responses = transport.receive_once() File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_base.py”, line 735, in receive_once p.read_messages(b, msg_queue, sock) File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py”, line 360, in read_messages self._read_ok_byte(b, sock) File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py”, line 343, in _read_ok_byte raise ServiceException(“service [%s] responded with an error: %s”%(self.resolved_name, str)) rospy.service.ServiceException: service [/ur3_realsense_handeyecalibration_eye_on_base/take_sample] responded with an error: error processing request: “camera_marker” passed to lookupTransform argument source_frame does not exist. [ur3_realsense_handeyecalibration_eye_on_base/namespace_guyue_11030_7952019406960363886_rqt-5] process has died [pid 11069, exit code -6, cmd /home/guyue/ur_ws/src/easy_handeye/rqt_easy_handeye/scripts/rqt_easy_handeye __name:=namespace_guyue_11030_7952019406960363886_rqt __log:=/home/guyue/.ros/log/4f4a0756-6d0d-11ec-b452-38fc98e4336a/ur3_realsense_handeyecalibration_eye_on_base-namespace_guyue_11030_7952019406960363886_rqt-5.log]. log file: /home/guyue/.ros/log/4f4a0756-6d0d-11ec-b452-38fc98e4336a/ur3_realsense_handeyecalibration_eye_on_base-namespace_guyue_11030_7952019406960363886_rqt-5.log 解决: 打开rqt,对准二维码,然后让rviz中出现了这个坐标 注意realsense需要单独启动4.4 在仿真环境运行的报错[INFO] [1641298197.817943, 69.092000]: Taking a sample… [ERROR] [1641298207.884633, 79.146000]: Error processing request: Lookup would require extrapolation into the past. Requested time 69.094000000 but the earliest data is at time 1641298197.859954119, when looking up transform from frame [camera_marker] to frame [camera_color_frame] [‘Traceback (most recent call last):\n’, ’ File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py”, line 632, in _handle_request\n response = convert_return_to_response(self.handler(request), self.response_class)\n’, ’ File “/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_server.py”, line 88, in take_sample\n self.sampler.take_sample()\n’, ’ File “/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_sampler.py”, line 88, in take_sample\n transforms = self._get_transforms()\n’, ’ File “/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_sampler.py”, line 78, in _get_transforms\n Duration(10))\n’, ’ File “/opt/ros/melodic/lib/python2.7/dist-packages/tf2_ros/buffer.py”, line 87, in lookup_transform\n return self.lookup_transform_core(target_frame, source_frame, time)\n’, ‘ExtrapolationException: Lookup would require extrapolation into the past. Requested time 69.094000000 but the earliest data is at time 1641298197.859954119, when looking up transform from frame [camera_marker] to frame [camera_color_frame]\n’] Traceback (most recent call last): File “/home/guyue/ur_ws/src/easy_handeye/rqt_easy_handeye/src/rqt_easy_handeye/rqt_easy_handeye.py”, line 132, in handle_take_sample sample_list = self.client.take_sample() File “/home/guyue/ur_ws/src/easy_handeye/easy_handeye/src/easy_handeye/handeye_client.py”, line 76, in take_sample return self.take_sample_proxy().samples File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py”, line 442, in call return self.call(*args, *kwds) File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py”, line 522, in call responses = transport.receive_once() File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_base.py”, line 735, in receive_once p.read_messages(b, msg_queue, sock) File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py”, line 360, in read_messages self._read_ok_byte(b, sock) File “/opt/ros/melodic/lib/python2.7/dist-packages/rospy/impl/tcpros_service.py”, line 343, in _read_ok_byte raise ServiceException(“service [%s] responded with an error: %s”%(self.resolved_name, str)) rospy.service.ServiceException: service [/ur3_realsense_handeyecalibration_eye_on_base/take_sample] responded with an error: error processing request: Lookup would require extrapolation into the past. Requested time 69.094000000 but the earliest data is at time 1641298197.859954119, when looking up transform from frame [camera_marker] to frame [camera_color_frame] [ur3_realsense_handeyecalibration_eye_on_base/namespace_guyue_2228_1559384220386469985_rqt-5] process has died [pid 2270, exit code -6, cmd /home/guyue/ur_ws/src/easy_handeye/rqt_easy_handeye/scripts/rqt_easy_handeye __name:=namespace_guyue_2228_1559384220386469985_rqt __log:=/home/guyue/.ros/log/119cbc42-6d57-11ec-b452-38fc98e4336a/ur3_realsense_handeyecalibration_eye_on_base-namespace_guyue_2228_1559384220386469985_rqt-5.log]. log file: /home/guyue/.ros/log/119cbc42-6d57-11ec-b452-38fc98e4336a/ur3_realsense_handeyecalibration_eye_on_base-namespace_guyue_2228_1559384220386469985_rqt-5.log ^C[rviz_guyue_2228_7026475105225641117-7] killing on exit [ur3_realsense_handeyecalibration_eye_on_base/calibration_mover-6] killing on exit [easy_handeye_calibration_server_robot-3] killing on exit [ur3_realsense_handeyecalibration_eye_on_base/easy_handeye_calibration_server-4] killing on exit [aruco_tracker-1] killing on exit [dummy_handeye-2] killing on exit shutting down processing monitor… … shutting down processing monitor complete done 解决: 因为前面的报错太多,所以就准备先在gazebo中运行没有错误后再连接真实的机械臂,然后前面的错误报完以后出现这个错误,这个错误不必在意,连接真实机械臂后就不报这个错误了。 使用gazebo调试的方法: 把连接真实ur机械臂ip地址那句换为启动ur机械臂gazebo的语句;并且启动ur机械臂moveit的语句后面标记sim为true 5 总结安装功能包 修改lauch文件(放入启动aruco和easy_handeye部分),并放到easy_handeye功能包下面 启动realsense roslaunch realsense2_camera rs_camera.launch 启动ur机械臂 # 1. 启动机械臂 roslaunch ur_robot_driver ur3_bringup.launch limited:=true robot_ip:=192.168.56.10 # 2. 启动示教器 # 3. 启动moveit roslaunch ur3_moveit_config ur3_moveit_planning_execution.launch limited:=true 启动手眼标定程序 roslaunch easy_handeye ur3_eye_to_hand_calibration.launch 启动rqt查看是否能识别到aruco码(点击菜单栏的 Plugins -> Visulization -> Image View,选择 /aruco_tracker/result 话题) 在窗口3检测当前位置是否可行check starting pose,依次点击next pose -> plan -> execute(注意plan完是绿色才可以execute) 在这里插入图片描述 每次执行完机械臂动作,在窗口2点击take sample,共17次,然后点击compute计算,结果显示在右下方 注: 如果手眼标定launch文件启动有问题,可能是opencv版本不对: pip2 install opencv-python==4.2.0.32
1. Github网站搜索官网:https://github.com/2. 工作空间创建工作空间mkdir catkin_ws cd catkin_ws mkdir src下载git工具sudo apt install git3. WPR系列机器人仿真工具3.1 系统版本该项目暂时提供三个版本,我选择的18.04 ROS MelodicROS Noetic (Ubuntu 20.04)ROS Melodic (Ubuntu 18.04)ROS Kinetic (Ubuntu 16.04)github搜索wpr_simulation3.2 复制https git下载链接 获取源码:cd ~/catkin_ws/src/ git clone https://github.com/6-robot/wpr_simulation.git文件查看3.3 安装依赖项:依赖包版本匹配ROS Melodic (Ubuntu 18.04)cd ~/catkin_ws/src/wpr_simulation/scripts ./install_for_Melodic.sh3.4 编译工作空间cd ~/catkin_ws catkin_make3.5 载入工作空间的环境配置source ~/catkin_ws/devel/setup.bash3.6 运行编译的ros程序简单场景:roslaunch wpr_simulation wpb_simple.launch显示gazebo仿真环境3.6 运行rqt控制的ros程序rosrun rqt_robot_steering rqt_robot_steering 然后滑动速度和角速度3.7 提前初始化source文件gedit ~/.bashrc添加source文件# Set ROS melodic source /opt/ros/melodic/setup.bash source ~/catkin_ws/devel/setup.bash修改后保存后面可以直接启动catkin_ws下的ros程序
1. 前期准备首先进入系统的软件和更新,选择清华源2. 设置软件源:清华匹配的ros_ubuntu版本sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ $DISTRIB_CODENAME main" > /etc/apt/sources.list.d/ros-latest.list'3. 设置最新的密钥:sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F42ED6FBAB17C6544. 安装更新sudo apt-get update5. 安装ROS Melodicsudo apt-get install ros-melodic-desktop-full6. 安装 ros-melodic-rqtsudo apt-get install ros-melodic-rqt*7. 先安装ros-pythonsudo apt-get install python-rosdep8. 初始化rosdep: sudo rosdep init出现如下错误/三种方法8.1 第一种电脑连接手机热点8.2 第二种修改系统访问地址基本是网络问题,换个网络尝试下(PS:我用手机热点解决的):访问 The Best IP Address, 查询 raw.githubusercontent.com 的ip地址我的是111.4.135.201打开sudo gedit /etc/hosts111.4.135.201 raw.githubusercontent.com8.3 第三种通过访问其他地址仓库我台式机第三种,采用如果报错请重启再试一是,非常谢谢阿杰:https://www.bilibili.com/video/BV1aP41137k9/?spm_id_from=333.788&vd_source=530bf85167de80ff1628de3bdb9da898sudo apt-get install python3-pipsudo pip3 install 6-rosdepsudo 6-rosdepsudo rosdep init rosdep update9. 安装rosinstallsudo apt-get install python-rosinstall10. 加载环境设置文件source /opt/ros/melodic/setup.bash11. 创建并初始化工作目录ROS使用一个名为catkin的ROS专用构建系统。为了使用它,用户需要创建并初始化 catkin工作目录,如下所示。除非用户创建新的工作目录,否则此设置只需设置一次。 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src catkin_init_workspace目前,只有src目录和CMakeLists.txt文件在catkin工作目录中,使用catkin_make命令来构建ifconfigip地址是192.168.1.110 cd ~/catkin_ws/ catkin_make设置环境变量:sudo apt install net-tools gedit ~/.bashrc # Set ROS melodic source /opt/ros/melodic/setup.bash source ~/catkin_ws/devel/setup.bash # Set ROS Network #ifconfig查看你的电脑ip地址 export ROS_HOSTNAME=192.168.1.110 export ROS_MASTER_URI=http://${ROS_HOSTNAME}:11311 # Set ROS alias command 快捷指令 alias cw='cd ~/catkin_ws' alias cs='cd ~/catkin_ws/src' alias cm='cd ~/catkin_ws && catkin_make'12. 超级终端Terminator ROS开发得力助手sudo apt install terminatorctr+alt+t快捷打开终端 Ctrl+Shift+O Split terminals Horizontally.(上下开新窗口) Ctrl+Shift+E Split terminals Vertically.(垂直开新窗口) Ctrl+Shift+Right Move parent dragbar Right.(放大当前窗口 向右) Ctrl+Shift+Left Move parent dragbar Left. Ctrl+Shift+Up Move parent dragbar Up. Ctrl+Shift+Down Move parent dragbar Down. Ctrl+Shift+W Close the current terminal. Alt+Up Move to the terminal above the current one.(切换当前窗口) Alt+Down Move to the terminal below the current one. Alt+Left Move to the terminal left of the current one. Alt+Right Move to the terminal right of the current one. Ctrl+Shift+S Hide/Show Scrollbar.(隐藏滚动条) Ctrl+Shift+F Search within terminal scrollback Ctrl+Shift+N or Ctrl+Tab Move to next terminal within the same tab, use Ctrl+PageDown to move to the next tab. If cycle_term_tab is False, cycle within the same tab will be disabled Ctrl+Shift+P or Ctrl+Shift+Tab Move to previous terminal within the same tab, use Ctrl+PageUp to move to the previous tab. If cycle_term_tab is False, cycle within the same tab will be disabled Ctrl+Shift+C Copy selected text to clipboard Ctrl+Shift+V Paste clipboard text Ctrl+Shift+Q Quits Terminator Ctrl+Shift+X (最大化当前窗口) Toggle between showing all terminals and only showing the current one (maximise). Ctrl+Shift+Z Toggle between showing all terminals and only showing a scaled version of the current one (zoom). Ctrl+Shift+T Open new tab Ctrl+Shift+Alt+T Open new tab at root level, if using extreme_tabs. Ctrl+PageDown Move to next Tab Ctrl+PageUp Move to previous Tab Ctrl+Shift+PageDown Swap tab position with next Tab Ctrl+Shift+PageUp Swap tab position with previous Tab Ctrl+Shift+F Open buffer search bar to find substrings in the scrollback buffer. Hit Escape to cancel. Ctrl+Plus (+) Increase font size. Note: this may require you to press shift, depending on your keyboard Ctrl+Minus (-) Decrease font size. Note: this may require you to press shift, depending on your keyboard Ctrl+Zero (0) Restore font size to original setting. F11 Toggle fullscreen(放大当前窗口) Ctrl+Shift+R Reset terminal state Ctrl+Shift+G Reset terminal state and clear window此时,我们可以对终端进行“水平分割”或“垂直分割”等命令:13. 小海龟测试打开三个终端:roscore rosrun turtlesim turtlesim_node rosrun turtlesim turtle_teleop_key总结:行则将至,作则必成
1. 前言1.1 需求分析上个月我买了一台主机,原先19年的飞行堡垒不中用了但可以正常办公,这不清明节快要来了吗!这不要回去好好祭祖,保佑我后面项目事事顺心。但是我想发挥主机的画图作用,天猫精灵的开关我也有,想在家用笔记本远程控制学校电脑开关机,网上也有相关教程,不过我是记得向日葵等远程协助的软件登录不了。😥😥😥1.2 原因分析2022年秋季广大高校对远程协助的软件进行限制,由于远程协助的软件(TeamViewer、Todesk、向日葵等)相继被爆出重大网络安全漏洞,黑客组织可通过这些安全漏洞获取客户端的远程操作权限,并窃取个人信息。因此许多远程协助的软件被禁,我悉心找到一款好用的远程控制软件「RayLink」(这一款应该也有网络安全漏洞),大家且过且珍惜吧!🤣🤣🤣但是目前大多数远程控制软件都采用了付费+免费的模式,当然免费的会有诸多功能限制,而最近刚新出的「RayLink」远程控制软件,完全免费,并且功能超给力,提供高帧率支持、不限制绑定设备数量等,要知道这些功能在大多数远程控制软件里都需要付费的。2. 方案设计整体构思,首先两台电脑都下载「RayLink」软件,用同一账号登录两台电脑,允许学校被控主机的「RayLink」软件自启动。设置学校被控主机的BIOS电源启动项(Restore AC Power Loss)为Power On。采用天猫精灵智能开关启动学校主机,以此形成封闭的控制链。2.1 RayLink下载官网地址:https://www.raylink.live/因为「RayLink」是刚上线的远程控制软件软件,目前只有发布了 Windows 版本,不过官方网站里显示 macOS、iOS、安卓、Linux 版本即将上线,后续锋哥也会给大家体验评测其它平台版本。安装好后跟大多数远程控制软件一样使用简单,只需要输入需远程控制电脑的设备码和密码即可远程连接。如果你有多台电脑需要经常远程控制,建议注册账户登录,这样方便在受控列表里面直接连接你的设备,就不用每次去输入设备码了,以及可以快速对远程控制的电脑进行锁屏、打开任务管理器、重启、关机操作。另外注册登录的用户可以获得更多功能支持,包括60/120帧率、隐私模式、4:4:4色彩、数位板支持、游戏手柄支持、虚拟屏等等。功能设置方面:支持受控结束后自动锁定本机屏幕,支持可选择密码的更新方式,如果你是重度远程用户,建议选择每次受控结束后更新密码,以提高安全性。远程速度:连接远程控制软件后在功能栏里可以看到当前的延迟、带宽、帧率、颜色模式、连接方式。锋哥测试的延迟在 3 ms 左右,还是非常给力的。清晰度:提供了流畅、高清、超清。当你网络环境不佳的时候,可以尝试降低清晰度以减少带宽。 帧率方面:提供了 30 / 60 / 120 三种,有些小伙伴远程办公可能是剪辑视频,加上目前大多数视频都采用了高帧率拍摄,在「RayLink」里选择高帧率可以获得更好的剪辑体验。另外如果你是远程玩游戏、看电影,选择高帧率也可以获得丝滑体验。色彩模式:如果你是设计行业,对色彩的准确度要求也会非常高,在「RayLink」里提供了 YUV4:4:4 无损采样方式,远程控制显示的画面完全没有经过压缩抽样,可以完成呈现亮度和色度,无损还原真实色彩。设备支持:支持数位板和数位屏,主控连接数位板后,即可远程使用数位板操作了,以及支持游戏手柄设备。不过锋哥目前没有这些设备,就没法演示了,建议你下载后自己试试看。传送文件:远程控制软件控制难免会需要传送文件,支持拖拽传输和剪切板复制粘贴传输。传输速度实测还是蛮快的,当然传输速度主要还是看你当前的带宽。隐私模式:如果你不希望被控端被别人看到你的操作,或者看到隐私内容,也可以开启隐私模式,开启后被控端屏幕就会关闭。两台电脑都下载「RayLink」软件,用同一账号登录两台电脑,允许学校被控主机的「RayLink」软件自启动。2.2 BIOS来电重启项1、首先要重启电脑;2、开机后根据自己电脑查表使用快捷键进入BIOS界面,我的电脑是铭瑄按ESC进入BIOS;3、用键盘上的上下左右键选择Power Management,再选择下方的Restore AC Power Loss,这一项控制是否支持来电启动,默认是关闭的Power Off;4、点击回车键,将该选项设置为Power On;5、选择后再点击回车键,就设为支持来电启动了,保存设置重启;2.3 天猫精灵智能开关去淘宝购买一个智能开关,我是喜欢天猫精灵这一系列的,19.9包邮那种插座先通电,手机下载天猫精灵app,然后打开app连接实验室的网络查找插座设备,我设置成电脑设备,然后将电脑主机的电源插座插到智能开关上。3. 实验效果3.1 远程控制效果先登录Raylink,用同一账号登录两台电脑,在自己的笔记本上测试如下:此图显示当前主机此图显示可以远程控制的被控主机控制效果非常流畅,3.2 远程开关机效果采用Ctrl+Alt+Delete启动任务管理器,即可关机此时主机关机,然后关掉智能插座,点一下开关关闭主机电源。大约等10s钟后,再点一下智能开关,电脑通电就自动开机,你就可以愉快远程啦!🎉🎉🎉4. 总结本例程是基于在家远程控制校园网主机开关机方案,对比市面上其它远程控制软件,目前「RayLink」完全免费,还是非常良心的,加上它为二三维设计行业、如三维动画制作影视特效制作、建筑效果图设计、以及游戏开发提供远程办公解方案、各种场景需求而定制了一些功能,基本上可以满足大多数人的远程控制软件需求,强烈推荐下载使用,记住低调使用。
1. 问题来源实验室的一个dell显示器,通过HDMI连接电脑后,在Windows上连接上就直接可以使用了。由于我电脑上安装是Windows11+Ubuntu18.04双系统,在我切换到Ubuntu时,显示器可以正常显示,但直接无法识别外接显示屏(dell 1080p)。在参照各种博客的情况下还是没有找到解决办法,但是这些博客的解决方案给我提供了解决思路,我也大体知道了问题的原因所在。是因为系统没有识别出外接显示器。2. 检查Ubuntu是否识别出外接显示器通过命令xrandr来查看robot@ms:~$ xrandr xrandr: Failed to get size of gamma for output default Screen 0: minimum 1024 x 768, current 1024 x 768, maximum 1024 x 768 default connected primary 1024x768+0+0 0mm x 0mm 1024x768 76.00* robot@ms:~$如果出现下面的内容,说明已经系统已经识别出了外接显示器,但是没有正常显示,直接1024 x 768。3. 解决没有识别出外接显示器问题如果上面的内容没有显示,那么说明系统无法识别你的显示器。这是因为外接显示器是使用你电脑的独立显卡驱动,而Ubuntu的内置显示器是使用集显驱动。如果你电脑没有独立显卡的话,也就不会出现识别问题了。因此,只要将系统的显卡驱动更换为独立显卡的驱动就可以了。下面是操作的步骤:我这里使用的系统是Ubuntu18.04.5 LTS在设置中找到“软件和更新”更改驱动设置点击附加驱动,下面可以显示系统支持的驱动,系统默认是使用下图中第三个驱动,每个人附加驱动的内容不同,每个根据自己电脑的情况选择驱动。然后再点击应用更改按钮,这里需要提醒的是这个过程会用时较长,只要耐心等待就可以啦,不必怀疑是不是出问题了,就是单纯的慢而已。。。在更改完驱动后,重启一下电脑,你会发现显示器直接可以显示内容了。4. 显示器扩展屏幕设置在外接显示时,和Windows系统一样,会默认设置为将显示器右扩展,因此如果想要更改的话可以通使用命令行和系统设置两种方法。命令行更改屏幕转换 //查看显示屏设置信息 xrandr //将外接显示器设置为自动达到最优分辨率 xrandr --output HDMI-0 --auto --primary //转换左右关系 xrandr --output eDp-1-1 --right-of HDMI-0 -auto上面命令需要注意的是其中HDMI-0和eDp-1-1要换成第一步查看显示屏设置信息中你自己电脑中显示的名字。希望能给您在使用Ubuntu显示屏设置过程中提供帮助。
1. 简介此文档的目的在于让使用者能够快速熟悉N32WB03x系列蓝牙SOC芯片的开发套件以及Keil MDK-ARM的相关设定,以减少开发前期的准备时间,降低开发难度。官网地址:https://www.nationstech.com/cpjs273/文档地址:https://www.nationstech.com/uploadfile/file/20230206/1675671659217095.pdfN32WB031_STB 开发板:https://www.nationstech.com/uploadfile/file/20230206/1675669890941879.zip1.1 产品简介N32WB03x系列蓝牙芯片是国民技术新一代高性能、超低功耗的蓝牙5.1芯片,采用32位Arm® Cortex®-M0内核,最高工作主频64MHz,片上集成48KB SRAM,256/512KB Flash。芯片集成先进的 BLE5.1射频收发器,符合蓝牙BLE5.1规范,可配置为标准的1Mbps BLE模式,2Mbps增强BLE模式, 125Kbps BLE远程模式(S8),500Kbps BLE远程模式(S2)。支持AOA(到达角)和AOD(离去角),支持 RSS I ( 接 收 器 信 号 强 度 指 示 ),同 时 支 持 主 从 角 色,支 持 多 连 接,支 持 数 据 包 长 度 扩 展,支 持 KEYSCAN,IRC,10位1.33Msps ADC(可配置为16位16Ksps),支持模拟MIC输入,PGA放大,支持基 本、通用、高级TIMER,RTC,WWDG,IWDG,LPUART,USART,SPI,I2C等外设。1.2 主要资源1.3 典型应用2. SDK/开发固件文件目录结构SDK 目录下是一个以固件库版本命名的文件,其中包含五个子文件夹:2.1 doc即SDK相关的说明文档,包含SDK使用指南和固件升级使用指南等。2.2 firmwareCMSIS:微控制器软件接口标准,是Cortex-M处理器系列的与供应商无关的硬件抽象层, CMSIS提供了内核与外设、实时操作系统和中间设备之间的通用接口。包含了用来访问内核的寄存器设备的名称定义,地址定义和配置函数。该接口包括调试通道定义。提供片上所有外设的定义,包括所有外设寄存器头文件、启动文件、系统初始化模板文件。n32wb03x_std_periph_driver:芯片外设的标准驱动函数,包括.c 的源文件和.h 的头文件。用户可移植到项目中,快速完成对某个外设模块的使用。2.3 middleware中间层固件,主要如下两个目录:Third_Party FreeRTOS: FreeRTOS 相关库Nationstech ble_library: 蓝牙BLE 相关库 ns_ble_stack: ble 蓝牙协议栈头文件 ns_ble_profile: ble profile 库源码 ns_library: ble 程序其他库源码,包含 log,sleep 和 timer 等2.4 utilities工具软件目录, 里面主要包含:dfu:固件升级相关工具软件目录和调用这些工具的 bat 脚本 Image:使用 bat 脚本生成的 bin 文件和用于DFU 演示的 bin 文件 JLink:烧录工具 Keys:用于生成 dfu 升级 bin 的密匙 NSAndroidUtil: DFU 测试 APK NSUtil:串口升级工具软件和源码2.5 projects Projects目录包含开发板目录,开发板目录下包含:bsp:包含调试串口打印功能的 log 函数,用于外设例程在调试过程答应各种调试信息。pplication:应用例程,使用了多种外设或者功能需求的综合性例程 peripheral_alone: 外设综合例程,包含串口通信,TIM 的 PWM 输出,ADC 读取和转为电压,IO 输出,IO输入中断响应和 RTC 休眠唤醒 ble_hid_rcu:蓝牙遥控器例程,使用 KEYSCAN 模块,ADC PGA 模块读取声音和蓝牙HID 数据发 送 FreeRTOS:Freertos 相关例程ble:蓝牙从机例程,通过对具体 profile 的蓝牙例程了解蓝牙程序开发的基本方法 dis:设备服务例程 hid_mouse: 蓝牙鼠标例程 rdtss: 蓝牙数传例程(128bit UUID),包含 DFU空中升级项目选项 rdtss_16bit: 蓝牙数传例程(16bit UUID),包含 DFU 空中升级项目选项heart_rate: 蓝牙心率服务例程 blood_pressure: 蓝牙血压服务例程。ble_central:蓝牙主机例程 central_rdtsc:蓝牙数传服务主机例程。可以配合 rdtss 例程使用。central_rdts_c&s:蓝牙数传服务主机和从机模式切换例程。可以配合rdtss或central_rdtsc例程使用。central_relay_1m1s:蓝牙数传服务中继例程,即一主一从同时工作。可以配合 rdtss 例程使用。dfu:设备固件升级例程 common: dfu 公共库目录 app_ota:蓝牙空中升级例程 image_update:单 bank模式下,image_update 例程源码 app_usart:串口升级例程(跳转 masterboot) masterboot:固件升级 boot,包含串口升级,固件校验和跳转peripheral: 包含各个外设功能模块的例程项目,实现每个外设模块的基本功能应用开发,用户可以通过这些例程项目快速了解芯片外设用法。3. 项目配置与烧录3.1 编译环境安装请安装KEIL MDK-ARM开发环境,版本要求为V5.00以上,建议使用V5.24.2.0。从MDK的官网可以下载得到MDK的安装包,然后安装即可,关于的MDK安装请看这个大佬的教程。MDK安装教程:https://blog.csdn.net/bruceoxl/article/details/108548573MDK下载地址:https://www.keil.com/download/product/3.2 固件支持包安装双击运行N32WB03x_DFP.1.1.0.pack安装Keil芯片支持包。支持包地址:https://www.nationstech.com/uploadfile/file/20230206/1675669890941879.zip3.3 编译环境配置注:所有例程已经按如下配置完成,所以运行例程不需要重新配置编译环境。Target页的FLASH和RAM配置 不包含ble功能项目 包含ble功能项目target页 带DFU功能项目,请参考《固件升级使用指南.PDF》Linker页 勾选使用Target页的memory配置 带ble项目需要加middlewares\Nationstech\ble_library\ns_ble_stack\symdef\symbol_g15.obj文件于Misc control,注意包含蓝牙主机功能的程序使用的obj文件是symbol_g15_central.objDebug页 调试器选择CMSIS-DAP Debugger作为开发板上的NS-Link Setting页面如下图3.4 编译与下载 编译:点击菜单的build按钮 下载:点击菜单的download按钮 调试:点击菜单的start/stop debug session按钮注意:下载程序后无法继续再下载 可能1: 代码中将SWDIO/SWDCLK用作其他用途,导致仿真接口失效。一般情况下不建议使用仿真引 脚用作其他功能设计 可能2:芯片进入低功耗sleep模式,此时仿真接口失效,需要在唤醒状态下下载,直接reset然后下载。3.5 BLE工程目录结构以rdtss蓝牙项目工程为例 Project Target N32WB03x: 蓝牙工程,不带DFU配置,一般ble项目只有这个target OTA_IMG_1:带蓝牙OTA工程,配置为Bank1地址 OTA_IMG_2:带蓝牙OTA工程,配置为Bank2地址目录结构如下 STARTUP:芯片启动文件 CMSIS:芯片内核配置 FWLB:芯片外设驱动库 BLE_STACK:蓝牙BLE协议栈 BLE_PROFILE:蓝牙BLE profile NS_DUF(可选):蓝牙OTA固件升级相关库 Crypto(可选):蓝牙OTA固件升级使用的加密相关库 NS_LIB:蓝牙应用相关库 BLE_APP:蓝牙应用代码 USER:用户应用代码 CONFIG:配置文件 DOC:说明文档 1、功能说明 蓝牙BLE数传服务(rdts)例程,使用128bit UUID。BLE主机连接设备后,下行数据将透传到USART1,USART1收到的数据将透传到BLE主机 2、使用环境 软件开发环境: KEIL MDK-ARM V5.24.2.0 硬件环境: 基于N32WB031_STB开发板 3、使用说明 系统配置; 1、时钟源:HSI=64M 2、调试串口使用的是LPUART(PB1/PB2),波特率是115200,8bit数据位,无校验位,1bit停止位,无流控。 3、数据串口使用USART1(PB6/PB7),波特率115200,8bit数据位,无校验位,1bit停止位,无流控。 4、蓝牙BLE名:NS_RDTSS 5、LED1开机即亮,LED2指示连接状态,蓝牙连上后亮 使用方法: 1、编译后烧录到开发板 4、注意事项 由于程序会进入sleep模式,则SWD将不能访问,请按RESET按钮后,在一秒之内执行烧录程序步骤。main.c/***************************************************************************** * Copyright (c) 2019, Nations Technologies Inc. * * All rights reserved. * **************************************************************************** * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Nations' name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /** * @file main.c * @author Nations Firmware Team * @version v1.0.1 * * @copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved. */ /** @addtogroup * @{ */ /* Includes ------------------------------------------------------------------*/ #include "n32wb03x.h" #include "rwip.h" #include "ns_ble.h" #include "ns_sleep.h" #include "ns_delay.h" #include "ns_log.h" #include "app_usart.h" #include "app_gpio.h" #include "app_ble.h" #if (CFG_APP_NS_IUS) #include "ns_dfu_boot.h" #endif /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ #define DEMO_STRING "\r\n Nations raw data transfer server(128bit UUID) demo \r\n" /* Private constants ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /** * @brief main function * @param * @return * @note Note */ int main(void) { //for hold the SWD before sleep delay_n_10us(200*1000); NS_LOG_INIT(); #if (CFG_APP_NS_IUS) if(CURRENT_APP_START_ADDRESS == NS_APP1_START_ADDRESS){ NS_LOG_INFO("application 1 start new ...\r\n"); }else if(CURRENT_APP_START_ADDRESS == NS_APP2_START_ADDRESS){ NS_LOG_INFO("application 2 start new ...\r\n"); } #endif app_ble_init(); NS_LOG_INFO(DEMO_STRING); // periph init LedInit(LED1_PORT,LED1_PIN); // power led LedInit(LED2_PORT,LED2_PIN); //connection state LedOn(LED1_PORT,LED1_PIN); app_usart_dma_enable(ENABLE); //init text usart_tx_dma_send((uint8_t*)DEMO_STRING, sizeof(DEMO_STRING)); delay_n_10us(500); //disable usart for enter sleep app_usart_dma_enable(DISABLE); while (1) { /*schedule all pending events*/ rwip_schedule(); ns_sleep(); } } /** * @brief user handle before enter sleep mode * @param * @return * @note */ void app_sleep_prepare_proc(void) { } /** * @brief user handle after wake up from sleep mode * @param * @return * @note */ void app_sleep_resume_proc(void) { } /** * @} */4 Memory分配4.1 Flash分配N32WB031芯片FLASH地址范围是0x01000000 - 0x0107FFFF,总空间为512K字节,分为BankA、BankB两个Bank,空间大小分别是256K字节,BankA地址范围是0x01000000 - 0x0103FFFF,BankB地址范围是0x01040000 - 0x0107FFFF。用户代码运行范围只能是其中一个Bank,默认使用BankA。注意N32WB031KC系列FLASH空间是256K,即只有BankA区域。需要使用固件升级功能请参考《固件升级使用指南.PDF》里面的FLASH内存分布章节。4.2 RAMN32WB031芯片RAM地址范围是0x20000000 - 0x2000BFFF,可用空间为48K字节 如果使用蓝牙功能,蓝牙协议栈将占用0x20000000 -0x20003FFF,总共16K字节RAM,用户代码可以使用0x20004000 - 0x2000BFFF,总共32K字节RAM 如果不用蓝牙功能,则用户代码可以使用全部48K字节RAM5. 系统时钟5.1 不带蓝牙协议栈例程系统时钟源可以选择HSE或者HSI,所有外设例程默认使用HSI 64M作为系统时钟源。低速时钟源可以选择外部晶体LSE 32.768K或者内部LSI 32K时钟源。5.2 蓝牙例程所有蓝牙例程默认使用HSI 64M作为系统时钟源,使用LSI作为低速时钟源,必须外接32M晶体为蓝牙射频专用时钟源。系统时钟源不建议更改,低速时钟源可以选择外部晶体LSE 32.768K或者内部LSI 32K时钟源,但是只能在蓝牙协议栈初始化函数里配置LSI或者LSE并初始化低速时钟源,用户代码后续不能切换低速时钟源,否则将影响蓝牙协议栈的功能。
1. 前言本例演示了采用CH307串口3与Arduino软串口收发通信,熟悉STM32和Arduino开发用易上手配置。✨✨✨这是使用MounRiver Studio开发的项目,支持在RISC-V核心基础硬件CH32V307评估板上使用带有msh Shell的RTOS快速原型。MCU:CH32V307VCT6,主频 144MHz,FLASH和RAM可配置l 全双工或半双工的同步或异步通信l NRZ 数据格式l 分数波特率发生器,最高 9Mbpsl 可编程数据长度l 可配置的停止位l 支持 LIN,IrDA 编码器,智能卡l 支持 DMAl 多种中断源首先,应安装 CH32V307 评估板的驱动程序,打开设备管理器查看USB 端口和外部接口已准备就绪。2. 软件配置2.1 安装MounRiver Studio环境搭建教程:https://blog.csdn.net/VOR234/article/details/1289324743. UASRT项目测试3.1 打开UASRT工程评估板说明及参考例程:https://www.wch.cn/downloads/CH32V307EVT_ZIP.html进入EXAM目录,就有对应的外设教程进入USART_HalfDuplex文件下,双击USART_HalfDuplex.wvproj,打开项目工程如下,main.c在user文件夹下3.2 CH307串口发送数据到Arduino实验修改CH307的main.c,杜邦线连接PB10(TX)--D2(RX);PB11(RX)--D3(TX)/********************************** (C) COPYRIGHT ******************************* * File Name : main.c * Author : WCH * Version : V1.0.0 * Date : 2021/06/06 * Description : Main program body. ********************************************************************************* * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * Attention: This software (modified or not) and binary are used for * microcontroller manufactured by Nanjing Qinheng Microelectronics. *******************************************************************************/ /* *@Note:采用CH307串口3与Arduino软串口收发通信 Hardware connection:PB10(TX)--D2(RX);PB11(RX)--D3(TX) */ #include "debug.h" /* Global typedef */ typedef enum { FAILED = 0, PASSED = !FAILED } TestStatus; /* Global define */ //#define RxSize1 (size(RxBuffer1)) #define TxSize1 (size(TxBuffer1)) #define RxSize1 256 #define size(a) (sizeof(a) / sizeof(*(a))) /* Global Variable */ u8 TxBuffer1[] = "abcd"; /* Send by UART3 */ u8 RxBuffer1[RxSize1] = {0}; /* USART3 Using */ u8 TxCnt1 = 0, RxCnt1 = 0; /********************************************************************* * @fn USARTx_CFG * * @brief Initializes the USART3 peripheral. * * @return none */ void USARTx_CFG(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; USART_InitTypeDef USART_InitStructure = {0}; // NVIC_InitTypeDef NVIC_InitStructure = { 0 }; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /* USART3 TX-->B.10 RX-->B.11 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; /* Only Configure TX Pin */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; /* Only Configure TX Pin */ GPIO_Init(GPIOB, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART3, &USART_InitStructure); USART_Cmd(USART3, ENABLE); // NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // NVIC_Init(&NVIC_InitStructure); // // USART_Cmd(USART3, ENABLE); } /********************************************************************* * @fn main * * @brief Main program. * * @return none */ int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); SystemCoreClockUpdate(); Delay_Init(); USART_Printf_Init(115200); printf("SystemClk:%d\r\n", SystemCoreClock); printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() ); printf("USART3 Arduino TEST\r\n"); USARTx_CFG(); /* USART3 INIT */ printf("USART3 INIT\r\n"); while(1) { /* CH307发送数据到Arduino */ while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET){ } for ( int var = 0; var < TxSize1-1; ++ var) { USART_SendData(USART3, TxBuffer1[var]); Delay_Ms(1); } printf("TxBuffer1:%s\r\n", TxBuffer1); Delay_Ms(1000); } }Arduino UNO 采用mixly编程代码如下#include <SoftwareSerial.h> SoftwareSerial mySerial(2,3); String item; volatile int number; void setup(){ mySerial.begin(9600); Serial.begin(9600); item = "hello123456"; number = 0; Serial.println(item); mySerial.println(item); } void loop(){ if (mySerial.available() > 0) { item = mySerial.readString(); Serial.println(String("item:") + String(item) + String("; number:") + String(number)); number++; } delay(1); }实验效果3.3 CH307串口接收数据Arduino实验接线保持不变修改CH307的main.c,杜邦线连接PB10(TX)--D2(RX);PB11(RX)--D3(TX) /********************************** (C) COPYRIGHT ******************************* * File Name : main.c * Author : WCH * Version : V1.0.0 * Date : 2021/06/06 * Description : Main program body. ********************************************************************************* * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * Attention: This software (modified or not) and binary are used for * microcontroller manufactured by Nanjing Qinheng Microelectronics. *******************************************************************************/ /* *@Note:采用CH307串口3与Arduino软串口收发通信 Hardware connection:PB10(TX)--D2(RX);PB11(RX)--D3(TX) */ #include "debug.h" /* Global typedef */ typedef enum { FAILED = 0, PASSED = !FAILED } TestStatus; /* Global define */ //#define RxSize1 (size(RxBuffer1)) #define TxSize1 (size(TxBuffer1)) #define RxSize1 256 #define size(a) (sizeof(a) / sizeof(*(a))) /* Global Variable */ u8 TxBuffer1[] = "abcd"; /* Send by UART3 */ u8 RxBuffer1[RxSize1] = {0}; /* USART3 Using */ u8 TxCnt1 = 0, RxCnt1 = 0; /********************************************************************* * @fn USARTx_CFG * * @brief Initializes the USART3 peripheral. * * @return none */ void USARTx_CFG(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; USART_InitTypeDef USART_InitStructure = {0}; // NVIC_InitTypeDef NVIC_InitStructure = { 0 }; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /* USART3 TX-->B.10 RX-->B.11 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; /* Only Configure TX Pin */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; /* Only Configure TX Pin */ GPIO_Init(GPIOB, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART3, &USART_InitStructure); USART_Cmd(USART3, ENABLE); // NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // NVIC_Init(&NVIC_InitStructure); // // USART_Cmd(USART3, ENABLE); } /********************************************************************* * @fn main * * @brief Main program. * * @return none */ int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); SystemCoreClockUpdate(); Delay_Init(); USART_Printf_Init(115200); printf("SystemClk:%d\r\n", SystemCoreClock); printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() ); printf("USART3 Arduino TEST\r\n"); USARTx_CFG(); /* USART3 INIT */ printf("USART3 INIT\r\n"); while(1) { /* CH307发送数据到Arduino */ // while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET){ // } // for ( int var = 0; var < TxSize1-1; ++ var) { // USART_SendData(USART3, TxBuffer1[var]); // Delay_Ms(1); // } // printf("TxBuffer1:%s\r\n", TxBuffer1); // Delay_Ms(1000); /* 从Arduino接收数据到CH307 */ RxBuffer1[RxCnt1++] = USART_ReceiveData(USART3); while(RxBuffer1[RxCnt1-1] == 'i'|| RxCnt1-1 != 0) { while(USART_GetFlagStatus(USART3, USART_FLAG_RXNE) == RESET){ } RxBuffer1[RxCnt1++] = USART_ReceiveData(USART3); if (RxBuffer1[RxCnt1-1] == '\t') { printf("RxBuffer1:%s\r\n", RxBuffer1); break; } } RxCnt1 = 0; for (int var = 0; var < RxSize1; ++var) { RxBuffer1[var] = 0; } Delay_Ms(1); } }Arduino UNO 采用mixly编程代码如下#include <SoftwareSerial.h> SoftwareSerial mySerial(2,3); String item; volatile int number; void setup(){ mySerial.begin(9600); Serial.begin(9600); item = "hello123456"; number = 0; Serial.println(item); mySerial.println(item); } void loop(){ mySerial.print(String("item:") + String(item) + String("; number:") + String(number) + String("; number:") + String(number) + String("\t")); number++; delay(1); }实验效果4. 小结🥳🥳🥳通过对这篇文章我们掌握了沁恒WCH CH32V307V-R1与Arduino的串口通讯,尝试与Arduino通讯做更加好玩的实验,进而丰富我们的生活。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境,🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣
1. 前言ADC 模块包含 2 个 12 位的逐次逼近型的模拟数字转换器,最高 14MHz 的输入时钟。支持 16 个外部通道和 2 个内部信号源采样源。可完成通道的单次转换、连续转换,通道间自动扫描模式、间断模式、外部触发模式、双重采样等功能。可以通过模拟看门狗功能监测通道电压是否在阈值范围内,本次实验采用一路ADC间隔均值采样,然后打印输出采样值和温度值,熟悉STM32开发用易上手配置。✨✨✨这是使用MounRiver Studio开发的项目,支持在RISC-V核心基础硬件CH32V307评估板上使用带有msh Shell的RTOS快速原型。MCU:CH32V307VCT6,主频 144MHz,FLASH和RAM可配置l 12 位分辨率l 支持 16 个外部通道和 2 个内部信号源采样l 多通道的多种采样转换方式:单次、连续、扫描、触发、间断等l 数据对齐模式:左对齐、右对齐l 采样时间可按通道分别编程l 规则转换和注入转换均支持外部触发l 模拟看门狗监测通道电压,自校准功能l 双重模式l ADC 通道输入范围:0≤VIN≤VDDAl 输入增益可调,可实现小信号放大采样首先,应安装 CH32V307 评估板的驱动程序,打开设备管理器查看USB 端口和外部接口已准备就绪。2. 软件配置2.1 安装MounRiver Studio环境搭建教程:https://blog.csdn.net/VOR234/article/details/1289324743. ADC项目测试3.1 打开ADC工程评估板说明及参考例程:https://www.wch.cn/downloads/CH32V307EVT_ZIP.html进入EXAM目录,就有对应的外设教程进入DInternal_Temperature文件下,双击Internal_Temperature.wvproj,打开项目工程如下,main.c在user文件夹下main.c,参考电压是3.3V/********************************** (C) COPYRIGHT ******************************* * File Name : main.c * Author : WCH * Version : V1.0.0 * Date : 2021/06/06 * Description : Main program body. ********************************************************************************* * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * Attention: This software (modified or not) and binary are used for * microcontroller manufactured by Nanjing Qinheng Microelectronics. *******************************************************************************/ /* *@Note Internal temperature sensor routine: Through the ADC channel 16(PA2), the output voltage value and temperature value of the internal temperature sensor are collected. */ #include "debug.h" /* Global Variable */ s16 Calibrattion_Val = 0; /********************************************************************* * @fn ADC_Function_Init * * @brief Initializes ADC collection. * * @return none */ void ADC_Function_Init(void) { ADC_InitTypeDef ADC_InitStructure={0}; GPIO_InitTypeDef GPIO_InitStructure={0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE ); RCC_ADCCLKConfig(RCC_PCLK2_Div8); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_DeInit(ADC1); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_Cmd(ADC1, ENABLE); ADC_BufferCmd(ADC1, DISABLE); //disable buffer ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); Calibrattion_Val = Get_CalibrationValue(ADC1); ADC_BufferCmd(ADC1, ENABLE); //enable buffer ADC_TempSensorVrefintCmd(ENABLE); } /********************************************************************* * @fn Get_ADC_Val * * @brief Returns ADCx conversion result data. * * @param ch - ADC channel. * ADC_Channel_0 - ADC Channel0 selected. * ADC_Channel_1 - ADC Channel1 selected. * ADC_Channel_2 - ADC Channel2 selected. * ADC_Channel_3 - ADC Channel3 selected. * ADC_Channel_4 - ADC Channel4 selected. * ADC_Channel_5 - ADC Channel5 selected. * ADC_Channel_6 - ADC Channel6 selected. * ADC_Channel_7 - ADC Channel7 selected. * ADC_Channel_8 - ADC Channel8 selected. * ADC_Channel_9 - ADC Channel9 selected. * ADC_Channel_10 - ADC Channel10 selected. * ADC_Channel_11 - ADC Channel11 selected. * ADC_Channel_12 - ADC Channel12 selected. * ADC_Channel_13 - ADC Channel13 selected. * ADC_Channel_14 - ADC Channel14 selected. * ADC_Channel_15 - ADC Channel15 selected. * ADC_Channel_16 - ADC Channel16 selected. * ADC_Channel_17 - ADC Channel17 selected. * * @return none */ u16 Get_ADC_Val(u8 ch) { u16 val; ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC )); val = ADC_GetConversionValue(ADC1); return val; } /********************************************************************* * @fn Get_ADC_Average * * @brief Returns ADCx conversion result average data. * * @param ch - ADC channel. * ADC_Channel_0 - ADC Channel0 selected. * ADC_Channel_1 - ADC Channel1 selected. * ADC_Channel_2 - ADC Channel2 selected. * ADC_Channel_3 - ADC Channel3 selected. * ADC_Channel_4 - ADC Channel4 selected. * ADC_Channel_5 - ADC Channel5 selected. * ADC_Channel_6 - ADC Channel6 selected. * ADC_Channel_7 - ADC Channel7 selected. * ADC_Channel_8 - ADC Channel8 selected. * ADC_Channel_9 - ADC Channel9 selected. * ADC_Channel_10 - ADC Channel10 selected. * ADC_Channel_11 - ADC Channel11 selected. * ADC_Channel_12 - ADC Channel12 selected. * ADC_Channel_13 - ADC Channel13 selected. * ADC_Channel_14 - ADC Channel14 selected. * ADC_Channel_15 - ADC Channel15 selected. * ADC_Channel_16 - ADC Channel16 selected. * ADC_Channel_17 - ADC Channel17 selected. * * @return val - The Data conversion value. */ u16 Get_ADC_Average(u8 ch,u8 times) { u32 temp_val=0; u8 t; u16 val; for(t=0;t<times;t++) { temp_val+=Get_ADC_Val(ch); Delay_Ms(5); } val = temp_val/times; return val; } /********************************************************************* * @fn Get_ConversionVal * * @brief Get Conversion Value. * * @param val - Sampling value * * @return val+Calibrattion_Val - Conversion Value. */ u16 Get_ConversionVal(s16 val) { if((val+Calibrattion_Val)<0) return 0; if((Calibrattion_Val+val)>4095||val==4095) return 4095; return (val+Calibrattion_Val); } /********************************************************************* * @fn main * * @brief Main program. * * @return none */ int main(void) { u16 ADC_val; s32 val_mv; SystemCoreClockUpdate(); Delay_Init(); USART_Printf_Init(115200); printf("SystemClk:%d\r\n",SystemCoreClock); printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() ); ADC_Function_Init(); printf("CalibrattionValue:%d\n", Calibrattion_Val); while(1) { ADC_val = Get_ADC_Average( ADC_Channel_TempSensor, 10 ); Delay_Ms(500); ADC_val = Get_ConversionVal(ADC_val); printf( "ADC-Val:%04d\r\n", ADC_val); val_mv = (ADC_val*3300/4096); printf("mv-T-%d,%0d\n",val_mv ,TempSensor_Volt_To_Temper(val_mv)); Delay_Ms(2); } }3.2 编译项目开发板数据线连接电脑就可以开始连接调试🛹🛹🛹,首先开始编译,编译成功如下然后下载,下载成功如下4. 下载验证4.1 接线根据程序设计调试,可以用手指触摸芯片,即可输出相关温度变化4.2 演示效果代码下载后验证,点击串口调试器,设置串口参数确认。复位运行成功如下打印温度变化,从12度到15度SystemClk:96000000 ChipID:30700518 CalibrattionValue:9 ADC-Val:1786 mv-T-1438,12 ADC-Val:1781 mv-T-1434,13 ADC-Val:1777 mv-T-1431,13 ADC-Val:1775 mv-T-1430,13 ADC-Val:1773 mv-T-1428,14 ADC-Val:1772 mv-T-1427,14 ADC-Val:1771 mv-T-1426,14 ADC-Val:1770 mv-T-1426,14 ADC-Val:1768 mv-T-1424,15 ADC-Val:1768 mv-T-1424,15 ADC-Val:1769 mv-T-1425,15 ADC-Val:1768 mv-T-1424,15 ADC-Val:1767 mv-T-1423,15 ADC-Val:1767 mv-T-1423,15 ADC-Val:17675. 小结🥳🥳🥳通过对这篇文章我们掌握了沁恒WCH CH32V307V-R1开发板读取板载温度实验,这样就可以设置适当工作环境防寒暑,确保设备正常接下来会有许多有趣的实验,尝试与Arduino通讯做更加好玩的实验,进而丰富我们的生活。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境,🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣
1. 前言作为全新一代开源精简指令集,RISC-V在嵌入式领域备受关注,沁恒微电子基于自研RISC-V架构青稞微处理器,推出高性能、无线型、低功耗等多个系列的RISC-V MCU产品。采用RISC-V架构的MCU已获得越来越多工程师的青睐,并应用到实际产品开发中,RISC-V生态正逐渐起步。🌻🌻🌻“RISC-VMCU创新应用大赛”以嵌入式应用为导向,以培养RISC-V MCU产业人才为目标,打造RISC-V MCU创新应用平台,助力RISC-V在国内更好的扎根落地,并在应用中快速发展壮大。🌼🌼🌼近年来,RISC-V生态获得了空前的繁荣发展,国内外众多科技公司纷纷下场布局、行业应用层出不穷,搭载RISC-V内核的MCU也逐渐走入了工程师的日常开发工作中。 工欲善其事必先利其器,要想实现基于RISC-V MCU的项目开发,与之配套的集成开发环境必不可少。目前市场上可供选择的RISC-V MCU开发工具已初具规模,由MounRiver团队打造的MounRiver® Studio(MRS)便是其中一种,熟悉STM32开发用易上手配置。✨✨✨这是使用MounRiver Studio开发的项目,支持在RISC-V核心基础硬件CH32V307评估板上使用带有msh Shell的RTOS快速原型。MCU:CH32V307VCT6,主频 144MHz,FLASH和RAM可配置LED:2个,用户 LEDs, LED1(blue),LED2(red)。按键:3个,Reset, User 和 Download。USB:2个,Tpye-C。网口:1个,内置 10M PHY。板载 WCH-Link 下载调试工具。首先,应安装 CH32V307 评估板的驱动程序,打开设备管理器查看USB 端口和外部接口已准备就绪。CH32V307数据手册:https://www.wch.cn/downloads/CH32V20x_30xDS0_PDF.htmlCH32V307参考手册:https://www.wch.cn/downloads/CH32FV2x_V3xRM_PDF.html评估板说明及参考例程:https://www.wch.cn/downloads/CH32V307EVT_ZIP.htmlCH343SER.ZIP串口地址2. 软件配置2.1 安装MounRiver StudioMRS是一款针对嵌入式项目(RISC-V/ARM)的集成开发环境,提供了包括编辑器、C编译器、宏汇编、链接器、库管理、仿真调试器和下载器等在内的完整开发资源,工具链方面增加了对WCH RISC-V系列单片机中断硬件自动保存上下文功能的支持。在包含通用RISC-V/ARM项目开发功能的基础上,MRS还集成了跨内核单片机工程转换接口,实现ARM内核项目到RISC-V开发环境的一键迁移。除此之外,该集成开发环境还有如下特点:●支持RISC-V/ARM两种内核芯片项目开发(编译、烧录、调试)●支持根据工程对应的芯片内核自动切换RISC-V或ARM工具链●支持Harmony LiteOS-M、RT-Thread、FreeRTOS等嵌入式操作系统开发●支持引用外部自定义工具链●支持轻量化的C库函数printf●支持32和64位RISC-V 指令集架构,I、M、A、C、F等指令集扩展●内置WCH、GD等多个厂家系列芯片工程模板,支持多种主流调试下载器●支持双击项目文件打开、导入工程●支持自由创建、导入、导出单片机工程模板●多线程构建,最大程度减少编译时间●支持软件中英文、深浅色主题界面快速切换●支持链接脚本文件可视化修改●支持文件版本管理,一键追溯历史版本●支持单片机在线编程ISP(In-System Programming)●支持汇编、C和C++语言(均无代码大小限制)●支持用户意见在线反馈功能●支持在线自动检测升级,本地补丁包离线升级●免费下载使用MRS最新V1.51版本安装包获取方式:www.mounriver.com 。【欢迎页】MRS提供了工程操作快捷入口,右侧展示软件整体介绍以及快速使用贴士。【主界面】MRS基于Eclipse界面风格,针对嵌入式开发,对主菜单、工具栏、页面排版进行了简化与定制。【工具栏】MRS重新设计了工具栏按钮图标,增加KEIL工程导入、链接脚本文件编辑、全局配置、工程配置、命令行工具、重新编译等功能入口。【内置芯片工程】MRS内置WCH、GD等厂家RISC-V、ARM等系列MCU的芯片工程模板,同时支持Harmony LiteOS-M、RT-Thread、FreeRTOS等嵌入式操作系统开发。【工具链】MRS可根据当前工程对应的芯片内核,自动切换RISC-V/ARM工具链,自动加载编译配置。【调试器】MRS支持GD-Link、JLink、WCH-Link等在线仿真调试器,可自由进行切换。【代码下载】MRS支持GD、WCH等厂家RISC-V/ARM系列芯片工程的代码下载。【代码调试】MRS支持GD、WCH等厂家RISC-V/ARM系列芯片工程的代码调试,支持单步执行、重新执行、暂停、全速执行等操作。3. 点灯项目测试3.1 打开点灯工程评估板说明及参考例程:https://www.wch.cn/downloads/CH32V307EVT_ZIP.html进入EXAM目录,就有对应的外设教程进入GPIO_Toggle文件下,双击GPIO_Toggle.wvproj,打开项目工程如下,main.c在user文件夹下main.c/********************************** (C) COPYRIGHT ******************************* * File Name : main.c * Author : WCH * Version : V1.0.0 * Date : 2021/06/06 * Description : Main program body. ********************************************************************************* * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * Attention: This software (modified or not) and binary are used for * microcontroller manufactured by Nanjing Qinheng Microelectronics. *******************************************************************************/ /* *@Note GPIO routine: PA0 push-pull output. */ #include "debug.h" /* Global define */ /* Global Variable */ /********************************************************************* * @fn GPIO_Toggle_INIT * * @brief Initializes GPIOA.0 * * @return none */ void GPIO_Toggle_INIT(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } /********************************************************************* * @fn main * * @brief Main program. * * @return none */ int main(void) { u8 i = 0; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); SystemCoreClockUpdate(); Delay_Init(); USART_Printf_Init(115200); printf("SystemClk:%d\r\n", SystemCoreClock); printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() ); printf("GPIO Toggle TEST\r\n"); GPIO_Toggle_INIT(); while(1) { Delay_Ms(250); GPIO_WriteBit(GPIOA, GPIO_Pin_0, (i == 0) ? (i = Bit_SET) : (i = Bit_RESET)); } }3.2 编译项目开发板数据线连接电脑就可以开始连接调试🛹🛹🛹,首先开始编译,编译成功如下然后下载,下载成功如下4. 下载验证4.1 接线根据原理图需要用杜邦线把LED1与PA0连接起来,即可点灯4.2 演示效果代码下载后验证,点击串口调试器,设置串口参数确认。复位运行成功如下打印SystemClk:96000000 ChipID:30700518 GPIO Toggle TEST5. 小结🥳🥳🥳通过对这篇文章我们掌握了沁恒WCH CH32V307V-R1在MounRiver Studio上环境配置教程,接下来会有许多有趣的实验,尝试与Arduino通讯做更加好玩的实验,进而丰富我们的生活。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境,🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣
1. 前言这是使用RT-thread IDE开发的项目,支持在RISC-V核心基础硬件CH32V307评估板上使用带有msh Shell的RTOS快速原型。MCU:CH32V307VCT6,主频 144MHz,FLASH和RAM可配置LED:2个,用户 LEDs, LED1(blue),LED2(red)。按键:3个,Reset, User 和 Download。USB:2个,Tpye-C。网口:1个,内置 10M PHY。板载 WCH-Link 下载调试工具。首先,应安装 CH32V307 评估板的驱动程序,打开设备管理器查看USB 端口和外部接口已准备就绪。CH32V307数据手册:https://www.wch.cn/downloads/CH32V20x_30xDS0_PDF.htmlCH32V307参考手册:https://www.wch.cn/downloads/CH32FV2x_V3xRM_PDF.html评估板说明及参考例程:https://www.wch.cn/downloads/CH32V307EVT_ZIP.htmlCH343SER.ZIP串口地址2. 软件配置2.1 安装RT-Thread Studio本次程序开发采用RT-Thread Studio集成开发环境,安装RT-Thread Studio。🥳🥳🥳官网地址:https://www.rt-thread.org/studio.html安装完成如下2.2 RT-Thread Studio配置沁恒WCH CH32V307V-R1进入RT-Thread Studio然后登陆,显示如下点击SDK Manage,选择安装CH307V-R1开发包和下载调试器根据安装日志,可见相关包已经安装成功,退出SDK管理器3 项目搭建3.1 新建RT-Thread项目点击文件,依次新建RT-Thread项目选择基于开发板,项目工程名称Blinky,查看对应开发板,点击完成展开项目,点击applications下的main.cmain.c文件/********************************** (C) COPYRIGHT ******************************* * File Name : main.c * Author : WCH * Version : V1.0.0 * Date : 2021/06/06 * Description : Main program body. * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * SPDX-License-Identifier: Apache-2.0 *******************************************************************************/ #include "ch32v30x.h" #include <rtthread.h> #include <rthw.h> #include "drivers/pin.h" #include <board.h> /* Global typedef */ /* Global define */ #define LED0_PIN 35 //PC3 /* Global Variable */ /********************************************************************* * @fn main * * @brief Main program. * * @return none */ int main(void) { rt_kprintf("MCU: CH32V307\n"); rt_kprintf("SysClk: %dHz\n",SystemCoreClock); rt_kprintf("www.wch.cn\n"); LED1_BLINK_INIT(); GPIO_ResetBits(GPIOA,GPIO_Pin_0); while(1) { GPIO_SetBits(GPIOA,GPIO_Pin_0); rt_thread_mdelay(500); GPIO_ResetBits(GPIOA,GPIO_Pin_0); rt_thread_mdelay(500); } } /********************************************************************* * @fn led * * @brief gpio operation by pins driver. * * @return none */ int led(void) { rt_uint8_t count; rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); rt_kprintf("led_SP:%08x\r\n",__get_SP()); for(count = 0 ; count < 10 ;count++) { rt_pin_write(LED0_PIN, PIN_LOW); rt_kprintf("led on, count : %d\r\n", count); rt_thread_mdelay(500); rt_pin_write(LED0_PIN, PIN_HIGH); rt_kprintf("led off\r\n"); rt_thread_mdelay(500); } return 0; } MSH_CMD_EXPORT(led, led sample by using I/O drivers);3.2 编译项目开发板数据线连接电脑就可以开始连接调试🛹🛹🛹然后下载,设置下载方式,选择rtthread,bin文件(在Debug文件夹下)有时需要更新Execute,更新成功再次点击下载Execute,下载成功4. 下载验证4.1 接线根据原理图需要用杜邦线吧LED1与PA0连接起来,即可点灯4.2 演示效果代码下载后验证,输入led运行成功。5. 小结🥳🥳🥳通过对这篇文章我们掌握了沁恒WCH CH32V307V-R1在RT-Thread Studio上环境配置教程,接下来会有许多有趣的实验,尝试与Arduino通讯做更加好玩的实验,进而丰富我们的生活。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境,🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣
1. 前言大夏龙雀科技DX-BT24&BT24-S&BT24-PA蓝牙模块,拥有5.1蓝牙协议,模块内置标准串口协议。可以通过模块串口跟移动端、PC端、主设备端进行数据交互,并可以使用AT命令对模块参数进行配置和修改。从而使设备以极低的成本、极快的速度加入物联网,让设备更方便、智能。官网地址BT24-PA蓝牙模块资料视频地址1.1.串口基本参数模块串口默认参数: 9600bps/8/n/1(波特率/数据位/无校验/停止位)模块支持软件流控(注:DX-BT24-PA不支持)模块BLE UUID: SERVICE UUID: FFEONOTIFY/WRITE UUID: FFE1WRITE UUID: FFE21.2.AT命令模式和透传模式AT命令模式:模块在未被其他设备连接上的情况下,即为命令模式,可以响应命令。透传模式:模块被其他设备连接上后即为透传模式,此时可以开始传输数据。1.3.模块数据吞吐量备注:上表格中数据仅供参考,本模块支持MTU值最大为253,数据吞吐量跟手机蓝牙的MTU值和连接间隔有关,数据以实际为准。2. 接线2.1 模块线序定义TTL串口调试器DX-BT24GNDGND5V5VRXDTXDTXDRXD串口TTL连接typeC数据线,连接电脑就可以开始连接调试2.2 相关AT命令详解2.2.1 命令格式说明AT+Command<param1, param2,param3> <CR><CF>所有的指令以AT开头,<CR><LF>结束,在本文档中表现命令和响应的表格中,省略了<CR><LF>,仅显示命令和响应。所有AT命令字符都为大写。<>内为可选内容,如果命令中有多个参数,以逗号“,”隔开,实际命令中不包含尖括号。<CR>为回车字符\r,十六进制为OXOD。<LF>为换行字符\n,十六进制为OXOA。指令执行成功,返回相应命令以OK结束,失败返回EEROR=<>,“<>”内容为对应错误码(请参考5.7)。2.2.2 回应格式说明+lndication<=param1, param2, param3><CR><CF>回应指令以加号“+”开头,<CR><CF>结束等于“=”后面为回应参数如果回应参数中有多个参数,会以逗号“,”隔开2.2.3 AT命令举例说明举例:修改蓝牙设备名称为1234发送:AT+NAME1234返回:+NAME=1234OK3. AT命令详解3.1 基础指令基本指令包含:测试、版本号、蓝牙状态参数、恢复出厂设置、重启等14条指令,表粗一般经常使用序号功能指令响应说明1测试指令ATOK用于测试串口2查询版本号AT+VERSION+VERSION= <version><version >软件版本号,依据不同的模块与定制需求版本会有区别3查询MAC地址AT+LADDR+LADDR= <laddr><laddr>蓝牙MAC地址码4查询蓝牙名AT+NAME+NAME=<name><name>蓝牙名,最长为28个字节设置蓝牙名AT+NAME<name>+NAME=<name> OK默认名称:BT24/BT24-S/BT24-PA,设置完该指令后需重启生效。5查询参数AT+NAMAC+NAMAC=<param><param>参数,关闭:0设置参数AT+NAMAC<param>+NAMAC=<param> OK打开6位MAC后缀:1;打开3位MAC后缀:26查询串口停止位AT+STOP+STOP=<param><param>序号0:1停止位设置串口停止位AT+STOP<param>+STOP= <param> OK1:2停止位;默认值:07查询串口校验位AT+PARI+PARI= <param><param>序号0:无校验设置串口校验位AT+PARI<param>+PARI= <param> OK1︰奇校验;2:偶校验;默认值:08查询波特率AT+BAUD+BAUD=<baud><baud>波特率对应序号1:2400;2:4800;3:9600;4: 19200设置波特率AT+BAUD<baud>+BAUD= <baud> OK5:38400;6:57600;7:115200默认值:3(9600)9查询流控状态AT+FLOW+FLOW =<param><param>序号0:为关闭流控设置流控状态AT+FLOW<param>OK1:为打开流控;默认值:010查询透传模式AT+TRANSPORT+TRANSPORT=<param><param>序号0:关闭透传设置透传模式AT+TRANSPORT<param >+TRANSPORT= <param> OK1:打开透传;默认值:111断开连接AT+DISC12查询蓝牙设备类型AT+TYPE+TYPE=<param><param>参数0x0000:未指定类型;0x0040:电话本类型;0x0080:笔记本电脑类型设置蓝牙设备类型AT+TYPE<param>+TYPE=<param> OK更多类型请查找蓝牙类型表;默认值:0x000013软件重启AT+RESET+RESETOK Power On14恢复出厂设置AT+DEFAULT+DEFAULTOK注意:设置完4/6/7/8/12指令后需重启生效;5指令:设置为打开6位MAC后缀则蓝牙有效名称最长为16个字节,设置为打开3位MAC后缀则蓝牙有效名称最长为22个字节。假设地址码为:112233aabbcc,设备蓝牙名称为BT24。打开3位MAC后缀,即设备蓝牙名称为:BT24aabbcc,打开6位MAC后缀,即设备蓝牙名称为:BT24112233aabbcc,设置完成后需重启才生效;9指令:中DX-BT24-PA不支持此指令;10指令: 如果设置关闭透传后,模块被连接上可以继续响应AT指令,如连接上后再发送打开透传命令,响应完之后,则进入透传模式,然后不再响应命令。此指令掉电保存;11指令:此指令只能在透传模式下使用,且只能由串口端发送有效,手机端发送无效。3.2 AT指令测试打开串口调试工具,连接端口号,打开串口,设置9600波特率,勾选加回车换行,右侧设置指令,并点击测试。此时蓝牙正常连接,下面开始测试,依次输入测试设备AT查看设备名称,默认BT24AT+NAME修改设备名称为23456VORAT+NAME23456VOR恢复出厂设置AT+DEFAULT查看设备名称,默认BT24AT+NAME效果如下3.3 手机测试安装DX-SMART软件,app,IOS下面演示APP安卓端,点击透传,搜索BLE,连接BT24蓝牙,设置文本123456内容,手机端点击发送电脑端接收手机端数据1234564. 小结🥳🥳🥳通过对这篇文章我们掌握了DX-BT24蓝牙模块-AT命令与手机透传教程,接下来会有许多有趣的实验,尝试与Arduino通讯做更加好玩的实验,进而丰富我们的生活。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境,🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣
1. 前言最近使用esp8266进行远程遥控时, 但是在驱动舵机servo库的过程中出现了esp8266 自动重启问题, 具体表现为串口助手不断输出错误信息,如下。--------------- CUT HERE FOR EXCEPTION DECODER --------------- Soft WDT reset >>>stack>>> ctx: cont sp: 3ffffce0 end: 3fffffc0 offset: 01a0 3ffffe80: 00000002 40105a43 00000001 60000200 3ffffe90: 00000002 4000410f 00001001 00000205 3ffffea0: 3fffc718 40004a3c 000003fb 000000012. 分析问题2.1 长时间没有喂狗显然是由于长时间没有喂狗导致的看门狗复位, 原因是在loop函数中长时间执行函数,没有延时函数delay,2.2 delayMicroseconds 函数触发注意的是 delay 函数和 delayMicroseconds 函数之间的区别, 长时间执行 delay 函数不会出现复位, 但是长时间执行 delayMicroseconds 函数则会导致复位delayMicroseconds(1000); servo.write(90);//舵机驱动自带delayMicroseconds操作由于远程控制中含有Ticker定时器与`delayMicroseconds``冲突Ticker是ESP32 arduino的自带库,可以设置以固定时间间隔反复执行某个任务,特别适合以固定频率从传感器收集数据。官方解释:Arduino Ticker 库允许您轻松创建 Ticker 回调,这些回调可以在预定的时间间隔内调用函数。您可以更改回调的重复次数,如果重复为 0,则代码以无限模式运行。工作方式类似于“线程”,必要时将运行辅助函数。该库不使用硬件计时器的中断,并使用micros() / millis()函数。您(实际上)不受股票代码数量的限制。3. 解决问题3.1 解决长时间没有喂狗所以添加了喂狗函数或者delay函数,如下ESP.wdtFeed(); delay(100);//延时100ms3.2 解决delayMicroseconds 函数触发解决delayMicroseconds 函数问题关键在于替代方法,delay 函数内部有喂狗机制, 而 delayMicroseconds 没有这个机制,自己写一个servo驱动函数,具体可见Arduino与SG90舵机握手/* int servopin 是端口号 int myangle 目标位置0~180度,此函数不精确,只有4分度-90 -45 45 90 int loops 循环次数,响应时间 */ void servopulse(int servopin, int myangle, int loops) /*定义一个脉冲函数,用来模拟方式产生PWM值*/ { for (int i = 0; i <= loops; i++) //给予舵机足够的时间让它转到指定角度 { int pulsewidth = (myangle * 11) + 500; //将角度转化为500-2480 的脉宽值 digitalWrite(servopin, HIGH); //将舵机接口电平置高 delay(pulsewidth / 1000); //延时脉宽值的微秒数 digitalWrite(servopin, LOW); //将舵机接口电平置低 delay(20 - pulsewidth / 1000); //延时周期内剩余时间 } delay(1); }3.3 设置定义域采用舵机的attach函数定义时,设定范围就可解决servo_R.attach(D5,500,2500);4. 小结🥳🥳🥳通过对这篇文章我们掌握了关于eps8266自动重启 Soft WDT reset问题解决,接下来会有许多有趣的实验,尝试与Arduino通讯做语音小车,进而丰富我们的生活。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境,🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣
1. 前言最近发现 自己的Chrome 浏览器自带的谷歌翻译用不了怎么办,网上查找一番发现是 DNS 解析的问题,并且很多人遇到这种情况,于是随手写个简单教程~1.1 问题模拟我用bing搜索《深度学习》,然后点开IBM网站,为啥翻译用不了?1.2 分析底层逻辑Chrome 浏览器自带的谷歌翻译,调用的 API 接口域名为:translate.googleapis.com而之所以近期突然无法使用了,是因为谷歌关闭了国内的谷歌翻译网页版 translate.google.cn ,因此连带着导致谷歌翻译 API 接口域名的解析也从国内 IP 改到了不可用的谷歌国外 IP,而谷歌国内服务器依然可用,所以只需手动在 Hosts 文件中将域名指向谷歌国内服务器 IP 即可。注意,目前已经没有任何国内可直接访问的 谷歌翻译在线网页版 了,改 Hosts 也不行! 谷歌国内 IP 哪里找?谷歌的一些非敏感网络服务一直都托管在国内服务器,都是通用的,因此随便找个谷歌国内域名,比如在 CMD 中 ping google.cn得到的 IP 就能拿来指向谷歌翻译 API 接口域名使用(如果该 IP 不可用,也可以找个在线全国 Ping 的网站来获得其他更多 IP)。可以直接使用我找好的这些国内 IP(任选其一):上海/电信: 180.163.150.34 180.163.151.34 180.163.151.162 180.163.150.162 180.163.150.33 上海/移动: 120.253.253.226 120.253.253.98 120.253.250.226 120.253.255.162 120.253.253.34 120.253.255.98 120.253.253.162 120.253.255.34 上海/Google数据中心/电信: 203.208.40.98 203.208.41.98 203.208.41.66 203.208.41.34 203.208.40.66 203.208.41.97 203.208.40.97 203.208.40.65 203.208.40.34 北京/电信: 220.181.174.226 220.181.174.34 220.181.174.98 220.181.174.162 220.181.174.33 203.208.50.162 北京/Google数据中心/电信: 203.208.43.66 203.208.39.194 203.208.50.66 203.208.43.98 203.208.50.34 203.208.39.226 北京/联通: 114.250.64.34 114.250.70.34 114.250.63.34 114.250.66.34 114.250.65.34 广州/电信: 113.108.239.226 58.63.233.98 113.108.239.162 广州/移动: 120.241.147.162 120.232.181.162 广州/联通: 58.254.137.226 58.254.137.162提示:以上 IP 并不保证最新可用,因此使用之前,建议在 CMD 中 Ping IP 确保可用。上面加粗的五个IP我测试了一下Microsoft Windows [版本 10.0.22000.1042] (c) Microsoft Corporation。保留所有权利。 C:\Users\Asus>ping 120.253.255.162 正在 Ping 120.253.255.162 具有 32 字节的数据: 来自 120.253.255.162 的回复: 字节=32 时间=29ms TTL=115 来自 120.253.255.162 的回复: 字节=32 时间=30ms TTL=115 来自 120.253.255.162 的回复: 字节=32 时间=29ms TTL=115 来自 120.253.255.162 的回复: 字节=32 时间=30ms TTL=115 120.253.255.162 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 29ms,最长 = 30ms,平均 = 29ms C:\Users\Asus>ping 58.254.137.162 正在 Ping 58.254.137.162 具有 32 字节的数据: 来自 58.254.137.162 的回复: 字节=32 时间=30ms TTL=108 来自 58.254.137.162 的回复: 字节=32 时间=31ms TTL=108 来自 58.254.137.162 的回复: 字节=32 时间=30ms TTL=108 来自 58.254.137.162 的回复: 字节=32 时间=30ms TTL=108 58.254.137.162 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 30ms,最长 = 31ms,平均 = 30ms C:\Users\Asus>ping 203.208.39.194 正在 Ping 203.208.39.194 具有 32 字节的数据: 来自 203.208.39.194 的回复: 字节=32 时间=36ms TTL=112 来自 203.208.39.194 的回复: 字节=32 时间=37ms TTL=112 来自 203.208.39.194 的回复: 字节=32 时间=36ms TTL=112 来自 203.208.39.194 的回复: 字节=32 时间=36ms TTL=112 203.208.39.194 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 36ms,最长 = 37ms,平均 = 36ms C:\Users\Asus>ping 203.208.41.34 正在 Ping 203.208.41.34 具有 32 字节的数据: 来自 203.208.41.34 的回复: 字节=32 时间=23ms TTL=110 来自 203.208.41.34 的回复: 字节=32 时间=22ms TTL=110 来自 203.208.41.34 的回复: 字节=32 时间=22ms TTL=110 来自 203.208.41.34 的回复: 字节=32 时间=84ms TTL=110 203.208.41.34 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 22ms,最长 = 84ms,平均 = 37ms C:\Users\Asus>ping 203.208.40.98 正在 Ping 203.208.40.98 具有 32 字节的数据: 来自 203.208.40.98 的回复: 字节=32 时间=27ms TTL=111 来自 203.208.40.98 的回复: 字节=32 时间=28ms TTL=111 来自 203.208.40.98 的回复: 字节=32 时间=26ms TTL=111 来自 203.208.40.98 的回复: 字节=32 时间=26ms TTL=111 203.208.40.98 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 26ms,最长 = 28ms,平均 = 26ms以上IP都没有丢失,效果最好的是:上海/Google数据中心/电信:203.208.40.98下面就用这个IP测试2. 解决办法注意:这些 IP 只能指向那些国内本来就能访问的谷歌服务,指向其他谷歌域名是无法使用的。怎么添加 Hosts?2.1 实操需要管理员权限打开编辑 Hosts 文件(修改该文件)。Windows 系统位置:C:\Windows\System32\drivers\etc\hostsLinux / MacOS系统位置:/etc/hosts以Windows为例在文件中添加一行保存即可,格式示例(自己根据需求修改前面的 IP 地址):203.208.40.98 translate.googleapis.com该示例 IP 并不保证最新可用,因此添加之前,建议在 CMD 中 Ping IP 确保可用。保存后,记得重启浏览器才能生效,如果还不行则尝试清空 DNS 缓存后(cmd 中执行 ipconfig /flushdns)再重启浏览器。2.2 验证效果3. 总结非常感谢各位大佬的支持,特别是西柚秀,到这里Chrome 浏览器自带谷歌翻译用不了就算完成了。大家快去探索翻译的乐趣吧!🥳🥳🥳我们实现对外部世界进行感知🎏,充分认识这个有机与无机的环境🌻,科学地合理地进行创作和发挥效益🛹,然后为人类社会发展贡献一点微薄之力。🏃♂️🏃♂️🏃♂️
1. 前言结合前期【经典Ubuntu20.04版本U盘安装双系统教程】,后续上网以及输入法的设置,还安装火狐浏览器H5 FLASH插件播放视频。2. 连接无线网2.1 wifi连接1. 网络连接配置在右上角靠近声音符号左边2. 点击为wifi符号,然后输入对应的账号和密码就好!3. 然后就可以上网啦!去B站看看!2.2 有线连接这个直接插网线就显示一切正确!大家愉快的上网吧!3. 中英文输入法切换采用中文界面,一般默认输入法为中文。shift键可以换为英文win+键实现快速切换如果想安装搜狗输入法,下面给出参考:Ubuntu安装搜狗输入法4. Firefox浏览器视频4.1 分析视频播放有的时候在Ubuntu操作系统中使用Firefox浏览器无法播放B站(bilibili)视频,在其它视频网站也无法播放,提示需要安装flash插件,不想安装flash,当然,你也可以按照Ubuntu 18.04下firefox浏览器安装flash的方法操作。4.2 解决办法不安装flash插件也可以使Firefox浏览器播放HTML5视频,但是需要安装一些软件。只需要在Ubuntu系统终端中输入下面命令:sudo apt-get install ubuntu-restricted-extras下面是读取日志vor@vor:~$ sudo apt-get install ubuntu-restricted-extras [sudo] vor 的密码: 正在读取软件包列表... 完成 正在分析软件包的依赖关系树 正在读取状态信息... 完成 将会同时安装下列软件: chromium-codecs-ffmpeg-extra gstreamer1.0-libav gstreamer1.0-plugins-ugly gstreamer1.0-vaapi i965-va-driver intel-media-va-driver liba52-0.7.4 libaacs0 libaom0 libaribb24-0 libass9 libavcodec-extra libavcodec-extra58 libavfilter7 libavformat58 libavutil56 libbdplus0 libbluray2 libbs2b0 libchromaprint1 libcodec2-0.9 libdvdnav4 libdvdread7 libfftw3-double3 libflite1 libgme0 libgsm1 libgstreamer-plugins-bad1.0-0 libigdgmm11 liblilv-0-0 libmpeg2-4 libmysofa1 libnorm1 libopencore-amrnb0 libopencore-amrwb0 libopenmpt0 libpgm-5.2-0 libpostproc55 librubberband2 libserd-0-0 libshine3 libsidplay1v5 libsnappy1v5 libsord-0-0 libsratom-0-0 libssh-gcrypt-4 libswresample3 libswscale5 libva-drm2 libva-wayland2 libva-x11-2 libva2 libvdpau1 libvidstab1.1 libvo-amrwbenc0 libx264-155 libx265-179 libxvidcore4 libzmq5 libzvbi-common libzvbi0 mesa-va-drivers mesa-vdpau-drivers ocl-icd-libopencl1 ubuntu-restricted-addons unrar va-driver-all vdpau-driver-all 建议安装: gstreamer1.0-vaapi-doc i965-va-driver-shaders libbluray-bdj libdvdcss2 libfftw3-bin libfftw3-dev serdi sidplay-base sordi opencl-icd libvdpau-va-gl1 nvidia-vdpau-driver nvidia-legacy-340xx-vdpau-driver nvidia-legacy-304xx-vdpau-driver 推荐安装: gstreamer1.0-fluendo-mp3 下列【新】软件包将被安装: chromium-codecs-ffmpeg-extra gstreamer1.0-libav gstreamer1.0-plugins-ugly gstreamer1.0-vaapi i965-va-driver intel-media-va-driver liba52-0.7.4 libaacs0 libaom0 libaribb24-0 libass9 libavcodec-extra libavcodec-extra58 libavfilter7 libavformat58 libavutil56 libbdplus0 libbluray2 libbs2b0 libchromaprint1 libcodec2-0.9 libdvdnav4 libdvdread7 libfftw3-double3 libflite1 libgme0 libgsm1 libgstreamer-plugins-bad1.0-0 libigdgmm11 liblilv-0-0 libmpeg2-4 libmysofa1 libnorm1 libopencore-amrnb0 libopencore-amrwb0 libopenmpt0 libpgm-5.2-0 libpostproc55 librubberband2 libserd-0-0 libshine3 libsidplay1v5 libsnappy1v5 libsord-0-0 libsratom-0-0 libssh-gcrypt-4 libswresample3 libswscale5 libva-drm2 libva-wayland2 libva-x11-2 libva2 libvdpau1 libvidstab1.1 libvo-amrwbenc0 libx264-155 libx265-179 libxvidcore4 libzmq5 libzvbi-common libzvbi0 mesa-va-drivers mesa-vdpau-drivers ocl-icd-libopencl1 ubuntu-restricted-addons ubuntu-restricted-extras unrar va-driver-all vdpau-driver-all 升级了 0 个软件包,新安装了 69 个软件包,要卸载 0 个软件包,有 14 个软件包未被升级。 需要下载 0 B/45.1 MB 的归档。 解压缩后会消耗 209 MB 的额外空间。 您希望继续执行吗? [Y/n]输入y当出现正在设定 ttf-mscorefonts-installer需要【把页面拉到最下方】,然后点击【Tab】键,才会选中【确定】,然后单击【Enter】才能完成…然后重新启动Firefox浏览器,到播放HTML5视频的页面去测试,应该是能正常播放HTML5视频了。5. 总结非常感谢各位大佬的支持,参考网上资料编写的,到这里Ubuntu安装后基本配置就算完成了。大家快去探索Ubuntu系统的乐趣吧!🥳🥳🥳我们实现对外部世界进行感知🎏,充分认识这个有机与无机的环境🌻,科学地合理地进行创作和发挥效益🛹,然后为人类社会发展贡献一点微薄之力。🏃♂️🏃♂️🏃♂️
1. 前言2019.10.24程序猿节腾讯在QQ官网发布了qq for linux 2.0.0 Beta,然后2020年4月1日发布QQ Linux版 2.0.0 Beta2,可谓是linux用户传输文件的一大福音。(我使用ubuntu20.04,对于其他linux架构和版本的朋友也可以参考一下,操作大同小异)官网地址2. QQ下载准备QQ Linux版 目前支持x64(x86_64、amd64)、arm64(aarch64)、mips64(mips64el)三种架构,每种架构支持Debian系、红帽系、Arch Linux系、其它发行版中的一种或几种(未来可能继续扩充)。每一次发布均会提供架构和发行版的若干种组合支持的安装包,可按下面所述的规则进行选择。打开QQ官网找到linux版本或者直接点击下面的链接每一个安装包会按照形如如下的格式命名:2.1选择架构:根据你所使用的机器硬件架构选择相应的兼容架构类型(可通过uname -a查看)x64(x86_64、amd64)、arm64(aarch64)、mips64(mips64el)2.2 linux发行版选择格式:后缀名安装包管理器支持发行版.rpmrpm/yum红帽系(如redhat、fedora、centos).debdpkg/aptdebian系(如debian、ubuntu、银河麒麟).pkg.tar.xzpacmanarch系(如Arch Linux、manjaro).shbash任意支持bash的发行版博主是ubuntu20.04系统,ubuntu点击x64 .deb点击x64架构下的.deb3.安装步骤3.1 安装依赖gtk2.0当前版本的QQ Linux版依赖gtk2.0,安装QQ Linux版前请确保你的系统已安装gtk2.0。以下是一些使用命令行安装gtk2.0的例子:sudo apt install libgtk2.0-0 # Ubuntusudo yum install gtk2.x86_64 # centos请参考你所使用的系统安装包管理器的使用说明来安装你所选择的QQ Linux版安装程序,注意你需要root权限才能完成安装。推荐第二种,第一种方式在一些发行版中你可以通过双击文件管理器中的安装程序完成安装;第二种方式以下是一些使用命令行来安装的例子:第一种方式第二种方式sudo ./linuxqq_1.0.1-b1-100_x86_64.sh sudo rpm -ivhlinuxqq_1.0.1-b1-100_mips64el.rpm sudo dpkg -ilinuxqq_1.0.1-b1-100_armhf.deb sudo apt install -y/path/to/linuxqq_1.0.1-b1-100_amd64.deb sudo pacman -Ulinuxqq_1.0.1-ci-94_x86_64.pkg.tar.xz根据我自己的x64 .deb电脑配置,在下载的软件包Ctrl+Alt+T打开终端,输入命令sudo dpkg -i linuxqq_2.0.0-b2-1089_amd64.deb3. 在显示应用程序中找到QQ,然后添加到菜单中。注意:如果版本更新后登录出现闪退情况,请删除 ~/.config/tencent-qq/#你的QQ号#目录后重新登录。在搜索中输入qq,扫码登陆3.2 卸载QQ请尽量使用你安装时使用的对应方式来卸载QQ Linux版(参考你所使用的系统安装包管理器说明)。同样需要root权限才能完成卸载。以下是一些例子:sudo rpm -e linuxqqsudo dpkg -r linuxqq与之对应我选择sudo dpkg -r linuxqq4. 总结非常感谢各位大佬的支持,参考网上资料编写的,到这里Ubuntu安装QQ使用就算完成了。大家快去探索Ubuntu系统的乐趣吧!🥳🥳🥳我们实现对外部世界进行感知🎏,充分认识这个有机与无机的环境🌻,科学地合理地进行创作和发挥效益🛹,然后为人类社会发展贡献一点微薄之力。🏃♂️🏃♂️🏃♂️
前提条件,第二种安装的需要是ubuntu20.04版本及以上。1.系统自带工具Print Screen该工具为ubuntu系统设置自带工具,可以直接使用,但不方便图示编辑,操作如下:1.1 快捷操作Print Screen为键盘上的截屏键,可以和其他键组合使用Print Screen 截取整个桌面Alt + Print Screen 截取选中的窗口Shift + Print Screen 自由选取这三个命令的结果是将截取的内容保存文图片,存放到文件夹中。文件夹为/home/(用户名)/图片还有三个按键组合,是将截取的内容放入到剪贴板中,可以用Ctrl + V粘贴Ctrl + Print Screen 整个桌面Ctrl + Alt + Print Screen 选中的窗口Ctrl + Shift + Print Screen 自由选取1.2 修改截图的快捷键为了方便左手操作,对此截图的快捷键自由选取修改改为Ctrl+1,可以在设置–键盘快捷键中修改,见下图。我这里键盘没有用Print键,采用Ctrl+12. flameshot截图工具2.1 安装命令sudo apt-get install flameshot安装很简单。如果当前用户安装不了,就切换到root用户安装。vor@vor:~$ sudo apt-get install flameshot [sudo] vor 的密码: 正在读取软件包列表... 完成 正在分析软件包的依赖关系树 正在读取状态信息... 完成 将会同时安装下列软件: libdouble-conversion3 libpcre2-16-0 libqt5core5a libqt5dbus5 libqt5gui5 libqt5network5 libqt5svg5 libqt5widgets5 libxcb-xinerama0 libxcb-xinput0 qt5-gtk-platformtheme qttranslations5-l10n 建议安装: qt5-image-formats-plugins qtwayland5 下列【新】软件包将被安装: flameshot libdouble-conversion3 libpcre2-16-0 libqt5core5a libqt5dbus5 libqt5gui5 libqt5network5 libqt5svg5 libqt5widgets5 libxcb-xinerama0 libxcb-xinput0 qt5-gtk-platformtheme qttranslations5-l10n 升级了 0 个软件包,新安装了 13 个软件包,要卸载 0 个软件包,有 14 个软件包未被升级。 需要下载 10.4 MB 的归档。 解压缩后会消耗 45.1 MB 的额外空间。 您希望继续执行吗? [Y/n] y 获取:1 http://mirrors.aliyun.com/ubuntu focal/universe amd64 libdouble-conversion3 amd64 3.1.5-4ubuntu1 [37.9 kB] 获取:2 http://mirrors.aliyun.com/ubuntu focal-security/main amd64 libpcre2-16-0 amd64 10.34-7ubuntu0.1 [181 kB] 获取:3 http://mirrors.aliyun.com/ubuntu focal-security/universe amd64 libqt5core5a amd64 5.12.8+dfsg-0ubuntu2.1 [2,006 kB] 获取:4 http://mirrors.aliyun.com/ubuntu focal-security/universe amd64 libqt5dbus5 amd64 5.12.8+dfsg-0ubuntu2.1 [208 kB] 获取:5 http://mirrors.aliyun.com/ubuntu focal-security/universe amd64 libqt5network5 amd64 5.12.8+dfsg-0ubuntu2.1 [673 kB] 获取:6 http://mirrors.aliyun.com/ubuntu focal/main amd64 libxcb-xinerama0 amd64 1.14-2 [5,260 B] 获取:7 http://mirrors.aliyun.com/ubuntu focal/main amd64 libxcb-xinput0 amd64 1.14-2 [29.3 kB] 获取:8 http://mirrors.aliyun.com/ubuntu focal-security/universe amd64 libqt5gui5 amd64 5.12.8+dfsg-0ubuntu2.1 [2,971 kB] 获取:9 http://mirrors.aliyun.com/ubuntu focal-security/universe amd64 libqt5widgets5 amd64 5.12.8+dfsg-0ubuntu2.1 [2,295 kB] 获取:10 http://mirrors.aliyun.com/ubuntu focal/universe amd64 libqt5svg5 amd64 5.12.8-0ubuntu1 [131 kB] 获取:11 http://mirrors.aliyun.com/ubuntu focal/universe amd64 flameshot amd64 0.6.0+git20191001-2 [288 kB] 获取:12 http://mirrors.aliyun.com/ubuntu focal-security/universe amd64 qt5-gtk-platformtheme amd64 5.12.8+dfsg-0ubuntu2.1 [124 kB] 获取:13 http://mirrors.aliyun.com/ubuntu focal/universe amd64 qttranslations5-l10n all 5.12.8-0ubuntu1 [1,486 kB] 已下载 10.4 MB,耗时 5秒 (2,242 kB/s) 正在选中未选择的软件包 libdouble-conversion3:amd64。 (正在读取数据库 ... 系统当前共安装有 147713 个文件和目录。) 准备解压 .../00-libdouble-conversion3_3.1.5-4ubuntu1_amd64.deb ... 正在解压 libdouble-conversion3:amd64 (3.1.5-4ubuntu1) ... 正在选中未选择的软件包 libpcre2-16-0:amd64。 准备解压 .../01-libpcre2-16-0_10.34-7ubuntu0.1_amd64.deb ... 正在解压 libpcre2-16-0:amd64 (10.34-7ubuntu0.1) ... 正在选中未选择的软件包 libqt5core5a:amd64。 准备解压 .../02-libqt5core5a_5.12.8+dfsg-0ubuntu2.1_amd64.deb ... 正在解压 libqt5core5a:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在选中未选择的软件包 libqt5dbus5:amd64。 准备解压 .../03-libqt5dbus5_5.12.8+dfsg-0ubuntu2.1_amd64.deb ... 正在解压 libqt5dbus5:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在选中未选择的软件包 libqt5network5:amd64。 准备解压 .../04-libqt5network5_5.12.8+dfsg-0ubuntu2.1_amd64.deb ... 正在解压 libqt5network5:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在选中未选择的软件包 libxcb-xinerama0:amd64。 准备解压 .../05-libxcb-xinerama0_1.14-2_amd64.deb ... 正在解压 libxcb-xinerama0:amd64 (1.14-2) ... 正在选中未选择的软件包 libxcb-xinput0:amd64。 准备解压 .../06-libxcb-xinput0_1.14-2_amd64.deb ... 正在解压 libxcb-xinput0:amd64 (1.14-2) ... 正在选中未选择的软件包 libqt5gui5:amd64。 准备解压 .../07-libqt5gui5_5.12.8+dfsg-0ubuntu2.1_amd64.deb ... 正在解压 libqt5gui5:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在选中未选择的软件包 libqt5widgets5:amd64。 准备解压 .../08-libqt5widgets5_5.12.8+dfsg-0ubuntu2.1_amd64.deb ... 正在解压 libqt5widgets5:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在选中未选择的软件包 libqt5svg5:amd64。 准备解压 .../09-libqt5svg5_5.12.8-0ubuntu1_amd64.deb ... 正在解压 libqt5svg5:amd64 (5.12.8-0ubuntu1) ... 正在选中未选择的软件包 flameshot。 准备解压 .../10-flameshot_0.6.0+git20191001-2_amd64.deb ... 正在解压 flameshot (0.6.0+git20191001-2) ... 正在选中未选择的软件包 qt5-gtk-platformtheme:amd64。 准备解压 .../11-qt5-gtk-platformtheme_5.12.8+dfsg-0ubuntu2.1_amd64.deb ... 正在解压 qt5-gtk-platformtheme:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在选中未选择的软件包 qttranslations5-l10n。 准备解压 .../12-qttranslations5-l10n_5.12.8-0ubuntu1_all.deb ... 正在解压 qttranslations5-l10n (5.12.8-0ubuntu1) ... 正在设置 libdouble-conversion3:amd64 (3.1.5-4ubuntu1) ... 正在设置 libxcb-xinput0:amd64 (1.14-2) ... 正在设置 libpcre2-16-0:amd64 (10.34-7ubuntu0.1) ... 正在设置 libxcb-xinerama0:amd64 (1.14-2) ... 正在设置 qttranslations5-l10n (5.12.8-0ubuntu1) ... 正在设置 libqt5core5a:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在设置 libqt5dbus5:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在设置 libqt5network5:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在设置 libqt5gui5:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在设置 libqt5widgets5:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在设置 qt5-gtk-platformtheme:amd64 (5.12.8+dfsg-0ubuntu2.1) ... 正在设置 libqt5svg5:amd64 (5.12.8-0ubuntu1) ... 正在设置 flameshot (0.6.0+git20191001-2) ... 正在处理用于 mime-support (3.64ubuntu1) 的触发器 ... 正在处理用于 hicolor-icon-theme (0.17-2) 的触发器 ... 正在处理用于 gnome-menus (3.36.0-1ubuntu1) 的触发器 ... 正在处理用于 libc-bin (2.31-0ubuntu9.9) 的触发器 ... 正在处理用于 man-db (2.9.1-1) 的触发器 ... 正在处理用于 desktop-file-utils (0.24-1ubuntu3) 的触发器 ...2.2 命令flameshot gui使用命令flameshot gui测试该截图工具,按ESC退出。2.3 截图工具设置快捷键给该截图工具设置快捷键,也就是给该命令设置快捷键,打开【设置】----【键盘快捷键】–点击最下面的【+】号,输入一下内容保存即可:这样就可以使用Ctrl +',来使用截图工具了。4. 总结非常感谢各位大佬的支持,参考网上资料编写的,到这里Ubuntu中截图工具使用就算完成了。大家快去探索Ubuntu系统的乐趣吧!🥳🥳🥳我们实现对外部世界进行感知🎏,充分认识这个有机与无机的环境🌻,科学地合理地进行创作和发挥效益🛹,然后为人类社会发展贡献一点微薄之力。🏃♂️🏃♂️🏃♂️
1. 摘要本篇文章主要介绍了在 Ubuntu 中使用 NTP 进行时间同步设置,通常客户端向服务器请求当前的时间,并根据结果来设置其时钟。2. 内容NTP 是通过网络来同步时间的一种 TCP/IP 协议。通常客户端向服务器请求当前的时间,并根据结果来设置其时钟。这个描述是挺简单的,实现这一功能却是极为复杂的 - 首先要有多层 NTP 服务器,第一层 NTP 服务器连接原子时钟,第二层、第三层服务器则担起负载均衡的责任,以处理因特网传来的所有请求。另外,客户端可能也超乎你想象的复杂 - 它必须排除通讯延迟,调整时间的同时不干扰其它在服务器中运行的进程。幸运的是,所有的这些复杂性都进行了封装,你是不可见也不需要见到的。在 Ubuntu 中,是使用 ntpdate和 ntpd来同步时间的,详细见官网。3. 具体实现3.1 timesyncd查看系统时间在最新的 Ubuntu 版本中,timesyncd替代了 ntpd的客户端的部分。默认情况下 timesyncd会定期检测并同步时间。它还会在本地存储更新的时间,以便在系统重启时做时间单步调整。通过 timedatectl和timesyncd设置的当前时间状态和时间配置,可以使用timedatectl status命令来进行确认输入查看时间指令:timedatectl返回如下vor@vor:~$ timedatectl Local time: 四 2022-09-29 09:26:18 CST Universal time: 四 2022-09-29 01:26:18 UTC RTC time: 四 2022-09-29 01:26:18 Time zone: Asia/Shanghai (CST, +0800)System clock synchronized: yes NTP service: active RTC in local TZ: no3.2 安装ntpdate同步时间库输入查看时间指令:sudo apt install ntpdate返回如下vor@vor:~$ sudo apt install ntpdate [sudo] vor 的密码: 正在读取软件包列表... 完成 正在分析软件包的依赖关系树 正在读取状态信息... 完成 下列【新】软件包将被安装: ntpdate 升级了 0 个软件包,新安装了 1 个软件包,要卸载 0 个软件包,有 0 个软件包未被升级。 需要下载 48.8 kB 的归档。 解压缩后会消耗 178 kB 的额外空间。 获取:1 http://mirrors.aliyun.com/ubuntu focal-security/universe amd64 ntpdate amd64 1:4.2.8p12+dfsg-3ubuntu4.20.04.1 [48.8 kB] 已下载 48.8 kB,耗时 0秒 (198 kB/s) 正在选中未选择的软件包 ntpdate。 (正在读取数据库 ... 系统当前共安装有 147529 个文件和目录。) 准备解压 .../ntpdate_1%3a4.2.8p12+dfsg-3ubuntu4.20.04.1_amd64.deb ... 正在解压 ntpdate (1:4.2.8p12+dfsg-3ubuntu4.20.04.1) ... 正在设置 ntpdate (1:4.2.8p12+dfsg-3ubuntu4.20.04.1) ... 正在处理用于 man-db (2.9.1-1) 的触发器 ...3.3 同步互联网时间输入查看时间指令:sudo ntpdate time.windows.com返回如下vor@vor:~$ sudo ntpdate time.windows.com 29 Sep 09:36:56 ntpdate[5539]: adjust time server 20.189.79.72 offset 0.080762 sec3.4 UTC改为localtime时间输入查看时间指令:sudo hwclock --localtime --systohc返回如下vor@vor:~$ sudo hwclock --localtime --systohc vor@vor:~$4. 总结非常感谢各位大佬的支持,特别是《机器人工匠阿杰》UP主,到这里经典Ubuntu同步系统时间统教程就算完成了。大家快去探索Ubuntu系统的乐趣吧!🥳🥳🥳我们实现对外部世界进行感知🎏,充分认识这个有机与无机的环境🌻,科学地合理地进行创作和发挥效益🛹,然后为人类社会发展贡献一点微薄之力。🏃♂️🏃♂️🏃♂️
1. 前言Ubuntu 建立在Debian的架构和基础架构之上,包括 Linux 服务器、桌面、物联以及云操作系统版本。最近项目需求换成linux的,入手ubuntu桌面比较简洁美观并且作为生产系统生态良好,开始了着手查找安装Ubuntu双系统的方法和视频,安装有两种:🎈方法🎈特点🎈定义虚拟机安装安全性高,可以双开通过软件模拟完成硬件,运行在一个完全隔离的环境中,不会对原系统产生影响U盘安装性能释放,相互访问将两个系统分别安装在同一台电脑的不同分区内,相互影响第一种发挥不出硬件本身的性能,尝鲜还行;算法学习推荐使用第二种,慢慢相互影响,命运与共。2. 前提准备大于8G的U盘一个(提前备份数据,然后清空)2.1 下载Ubuntu 20.04 LTS 镜像官网地址:https://cn.ubuntu.com/download推荐下载地址:清华源下载ubuntu-20.04.5-desktop-amd64.iso选择Ubutun的20.04.5 (amd64, Desktop LiveDVD)下载2.2 下载安装Win32 Disk Imager工具视频:官网地址:该程序旨在将原始磁盘映像写入可移动设备或将可移动设备备份到原始映像文件。它对于嵌入式开发非常有用,即 Arm 开发项目(Android、Ubuntu on Arm 等)。然后就有第二个下载的工具安装第一个下载的Ubutun系统2.3 制作Ubutun安装盘视频:选择镜像文件Ubutun文件,此处K盘为U盘,其他不管直接写入,点击Yes继续,等待烧写完成。烧写完成3. window设置3.1 磁盘分区视频:分出一个空的区域给ubuntu系统做存储。在桌面上,点击计算机图标(右键)–> 管理 --> 找到磁盘管理,之后找一个比较大的硬盘分区点击一下,大约需要40G空间。如果你的可以分出更多,按照这个比例划分就好🏃♂️🏃♂️🏃♂️分区(引导区)efi(内存交换区)swap(根挂载点C盘) /(非系统盘) /home功能开机选择系统引导文件计算机运行交互产生数据暂存区域安装系统软件位置存放用户数据大小分配500MB10000MB20000MB11450MB注意引导区efi要求在C盘(分出500MB),其他分区可在C盘外(分出40G)方案一适用于磁盘空间大的方案二适用于磁盘空间小的输入需要压缩的空间,就能得到一个对应的空余空间用来当做ubuntu系统盘。3.2 查看计算机磁盘格式视频:Windows磁盘格式一般为MBR和GPT两种格式查看方法,点击对应磁盘,右键属性,然后查看卷,下面可见对应分区形式4. Ubuntu安装Ubuntu安装分为两种MBR分区和GPT分区两种,大家按需就位💖💖💖4.1 进入Bios设置U盘启动开机或重启,根据常用的品牌,我的是华硕笔记本狂按F2,进入Bios的设置,下面给出对应启动键表,方便大家自查!😀😀😀一般电脑设置保护,在BIOS里面的Security,把Security Boot由Enable改为Disable在开始设置setup中,UEFI/Legacy Boot选择Legacy Only模式,然后ESC退出保存4.2 MBR分区安装视频进入安装U盘启动后会出现黑色界面的引导界面。选择English US键盘布局选择English US键盘布局连接网络选择正常安装,不建议把下面两个选项也勾上,勾上容易下载识别导致故障。选择安装类型,**这里我们自定义安装,选择其他选项。**如果不想折腾也可以简单选择第一个选项。分区,这是最重要的一点,前面我们预留了硬盘空间这里就用上了,我们点击空余空间,点 + 号新建分区。这里我们要分四个区域,分别是/boot 启动目录,开机启动所需目录。(C盘分出来的500MB)swap 交换空间,一般10000MB。/ 根目录我分了20000MB/home 家目录,就是我们自己存放用户数据的目录,剩下全部都给他。 方案二是根挂载点和/home合并之后点击 现在安装 即可。选择上海时区选择用户设置,小巧简洁就好等安装完成以后点重启,点击现在重启然后把U盘拔下来,按回车键就重启了。选择第一项为Ubutun启动,最后一项为Windows启动点击前进,选择否,然后一直前进,就顺利安装👻👻👻4.3 GPT分区安装视频前期操作可以参照MRT分区安装。只有第七步有差异。分区有两点不同,第一点原先的/boot分区现在是EFI系统分区第二点修改EFI分区的引导器与之对应,这里p5对p55. 总结非常感谢各位大佬的支持,特别是《机器人工匠阿杰》UP主,到这里经典Ubuntu20.04版本U盘安装双系统教程就算完成了。大家快去探索Ubuntu系统的乐趣吧!🥳🥳🥳我们实现对外部世界进行感知🎏,充分认识这个有机与无机的环境🌻,科学地合理地进行创作和发挥效益🛹,然后为人类社会发展贡献一点微薄之力。🏃♂️🏃♂️🏃♂️
1. MicroPython 介绍MicroPython是具有部分原生代码编译功能的 Python 解释器。MicroPython 实现了 Python 3.4 和 Python 3.5 及更高版本的一些精选功能,用于嵌入式处理器和受限系统。它与 CPython 不同,您可以在此处阅读有关差异的更多信息。MicroPython 是 Python 3编程语言的精简高效实现,其中包括 Python 标准库的一小部分,并且经过优化,可在微控制器和受限环境中运行。MicroPython pyboard是在裸机上运行 MicroPython 的紧凑型电子电路板,为您提供可用于控制各种电子项目的低级 Python 操作系统。MicroPython 充满了高级功能,例如交互式提示、任意精度整数、闭包、列表推导、生成器、异常处理等等。然而,它足够紧凑,可以在 256k 的代码空间和 16k 的 RAM 内安装和运行。MicroPython 旨在尽可能与普通 Python 兼容,让您可以轻松地将代码从桌面传输到微控制器或嵌入式系统。2. 入门首先,我们将Pi RP2040 连接到计算机,并从 MicroPython 上传一个简单的代码来检查板子是否运行良好。2.1 硬件设置Pi RP2040 x1安卓Micro数据线 x1电脑 x12.2 软件设置步骤 1 :根据您的操作系统下载并安装最新版本的Thonny 编辑器我的是windows,选推荐的第一个,下载地址步骤 2 :启动Thonny选择简体中文和Pi步骤 3 :点击“切换至一般模式”,重新启动。效果如下第 4 步。连接Pi Pico,依次选择运行>配置解释器>解释器>端口,选择设备为MicroPython(Raspberry Pi Pico),端口为Try to detect prot automatically3. RP2040 连接到 PC 并点亮3.1 步骤 1按住“BOOT”按钮,然后通过安卓线将RP2040连接到PC。如果运行良好,PC 上会显示“RPI-RP2”桌面。👻👻👻3.2 步骤 2按下“停止/重启后端”按钮,将弹出一个窗口,帮助您在板上安装 MicroPython 固件。为您的开发板下载正确的 MicroPython UF2 文件:Raspberry Pi PicoRaspberry Pi Pico W固件完成后,打开设备管理器查看端口。😀😀😀端口是:COM253.3 步骤 3检查解释器是否一致COM25将以下代码复制到 Thonny。from machine import Pin, Timer led = Pin(25, Pin.OUT) Counter = 0 Fun_Num = 0 def fun(tim): global Counter Counter = Counter + 1 print(Counter) led.value(Counter%2) tim = Timer(-1) tim.init(period=1000, mode=Timer.PERIODIC, callback=fun) 第 4 步。通过单击“运行当前脚本”按钮上传代码。第一次,Thonny 会询问您要将代码文件保存在哪里。This Computer和Raspberry Pi Pico都很好。如果运行良好,您将看到 LED 灯每秒打开和关闭一次。并且越来越多的输出也将显示在 Shell 中。4. IIC 连接RP2040在SSD1306显示在本项目中,我们将通过IIC接口连接Grove - OLED Display 0.96" (SSD1306),在Seeed Studio XIAO RP2040上演示IIC功能。4.1 硬件连接步骤 1。下载ssd1306.py库并用 Thonny 打开它。# MicroPython SSD1306 OLED driver, I2C and SPI interfaces from micropython import const import framebuf # register definitions SET_CONTRAST = const(0x81) SET_ENTIRE_ON = const(0xA4) SET_NORM_INV = const(0xA6) SET_DISP = const(0xAE) SET_MEM_ADDR = const(0x20) SET_COL_ADDR = const(0x21) SET_PAGE_ADDR = const(0x22) SET_DISP_START_LINE = const(0x40) SET_SEG_REMAP = const(0xA0) SET_MUX_RATIO = const(0xA8) SET_COM_OUT_DIR = const(0xC0) SET_DISP_OFFSET = const(0xD3) SET_COM_PIN_CFG = const(0xDA) SET_DISP_CLK_DIV = const(0xD5) SET_PRECHARGE = const(0xD9) SET_VCOM_DESEL = const(0xDB) SET_CHARGE_PUMP = const(0x8D) # Subclassing FrameBuffer provides support for graphics primitives # http://docs.micropython.org/en/latest/pyboard/library/framebuf.html class SSD1306(framebuf.FrameBuffer): def __init__(self, width, height, external_vcc): self.width = width self.height = height self.external_vcc = external_vcc self.pages = self.height // 8 self.buffer = bytearray(self.pages * self.width) super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) self.init_display() def init_display(self): for cmd in ( SET_DISP | 0x00, # off # address setting SET_MEM_ADDR, 0x00, # horizontal # resolution and layout SET_DISP_START_LINE | 0x00, SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 SET_MUX_RATIO, self.height - 1, SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 SET_DISP_OFFSET, 0x00, SET_COM_PIN_CFG, 0x02 if self.width > 2 * self.height else 0x12, # timing and driving scheme SET_DISP_CLK_DIV, 0x80, SET_PRECHARGE, 0x22 if self.external_vcc else 0xF1, SET_VCOM_DESEL, 0x30, # 0.83*Vcc # display SET_CONTRAST, 0xFF, # maximum SET_ENTIRE_ON, # output follows RAM contents SET_NORM_INV, # not inverted # charge pump SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, SET_DISP | 0x01, ): # on self.write_cmd(cmd) self.fill(0) self.show() def poweroff(self): self.write_cmd(SET_DISP | 0x00) def poweron(self): self.write_cmd(SET_DISP | 0x01) def contrast(self, contrast): self.write_cmd(SET_CONTRAST) self.write_cmd(contrast) def invert(self, invert): self.write_cmd(SET_NORM_INV | (invert & 1)) def show(self): x0 = 0 x1 = self.width - 1 if self.width == 64: # displays with width of 64 pixels are shifted by 32 x0 += 32 x1 += 32 self.write_cmd(SET_COL_ADDR) self.write_cmd(x0) self.write_cmd(x1) self.write_cmd(SET_PAGE_ADDR) self.write_cmd(0) self.write_cmd(self.pages - 1) self.write_data(self.buffer) class SSD1306_I2C(SSD1306): def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): self.i2c = i2c self.addr = addr self.temp = bytearray(2) self.write_list = [b"\x40", None] # Co=0, D/C#=1 super().__init__(width, height, external_vcc) def write_cmd(self, cmd): self.temp[0] = 0x80 # Co=1, D/C#=0 self.temp[1] = cmd self.i2c.writeto(self.addr, self.temp) def write_data(self, buf): self.write_list[1] = buf self.i2c.writevto(self.addr, self.write_list) class SSD1306_SPI(SSD1306): def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): self.rate = 10 * 1024 * 1024 dc.init(dc.OUT, value=0) res.init(res.OUT, value=0) cs.init(cs.OUT, value=1) self.spi = spi self.dc = dc self.res = res self.cs = cs import time self.res(1) time.sleep_ms(1) self.res(0) time.sleep_ms(10) self.res(1) super().__init__(width, height, external_vcc) def write_cmd(self, cmd): self.spi.init(baudrate=self.rate, polarity=0, phase=0) self.cs(1) self.dc(0) self.cs(0) self.spi.write(bytearray([cmd])) self.cs(1) def write_data(self, buf): self.spi.init(baudrate=self.rate, polarity=0, phase=0) self.cs(1) self.dc(1) self.cs(0) self.spi.write(buf) self.cs(1) 步骤 2。单击“文件→另存为”并将库保存在“Raspberry Pi Pico”中选择“Raspberry Pi Pico”作为我们保存的位置。确保保存的文件名为“ssd1306.py”,否则将无法使用。步骤 3。将以下代码复制到 Thonny。from ssd1306 import SSD1306_I2C from machine import Pin, I2C from time import sleep i2c = I2C(1, scl=Pin(7), sda=Pin(6), freq=200000)#Grove - OLED Display 0.96" (SSD1315) oled = SSD1306_I2C(128, 64, i2c) while True: oled.fill(0)#clear oled.text("Hello,World!",0,0) oled.show() #sleep(0.5) 第 4 步。通过单击“运行当前脚本”按钮上传代码。第一次,Thonny 会询问您要将代码文件保存在哪里。This Computer和Raspberry Pi Pico都很好。接线入下端口A板子端口B板子VCCSSD13063V3PicoGNDSSD1306GNDPicoSCLSSD1306GPIO7PicoSDASSD1306GPIO6Pico如果运行良好,您将看到文本“Hello,World!” 显示在屏幕上。5. 其他资源一些额外的库和示例代码在这里:[ZIP] XIAO-RP2040-MicroPython-Grove.zipMicroPython【树莓派 Pico 基于Arduino IDE编程开发】【树莓派 Pico 和 Pico W】
1. Pico族Raspberry Pi Pico 系列包括 Raspberry Pi Pico(左)、Pico H(中)和 Pico W(右)。2. 树莓派 Pico 和 Pico HRaspberry Pi Pico 是一款具有灵活数字接口的低成本、高性能微控制器板。2.1 主要特点:英国树莓派设计的RP2040微控制器芯片双核 Arm Cortex M0+ 处理器,运行频率高达 133 MHz 的灵活时钟264kB SRAM 和 2MB 板载闪存支持设备和主机的 USB 1.1低功耗睡眠和休眠模式通过 USB 使用大容量存储进行拖放编程26×多功能GPIO引脚2 × SPI、2 × I2C、2 × UART、3 × 12 位 ADC、16 × 可控 PWM 通道片上精确时钟和定时器温度感应器片上加速浮点库8 个可编程 I/O (PIO) 状态机,用于自定义外设支持Raspberry Pi Pico 带有一个城堡形模块,允许直接焊接到载板上,而 Pico H 带有预焊接接头。笔记两块板都有一个三针串行线调试 (SWD) 接头。然而,Pico H 将其拆分为一个小的键控3 针连接器,而 Pico 在电路板边缘附近有三个带齿的通孔针。2.2 引脚和设计文件pico 引出线下载引脚图(PDF)下载设计文件(Cadence Allegro)下载开发文件笔记有关 Fritzing 的更多信息,请访问fritzing.org网站。3. 树莓派 Pico WRaspberry Pi Pico W 使用英飞凌 CYW4343 添加了板载单频段 2.4GHz 无线接口 (802.11n),同时保留了 Pico 外形尺寸。板载 2.4GHz 无线接口具有以下3.1 主要特点:无线 (802.11n),单频段 (2.4 GHz)WPA3支持多达四个客户端的软接入点该天线是 ABRACON(原 ProAnt)许可的板载天线。无线接口通过 SPI 连接到RP2040微控制器。由于管脚限制,一些无线接口管脚是共享的。CLK 与 VSYS 监视器共享,因此只有在没有正在进行的 SPI 事务时才能通过 ADC 读取 VSYS。Infineon CYW43439 DIN/DOUT 和 IRQ 在 RP2040 上都共享一个引脚。只有当 SPI 事务不在进行中时,才适合检查 IRQ。该接口通常以 33MHz 运行。为获得最佳无线性能,天线应位于自由空间中。例如,将金属放在天线下方或附近会降低其增益和带宽方面的性能。在天线的侧面添加接地金属可以提高天线的带宽。笔记CYW43439 无线芯片通过 SPI 连接到 RP2040。虽然 CYW43439 支持 802.11 无线和蓝牙,但最初 Pico W不支持蓝牙。稍后可能会添加支持,并将使用相同的 SPI 接口。如果添加支持,现有硬件可能需要更新固件以支持蓝牙,但无需修改硬件。3.2 引脚和设计文件picow 引出线下载引脚图(PDF)下载设计文件(Cadence Allegro)下载开发文件4. 软件实用程序4.1 你的 Pico 拥有什么?如果您忘记了在您的 Raspberry Pi Pico 中编程的内容,并且该程序是使用我们的 Pico C/C++ SDK 构建的,它通常会在二进制文件中嵌入名称和其他有用信息。您可以使用Picotool命令行实用程序来查找这些详细信息。我们的“入门”文档中提供了有关如何使用 Picotool 执行此操作的完整说明。转到Picotool Github 存储库。4.2 重置闪存Pico 的 BOOTSEL 模式存在于 RP2040 芯片内部的只读存储器中,不会被意外覆盖。无论如何,如果您在插入 Pico 时按住 BOOTSEL 按钮,它将显示为一个驱动器,您可以将新的 UF2 文件拖到该驱动器上。没有办法通过软件来砖板。但是,在某些情况下,您可能需要确保闪存为空。您可以通过在 Pico 处于大容量存储模式时将一个特殊的 UF2 二进制文件拖放到您的 Pico 上来做到这一点。下载UF2 文件见Github 上的代码5. 帮助文档Raspberry Pi Pico 和其他基于 RP2040 的板的文档。5.1 RP2040 设备RP2040 数据表Raspberry Pi 的微控制器使用 RP2040 进行硬件设计使用 RP2040 微控制器构建电路板和产品5.2 树莓派 Pico树莓派 Pico 数据表基于 RP2040 的微控制器板树莓派 Pico 入门使用 Raspberry Pi Pico 和其他基于 RP2040 的微控制器板进行 C/C++ 开发笔记虽然它不受官方支持,但有一个适用于 Windows 的 Pico Setup安装工具,它可以在 Windows 10 上自动安装 C/C++ SDK。5.3 树莓派 Pico W树莓派 Pico W 数据表具有无线wifi功能的基于 RP2040 的微控制器板使用 Raspberry Pi Pico W 连接到 Internet使用 C/C++ 或 MicroPython 在线获取 Raspberry Pi Pico W5.4 软件开发树莓派 Pico C/C++ SDK用于在 RP2040 微控制器上进行 C/C++ 开发的库和工具树莓派 Pico Python SDKRP2040 微控制器的 MicroPython 环境树莓派 Pico 和 Pico WRaspberry-Pi-PICO系列–第一篇 初识RP2040
1. 小树简介🌻小树科技官网理念:集体智慧,更加强大,小树, 为国人打造优质创客工具2. 3D打印机🌻🌻2.1 打印机定义:三维立体打印机,也称三维打印机(3D Printer,简称3DP)是快速成型(Rapid Prototyping,RP)的一种工艺,采用层层堆积的方式分层制作出三维模型,其运行过程类似于传统打印机,只不过传统打印机是把墨水打印到纸质上形成二维的平面图纸,而三维打印机是把液态光敏树脂材料、熔融的塑料丝、石膏粉等材料通过喷射粘结剂或挤出等方式实现层层堆积叠加形成三维实体。2.2 打印机分类:材料选择性熔覆工艺(FDM)、光敏树脂选择性固化工艺(SLA)、粉末材料选择性烧结工艺(SLS)、选择性区域透光树脂固化工艺(LCD)、投影式三维打印工艺(DLP)等。2.3 打印机结构:FDM式3D打印机的机械结构发展迅猛,最常见的应该就是Prusa i3龙门结构,本文中讲的是Cantilevered臂梁结构内容。当然还有其它结构比如Delta三角洲机型、Ultimaker结构、Corexy结构等。可参照:DIY3d打印入门指南】各种结构总览,直观认识常见的3d打印机结构3. 小树T系列安装🌻🌻🌻3.1 采购根据需求采购对应的型号,我采用的是T3(T4带WiFi):相关材料自查、相关参数自查目标就是组装一台可以使用的打印机3.2 预先了解围绕主控板展开主板详解,安装视频:MKS GEN 2.1主板装驱动和跳线帽注意:GEN 1.0,2.0的跳线帽都是插好的,用户不需要插,没有跳线帽包!3.3 小树装机文档见:https://docs.qq.com/slide/DZklodWdBSUl2cnli视频见:https://space.bilibili.com/53548293/channel/seriesdetail?sid=1340891大家根据自身需求逐一安装!建议围绕官方教程展开:https://space.bilibili.com/53548293/channel/seriesdetail?sid=13408913.4 调试切片当我们安装完成,需要对打印机进行打印测试,调机视频:https://www.bilibili.com/video/BV1354y117px基本的XYZ轴一定弄清楚这是我调试的顺序记录切片软件采用cura:详细见cura教学3.5 附带工具3.6 附带打印大家组装调试好机子之后,可以把对应的保护盒打印一份,整理线路(功率线和信号线分开)小树T3代 用户自助3D打印文件,STL文件需要自己切片 ,Gcode文件可以直接打印4. 总结🌻🌻🌻🌻本文从介绍小树科技开始,是国内最早研发3D打印机的公司。接着阐述了3D打印机是采用层层堆积的方式分层制作出三维模型,列举出不同打印模式机器,分析最常见FDM型打印机的结构。根据自身选择的小树T3打印机散件,如何循序善诱由0到1的组装调试打印全过程。非常感谢你的阅读!我们会好好学习天天向上🎉🎉🎉
1. 描述V1.0和V2.1的区别:在MKS GEN_L V2.1上 MKS TMC2130 SPI,MKS TMC2208、MKSTMC2209 UART模式直插接用,通过跳线帽跳线,不用飞线。将2560及 ramps1.4集合在一块板子上,解决了Ramps1.4组合接口繁琐、易初故障的问题用户可自己更换电机驱动,支持4988驱动和8825驱动、TMC2100 驱动。预留外接驱动信号,可外接大驱动来驱动57.86电机。采用高质量MOSFET管,散热效果更好,保证长时间工作稳定。采用专用电源芯片,支持12V-24V电源输入,解决Ramps电压转换芯片发热、供电不足问题。稳定可靠的滤波电路大大降低干扰的可能性,最大可能的避免打印过程中出现的死机、乱跑等现象。采用CH340串口芯片,在确保稳定可靠的前提下,降低成本,更是解决了以往16U2难装驱动的问题。可以接受24V输入,同样系统功率下可以把热床电流减小到1/4,有效解决热床MOS管发热问题。使用开源固件 Marlin,配置和ramps1.4完全相同,可直接替代 Ramps1.4.可直接连接2004LCD 显示屏及12864LCD 显示屏,可支持创客开发的TFT28、TFT32触摸屏。XYZ轴分别采用不同颜色的端子来对应电机和限位开关,方便接线。人性化的设计,用不同颜色的端子区分驱动方向,降低插反的概率,防止因驱动插反而损坏主板。将2560和Ramps1.4集成到一块PCB,布线更简单,更稳定,支持marlin 1.x和marlin 2.xx,支持MKS TFT系列等从 V1.0 开始的硬件并添加对 TMC UART、SPI 模式的支持MKS 建议您使用 V2.1 版本,因为它支持更多功能2. 特征高性能、低功耗 Atmel® AVR® 8 位微控制器 AMEGA2560-16AUSuooprt DC12-24 VINDcin-Dc5v 使用 MP1584EN, 3A, 1.5MHz, 28V 降压转换器热床使用HY3403D,参数为30V/100AHOT-END和FAN使用HY1403D,参数为30V/42A3 NTC100K TH1,TH2,TB 温度测量集成 5 个 ASIX接口通过 EXP1 EXP2 支持 LCD 和通过 AUX-1 支持 MKS TFT 系列屏幕通过 USB 上传固件添加对 TMCUART、SPI 模式的支持主板参数:主板型号:MKS GEN_LV2.1微处理器:ATMEGA2560外双尺寸:110*84mm安装孔尺寸:102*76mm输入电压:12V~24V 5A~15A电机驱动器:2208,2209,2225,2226,4988,8825,8729等驱动温度传感器接口:NTC 100K支持触摸屏:LCD/ LCD2004、LCD12864、摸屏MKS MINI12864V1.0、MKS MINI12864 V3.0.MKS系列支持打印文件格式:G-code支持机器结构:XYZ、 delta 、 kossel 、Ultimaker . corexy推荐软件:Cura 、 Simplify3d、Pronterface 、Repetier-Host固件更新:通过USB连接电脑更新3. 主板封装3.1 尺寸图整体尺寸为11084mm,螺栓固定孔位为10276mm3.2 接线图3.2.1 MKS GEN_L V1.0系统连接图3.2.2 MKSGEN_L V2.1系统连接图中文版英文版V2.1相对V1.0版本优化散热,以及减少串口下载晶振(减少物料)4. 引脚排列MKS GEN_LV1.0:MKS GEN_LV2.1:怎加更多端口细节5. GEN_LV2.1驱动设置注意:以下设置是基于MKS系列的驱动进行的设置,不同厂家的驱动可能设置的方式有所不同。5.1 Step/dir普通运行模式在普通模式的情况下,(如A4988,LV8729,TB67s109)通过跳线帽调节驱动的细分。可以根据自身需求,将跳线帽插到右侧两排黑色排针的M0,M1,M2处,进而实现对细分的调节。注意:在普通的模式下第四个插针,建议不要插跳线帽。如果插上跳线帽可能会影响部分驱动的使用。(如TB67S109)5.2 Uart模式(MKS TMC2208 V2.0)电机驱动在UART模式下,可以直接在Marlin固件中直接进行电流、工作模式的配置。以TMC2208为例,使用的UART模式的情况下,需要做到以下几点。(图文配合理解)如图所示驱动下面跳线帽需要全部取出(不能带有跳线帽)。在主板上的UART插针处,插上跳线帽。在marlin固件进行驱动部分的设置(详情请参考说明书)5.3 SPI模式SPI模式由于主板内部线路的支持, TMC2130或者其他类型驱动的SPI模式不再需要进行跳线,直接跳线帽即可完成设置,如下图所示左侧绿色四排全部插上跳线帽。SPI模式marlin固件设置(详情请参考说明书)。
1.万耦启物简介启物开发板主控芯片为MM32F3277G8P(MM32F3270),拥有温湿度传感器、WiFi模块、蜂鸣器等丰富的板载资源,还包括SD卡、USB、摄像头、屏幕等各类接口,是连接Onenet的好帮手!🤣🤣🤣1.1 展示细节实物图:板载接口资源:板载尺寸94mm*72mm1.2 原理图CPU外围电路引脚接口电路拓展外设电路2. 板载资源使用高性能的 Arm® Cortex-M3 为内核的 32 位微控制器,最高工作频率可达 120MHz,内置高速存储器,丰富的 I/O 端口和多种外设。512KB Flash,128KB SRAM3 个 12 位的 ADC、2 个 12 位的DAC、2 个比较器2 个 16 位通用定时器、2 个 32 位通用定时器、2 个 16 位基本定时器和 2 个 16 位高级定时器2 个 I2C 接口、3 个 SPI 接口、3 个 I2S 接口和 8 个 UART 接口1 个 USB OTG 全速接口1 个 CAN 接口1 个 SDIO 接口工作电压为 2.0V - 5.5V工作温度范围(环境温度)-40℃ - 85℃ 工业型和-40℃ - 105℃ 扩展工业型(后缀为V)多种省电工作模式支持低功耗应用的需求提供 LQFP144、LQFP100、LQFP64、LQFP48 和 QFN40 封装2.1 接口板载USB-TTL接口:启物开发板DebugUART输出接口,硬件接口为USBType-C母座,,直连电脑设备识别为CH340串口,可作为5V供电接口。MCU USBO接口:MM32F3277USB接口,支持USB2.0Full-Speed (全速)。硬件接口为USBType-C母座,可作为5V供电接口。屏幕接口:此接口可使用逐飞科技的TFT1.8寸屏幕,也可使用1.14寸或2.0寸IPS屏幕,或者使用OLED屏幕,连接方式详见后续接口讲解。摄像头接口:此接口可接入摄像头类光电传感器,兼容逐飞科技的小钻风硬件二值化摄像头、总钻风全局快门灰度摄像头。SWD调试接口∶此接口连接MM32F3277芯片的SWD调试引脚,可直接使用逐飞科技的DAP调试下载器与ARM调试下载器进行调试下载。JTAG调试接口:标准的JTAG接口,可使用Jlink调试下载器直连进行调试下载。RTC电池:纽扣电池卡扣,可使用纽扣电池为芯片RTC供电。电源拓展接口:为了方便用户接线测试使用,预留的3V3、5V与GND接口。l0拓展接口: 2.54mm间距的双排针接口,引出了芯片上部分IO引脚,包含一些常用的功能例如ADC、PWM、UART 与SPI等。NRF2401接口:2.54mm间距的双排座接口,可直接使用常见的SPI接口的NRF24LO1模块。SD (TF)卡座:SD卡插槽,可使用SD (TF)卡。2.2 模块类蜂鸣器:有源蜂鸣器,使用芯片的B5引脚进行控制,可以使用PWM方式调音。AHT20温湿度传感器:开发板搭载的温湿度传感器,使用C方式驱动对应芯片B10/B11引脚。ESP8266 - — WiFi模块:开发板搭载的无线WiFi模块,使用UART方式驱动对应芯片BO/B1引脚。2.3 按键类用户按键:连接至MCU的D12/D14D/15引脚,按下时对应引脚处于低电平。功能按键/RST按键:连接至MCU的RST引脚,按不时芯片复位引脚电平拉低进入复位。功能按键/BOOTO按键:连接至MCU的 H3引脚,当MCU从复位状态进入运行状态时,若此按键处于按下状态,则 MCU进入ISP启动模式。2.4 跳线类串口选择开关:此跳线开关可选择Debug UART的log信息从SWD调试接输出还是从板载USB-TTL接口输出。2.5 指示灯类RGB指示灯:RGB灯珠,RED对应芯片Al引脚,GREEN对应芯片A2引脚,BLUE对应芯片A3引脚,可使用对应引脚的 PWM或者IO方式驱动。电源指示灯:主板上各3V3供电指示灯,正常黄色亮起为供电正常。3.开发接口简介3.1.摄像头接口逐飞科技的摄像头接口转接板连接主板时,出线方向朝外,使用FPC排线为异面排线。连接时俯视图如下示例。3.2.屏幕接口3.2.1.OLED屏幕屏幕接口接入OLED屏幕时,连接靠近摄像头接口一侧的排座,从GND引脚开始对应,OLED模块仅有7个引脚,所以D11引脚对应的位置悬空。连接如下所示。3.2.2.1.8寸TFT屏幕屏幕接口接入1.8寸TFT屏幕时,连接靠近摄像头接口一侧的排座,从GND引脚开始对应,1.8寸TFT屏幕正好一排8个引脚,占用一整排排座。连接俯视图如下。3.2.3.1.14 寸IPS屏幕屏幕接口接入1.14寸IPS屏幕时,连接靠近摄像头接口一侧的排座,从GND引脚开始对应,1.14寸IPS屏幕正好一排8个引脚,占用一整排排座。连接俯视图如下。3.2.4.1.14 寸IPS屏幕屏幕接口接入2寸IPS屏幕时连接方式如下,连接靠近摄像头接口一侧的排座,从GND引脚开始对应,2寸IPS屏幕正好两排8个引脚,总共16个引脚,占用整个2*8排座。3.3.NRF接口常见的NRF模块即可,安装连接时,天线方向朝外。安装连接时俯视图如下。3.4.RTC电池接口纽扣电池安装连接时负极朝下正极朝上,俯视图如下。3.5.SD (TF)卡接口SD卡连接时插入自锁座即可,插入后有锁紧动作,接入正常时俯视图如下。3.6.调试下载接口3.6.1.SWD调试接口逐飞科技的DAPLink连接方式,出线方向朝外。3.6.2.JTAG调试接口逐飞科技的ARM调试器连接方式,出线方向朝外。3.7.拓展接口启物开发板上预留了拓展接口,拓展接口将芯片上部分引脚引出,可供测试、调试、拓展外设等需求使用,接口示意图与对应引脚如下图。UART1拓展;B6引脚可用作 UARTl的 TX引脚,B7引脚可用作 UART1的RX引脚;UART7拓展:B6/E8引脚可用作UART7的TX引脚,B7/E7引脚可用作 UART7的RX引脚;UART5拓展:A4引脚可用作UART5的 RX引脚,A5引脚可用作UART5的TX引脚;UART8拓展:E6引脚可用作 UART8的 RX引脚,E1引脚可用作UART8的 TX引脚;IIC1拓展:B6/B8引脚可用作lC1的SCL引脚,B7/B9引脚可用作lICl的SDA引脚;IIC2拓展:IIC2默认分配给了板载的AHT20传感器,这里可以复用功能,E5引脚可用作IIC2的SCL引脚,E6引脚可用作ⅡIC2的SDA引脚;SPIl拓展:A4引脚可用作SPI1的 NSS引脚,A5引脚可用作SPl1的SCK引脚,A6引脚可用作SPI1的 MISO引脚,A7引脚可用作SPI1的 MOSI引脚;SPI2拓展:SPI2默认分配给NRF接口,这里可以复用,E2引脚可用作SP2的SCK引脚,E3/E4引脚可用作SPI2的NSS引脚,E5引脚可用作SPI2的MISO引脚,E6引脚可用作SPI2的MOSI引脚;lIS1拓展:A4引脚可用作lSl的WS引脚,A5引脚可用作llS1的CK引脚,A6引脚可用作IISl的MCK引脚,A7引脚可用作IIS1的SD引脚;IIS2拓展:E2引脚可用作ⅡIS2的WS引脚,E3/E4引脚可用作ⅡIS2的CK引脚,E5引脚可用作IlS2的 MCK引脚,E6引脚可用作IIS2的SD引脚;PWM拓展:B6-B9可用作TIM4的CH1-CH4的 PWM输出使用,其余引脚上还有不同的TIM输出的不连续的PWM输出通道可用;ADC拓展∶A4-A7可用作 ADC1/2的 CH4-CH7的ADC输入使用;4.复位与解锁4.1 复位与ISP下载模式启物开发板的左下角的功能按键区域,包含了RST复位按键与BOOT0按键。ISP下载软件按住BOOT0按键,再按一次RST按键,启物开发板的MM32F3277芯片就会复位并进入ISP下载模式,进入ISP下载模式后可通过串口进行ISP进行程序下载。主闪存存储器启动(BOOTO=0):主闪存存储器的起始地址是Ox0800 0000,当其被选为启动模式时,被映射到启动存储空间《Ox00000000),但是闪存存储器的内容依旧可以从起始地址(Ox08000000)访问,即当主闪存存储器被选为启动模式,启动地址和起始地址都可以访问闪存存储器。系统存储器启动(BOOT1=0&BOOTO=1:系统存储器的起始地址是Ox1FFF F400,当其被选为启动模式时,被映射到启动存储空间(Ox0000 0000),但是系统存储器的内容依旧可以从起始地址(Ox1FFF F400)访问,即当系统存储器被选为启动模式,启动地址和起始地址都可以访问系统存储器。内置SRAM启动(BOOT1=1&BOOTO=1):内置SRAM的起始地址是0x2000 0000,当其被选为启动模式时,被映射到启动存储空间(Ox0000 0000),但是内置SRAM的内容依旧可以从起始地址(Ox2000 0000)访问,即当内置SRAM被选为启动模式,启动地址和起始地址都可以访向内置SRAM.引导程序: 出厂后引导程序存放在系统存储器中,可以通过串口进行ISР编程。4.2 解锁当主控芯片由于错误的程序导致芯片锁定时,可以通过按键操作进入ISP下载模式。进入ISP下载模式后,进行全片擦除或者下载一个新的空工程即可完成解锁。务必需要注意的是不能使用导致芯片锁定的程序进行解锁操作。5. 适合于多种应用场合:工业控制小型 PLC家电控制指纹识别打印机消防监控电梯主控断路器电池管理不间断电源LED 面板控制GPS 追踪器通信转换模块
一、 设计目标学习常见的SLAM知识,使用Cartographer算法实现二维栅格化地图的建立,并进行优化和测试。二、 技术要求查找建图相关资料,了解常用的激光SLAM算法;安装Linux系统,建议Ubuntu18.04;安装ROS环境并学习其基本操作;完成谷歌Cartographer算法建图环境搭建;使用Cartagrapher算法进行建图测试;学习算法原理,对算法进行优化及测试。三、 设计方案1. 激光SLAM简介SLAM (simultaneous localization and mapping) , 即时定位与地图构建,或称并发建图与定位。问题可以描述为:将一个机器人放入未知环境中的未知位置,是否有办法让机器人一边移动一边逐步描绘出此环境完全的地图,所谓完全的地图(a consistent map)是指不受障碍行进到房间可进入的每个角落。近年来,智能机器人技术在世界范围内得到快速发展。从室内、外搬运机器人,到自动驾驶汽车,再到空中无人机、水下探测机器人等,智能机器人的运用都得到了巨大突破。激光雷达已经被证明在低照度、少纹理等环境中更加有效,可以提供高信噪比的观测数据,精度高,测量距离远,可以准确获得目标的三维信息。激光SLAM技术相对成熟,在工业 AGV、无人驾驶领域已经得到广泛应用。激光SLAM利用二维激光测距仪或者三维激光测距仪对场景进行感知,利用返回的点云数据估计车辆的运动,并输出场景建模的结果。激光SLAM的工作原理也可以分为前端和后端2个部分,前端用于获取扫描数据,通过帧间点云的匹配估计车辆的运动关系,后端用于进行优化计算,闭环检测以及场景建模的输出等。在前端计算中,常用的点云匹配方法有迭代最近邻(Iterative Closest Point, ICP)算法及其变种算法,如PI-IC,相关性扫描匹配方法 (Correlation Scan Match, CSM),特征匹配法[8]和梯度优化方法等,在后端优化方法中,常用的方法有基于滤波器的方法和基于图优化的方法等。目前常见 的 二 维 激 光SLAM方 法 有:Gmapping-SLAM, Hector-SLAM,Karto SLAM和 Cartographer等,三 维 激 光SLAM方 法有LOAM,LeGO-LOAM和 MC2SLAM等。本次我们主要以谷歌开源的Cartographer建图算法进行相关的算法测试与改进。2. Cartographer简介与使用1) Cartographer简介2016年10月5日,谷歌宣布开放一个名为cartographer的即时定位与地图建模库,开发人员可以使用该库实现机器人在二维或三维条件下的定位及建图功能。cartograhper的设计目的是在计算资源有限的情况下,实时获取相对较高精度的2D地图。考虑到基于模拟策略的粒子滤波方法在较大环境下对内存和计算资源的需求较高,cartographer采用基于图网络的优化方法。目前cartographer主要基于激光雷达来实现SLAM,谷歌希望通过后续的开发及社区的贡献支持更多的传感器和机器人平台,同时不断增加新的功能。首先是对整个功能包的安装过程cartographer功能包已经与ROS集成,现在已经提供二进制安装包,本次采用源码编译的方式进行安装。为了不与已有功能包冲突,最好为cartographer专门创建一个工作空间,这里我们新创建了一个工作空间google_ws,然后使用如下步骤下载源码并完成编译。安装工具 可以使用如下命令安装工具:$ sudo apt-get update $ sudo apt-get install -y python-wstool python-rosdep ninja-build初始化工作空间 使用如下命令初始化工作空间:$ cd google_ws $ wstool init src加入cartographer_ros.rosinstall并更新依赖 命令如下:$ wstool merge -t src https://raw.githubusercontent.com/googlecartographer/cartographer_ros/master/cartographer_ros.rosinstall $ wstool update -t src安装依赖并下载cartographer相关功能包 命令如下:$ rosdep update $ rosdep install --from-paths src --ignore-src --rosdistro=${ROS_DISTRO} -y编译并安装 命令如下$ catkin_make_isolated --install --use-ninja $ source install_isolated/setup.bash如果下载服务器无法连接,也可以使用如下命令修改ceres-solver源码的下载地址为https://github.com/ceres-solver/ceres-solver.git$ gedit google_ws/src/.rosinstall改完成后重新运行编译安装的命令,如果没有出错,则cartographer的相关功能包安装成功。2) 官方demo的演示首先,下载官方提供的2D Cartographer功能包,复现并测试功能包的运行情况。$ wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_2d/cartographer_paper_deutsches_museum.bag接着,运行Cartographer的demo文件,复现该文件的建图功能。如下图3-1、3-2所示:$ roslaunch cartographer_ros demo_backpack_2d.launch bag_filename:=${HOME}/Downloads/cartographer_paper_deutsches_museum.bag图3-1图3-2另起终端,输入下列指令,如图3-3查看该建图功能中订阅的话题:$ rostopic list图3-3另起一个终端,查看该工程的tf配置,如下图3-4所示:$ rosrun rqt_tf_tree rqt_tf_tree另起终端,输入下列指令,查看该建图功能运行的相关节点,如图3-5所示:$ rosrun rqt_graph rqt_graph图3-53. 阿克曼模型测试通过对官方功能包的功能复现,我们可以更好的学习到Cartographer与传统2D建图算法相比的优缺点与异同。所以我们将五个关键任务中第一部分在ros中搭建的阿克曼运动模型应用起来,通过配置其相关参数,使他可以使用Cartographer在仿真环境下进行相关的建图与导航功能的测试,加深对第一部分阿克曼运动的理解,同时也强化Cartographer在阿克曼运动中的实际建图效果。1) SLAM建图首先,需要对谷歌Cartographer建图功能包中相关的数据进行一些配置,由于普通用的基本为2D或者3D激光雷达,如我的机器人使用2D激光,这里按照这个进行简介,我们移植到自己机器人需做三件事:第一件:一定要把Cartography和自己ROS 工作空间隔离开,不然存在问题,两个不是用相同编译器进行。第二件:更改demo_revo_lds.launch使其匹配自己的机器人第三件:根据自己机器人配置的TF结构对cartography的配置文件进行更改,这里主要会更改lua脚本,这里使用revo_lds.lua。更改demo_revo_lds.launch,这里主要删除不需要配置,如跑bag的节点和更改我们自己发布的2D激光雷达的数据,更改后的如下:<launch> <param name="/use_sim_time" value="false" /> <node name="cartographer_node" pkg="cartographer_ros" type="cartographer_node" args=" -configuration_directory $(find cartographer_ros)/configuration_files -configuration_basename revo_lds.lua" output="screen"> <remap from="scan" to="scan" /> </node> <node name="cartographer_occupancy_grid_node" pkg="cartographer_ros" type="cartographer_occupancy_grid_node" args="-resolution 0.05" /> <node name="rviz" pkg="rviz" type="rviz" required="true" args="-d $(find cartographer_ros)/configuration_files/demo_2d.rviz" /> </launch>更改revo_lds.lua主要也是对我们没用到的配置进行删除处理,这里主要看我们发布的坐标系更改后如下:include "map_builder.lua" include "trajectory_builder.lua" options = { map_builder = MAP_BUILDER, trajectory_builder = TRAJECTORY_BUILDER, map_frame = "map", tracking_frame = "laser_link", published_frame = "laser_link", odom_frame = "odom", provide_odom_frame = true, publish_frame_projected_to_2d = false, use_pose_extrapolator = true, use_odometry = false, use_nav_sat = false, use_landmarks = false, num_laser_scans = 1, num_multi_echo_laser_scans = 0, num_subdivisions_per_laser_scan = 1, num_point_clouds = 0, lookup_transform_timeout_sec = 0.2, submap_publish_period_sec = 0.3, pose_publish_period_sec = 5e-3, trajectory_publish_period_sec = 30e-3, rangefinder_sampling_ratio = 1., odometry_sampling_ratio = 1., fixed_frame_pose_sampling_ratio = 1., imu_sampling_ratio = 1., landmarks_sampling_ratio = 1., } MAP_BUILDER.use_trajectory_builder_2d = true TRAJECTORY_BUILDER_2D.submaps.num_range_data = 35 TRAJECTORY_BUILDER_2D.min_range = 0.3 TRAJECTORY_BUILDER_2D.max_range = 8. TRAJECTORY_BUILDER_2D.missing_data_ray_length = 1. TRAJECTORY_BUILDER_2D.use_imu_data = false TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.linear_search_window = 0.1 TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.translation_delta_cost_weight = 10. TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.rotation_delta_cost_weight = 1e-1 POSE_GRAPH.optimization_problem.huber_scale = 1e2 POSE_GRAPH.optimize_every_n_nodes = 35 POSE_GRAPH.constraint_builder.min_score = 0.65 return options有些比较明了的参数根据自己的要求进行更改,其他的我们暂时默认就好。 配置完成后回到google_ws路径下,使用如下命令再次编译:$ catkin_make_isolated --install --use-ninja打开仿真环境下的gazebo可视化界面,加载雷达和相关的传感器数据,如下图3-6所示:$ roslaunch bringup ares_gazebo_rviz.launch图3-6启动键盘控制:$ rosrun ares_description keyboard_teleop.py运行cartographer的建图功能,操纵键盘开始建图,如图3-7、3-8、3-9所示:$ roslaunch cartographer_ros demo_revo_lds.launch图3-7图3-8图3-9建图完成后,运行下列程序,执行保存地图的功能,为后续的导航提供所需地图,如图3-10所示:$ rosrun map_server map_saver -f ~/map图3-102) SLAM导航上述的建图完成后,我们测试一下阿克曼模型的导航功能,考虑到阿克曼模型和真车类似,base_local_planner 和dwa_local_planner不适应阿克曼,所以建图的过程我们选用teb算法进行仿真,打开仿真环境下的gazebo可视化界面,如图3-11,加载雷达和相关的传感器数据:$ roslaunch bringup ares_gazebo_rviz.launch 图3-11首先我们查看导航功能的move_base.launch文件的相关配置:<launch> <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen"> <rosparam file="$(find bringup)/param/costmap_common_params.yaml" command="load" ns="global_costmap" /> <rosparam file="$(find bringup)/param/costmap_common_params.yaml" command="load" ns="local_costmap" /> <rosparam file="$(find bringup)/param/local_costmap_params.yaml" command="load" /> <rosparam file="$(find bringup)/param/global_costmap_params.yaml" command="load" /> <rosparam file="$(find bringup)/param/teb_local_planner_params.yaml" command="load" /> <rosparam file="$(find bringup)/param/move_base_params.yaml" command="load" /> <param name="base_local_planner" value="teb_local_planner/TebLocalPlannerROS" /> <!--<param name="controller_frequency" value="10" /> <param name="controller_patiente" value="15.0"/>--> </node> <node name="map_server" pkg="map_server" type="map_server" args="$(find bringup)/map/map.yaml" output="screen"> <param name="frame_id" value="map"/> </node> <!--<node pkg="tf" type="static_transform_publisher" name="odom_to_map" args="0 0 0 0 0 0 1 /odom /map 100" />--> <!--<include file="$(find bringup)/launch/robot_amcl.launch.xml" />--> <node name="nav_sim" pkg="ares_description" type="nav_sim.py" > </node> <arg name="use_map_topic" default="True"/> <arg name="scan_topic" default="/scan"/> <arg name="initial_pose_x" default="-0.5"/> <arg name="initial_pose_y" default="0.0"/> <arg name="initial_pose_a" default="0.0"/> <arg name="odom_frame_id" default="odom"/> <arg name="base_frame_id" default="base_footprint"/> <arg name="global_frame_id" default="map"/> <node pkg="amcl" type="amcl" name="amcl"> <param name="use_map_topic" value="$(arg use_map_topic)"/> <!-- Publish scans from best pose at a max of 10 Hz --> <param name="odom_model_type" value="diff"/> <param name="odom_alpha5" value="0.1"/> <param name="gui_publish_rate" value="10.0"/> <param name="laser_max_beams" value="810"/> <param name="laser_max_range" value="-1"/> <param name="min_particles" value="500"/> <param name="max_particles" value="5000"/> <param name="kld_err" value="0.05"/> <param name="kld_z" value="0.99"/> <param name="odom_alpha1" value="0.2"/> <param name="odom_alpha2" value="0.2"/> <!-- translation std dev, m --> <param name="odom_alpha3" value="0.2"/> <param name="odom_alpha4" value="0.2"/> <param name="laser_z_hit" value="0.5"/> <param name="laser_z_short" value="0.05"/> <param name="laser_z_max" value="0.05"/> <param name="laser_z_rand" value="0.5"/> <param name="laser_sigma_hit" value="0.2"/> <param name="laser_lambda_short" value="0.1"/> <param name="laser_model_type" value="likelihood_field"/> <!-- <param name="laser_model_type" value="beam"/> --> <param name="laser_likelihood_max_dist" value="2.0"/> <param name="update_min_d" value="0.1"/> <param name="update_min_a" value="0.2"/> <param name="odom_frame_id" value="$(arg odom_frame_id)"/> <param name="base_frame_id" value="$(arg base_frame_id)"/> <param name="global_frame_id" value="$(arg global_frame_id)"/> <param name="resample_interval" value="1"/> <!-- Increase tolerance because the computer can get quite busy --> <param name="transform_tolerance" value="1.0"/> <param name="recovery_alpha_slow" value="0.0"/> <param name="recovery_alpha_fast" value="0.0"/> <param name="initial_pose_x" value="$(arg initial_pose_x)"/> <param name="initial_pose_y" value="$(arg initial_pose_y)"/> <param name="initial_pose_a" value="$(arg initial_pose_a)"/> <remap from="/scan" to="$(arg scan_topic)"/> <remap from="/tf_static" to="/tf_static"/> </node> </launch>该部分加载了导航必要的全局与局部规划的相关配置参数以及代价地图的相关配置参数,并且考虑到没有GPS为小车做定位,选用amcl对阿克曼小车进行更加精准的定位。重启一个终端,运行下列命令,如图3-12:$ roslaunch bringup move_base.launch图3-12使用rviz中的2D Nav Goal发布目标点,Ares阿克曼小车就会自动导航到该点,效果如下图3-13、3-14、3-15所示:图3-13图3-14图3-15四、 总结与展望至此,cartographer的官方功能包的复现和对自己的阿克曼模型的建图验证,可以证明该建图算法的建图效果要优于gmapping等传统的2D建图效果,主要体现在cartographer的回环检测功能,在建图过程中我们可以发现,该算法可以不断地对时所建的地图进行不断地调整和优化,这是传统普通的slam算法所没有的功能;后续的时间中我们将考虑融合搭建在阿克曼车上的rgbd相机,实现相机+激光雷达融合的rtabmap slam算法,并不断优化cartographer功能包的相关参数以及阿克曼的相关配置。在导航方面,将加入第四部分中优化后的A*算法来进行相关的导航功能。以及控制阿克曼智能车实现导航过程中的物体目标识别和车道线检测与巡线的功能,并实现与上位机的实时通讯。
1. Serial Studio前言分享一个开源的串口项目——Serial Studio,这是一个强大的数据可视化软件,支持串口通信,串口终端,网络通信 TCP/UDP,MQTT通信协议。这个项目遵循MIT协议,所以是可以商用的。Serial Studio 允许您轻松地显示、处理和导出嵌入式项目中的数据。该应用程序能够与串行端口、网络套接字和 MQTT 代理进行交互。项目的主页地址:https://serial-studio.github.io/2. Serial Studio特点多个小部件使用 FFT 图表、多数据图、对数图、仪表、条形小部件等可视化您的数据。导出您的数据Serial Studio 可以根据从您的嵌入式设备接收到的数据实时生成 CSV 文件。数据完整性检查支持 CRC-8、CRC-16 和 CRC-32 校验和。有关更多信息,请查看此问题。项目编辑无需打开代码编辑器或阅读 wiki 即可轻松创建和编辑您的项目。3. Serial Studio下载安装源代码已经托管到Github上,项目地址:https://github.com/Serial-Studio/Serial-Studio这个项目已经累积到2.8K的star了 ,这个项目的源码是完全开发的,所以非常方便进行二次开发,增加一些自己想要的功能。编译本项目的唯一要求是在你的电脑系统中安装 QT , 本项目编译支持 Qt 5.15。在GNU/Linux系统上,还需要安装libgl1-mesa-dev才能编译应用程序。已使用的Qt模块的完整列表:Qt SVGQt QuickQt WidgetsQt NetworkingQt Serial PortQt Print SupportQt Quick WidgetsQt Quick Controls 2这个项目的具体构建过程可以参考GitHub上的构建说明,基于Python环境。如果想要直接使用软件的话,直接进行下载安装即可。下载地址:https://github.com/Serial-Studio/Serial-Studio/releases这里我下载并安装了软件,进行了简单的试用,整体来说,很不错。安装后主界面4. Serial Studio使用这里需要加载一个json文件,对于控制面板里的每一个组件,需要在json中配置好,然后通信协议发送特定格式的数据,就可以将数据可视化地显示出来了。4.1 配置文件json文件配置,打开Serial Studio,点击json编辑器设置json解析格式,首先添加组别,包含帧头、分隔符、帧尾以及数据显示格式,记得申请保存哟!🤣🤣🤣下面是两组数据state1,state2下面就是配置的json文件{ "frameEnd": "*/", "frameStart": "/*KAANSATQRO,", "groups": [ { "datasets": [ { "alarm": 0, "fft": false, "fftSamples": 1024, "graph": true, "led": true, "log": false, "max": 0, "min": 0, "title": "state1", "units": "", "value": "%1", "widget": "" }, { "alarm": 0, "fft": false, "fftSamples": 1024, "graph": true, "led": true, "log": false, "max": 0, "min": 0, "title": "state2", "units": "", "value": "%2", "widget": "" } ], "title": "led", "widget": "" } ], "separator": ",", "title": "test" } 4.2 数据来源采用串口在线输入格式需与上面一致/*KAANSATQRO,0,0*/显示效果采用csv离线导入部分数据截图演示效果:
1.0 mpu6050此图转载钦源盛数码专营店本篇通过Renesas RA6M4开发板采用I2C读取mpu6050传感器的角加速度,角速度和温度示例程序演示。1.1 mpu6050介绍MPU6050是一种非常流行的空间运动传感器芯片,可以获取器件当前的三个加速度分量和三个旋转角速度。由于其体积小巧,功能强大,精度较高,不仅被广泛应用于工业,同时也是航模爱好者的神器,被安装在各类飞行器上驰骋蓝天。1.2 mpu6050特点使用芯片:MPU-6050供电电源:3-5V(内部低压差稳压)通信方式:标准lIC通信协议芯片内置16BITAD转换器,16位数据输出陀螺仪范围:±250 500 1000 2000 °/s加速度范围:±2±4±8±16G温度范围:-20℃~60℃采用沉金PCB,机器焊接工艺保证质量引脚间距2.54MM需在气体环境中工作,不可测量液体和反接电源😅😅😅尺寸大小如下:1.3 mpu6050应用运动感测游戏现实增强行人导航器“零触控”手势用户接口姿势快捷方式认证电子稳像(EIS: Electronic lmage Stabilization )光学稳像(Ols: Optical lmage Stabilization )2. RT-theard配置2.1 硬件需求1、需要mpu6050采集气体环境下的气压和温度,I2C通讯接线SDA—p504;SCL—p506,不需要关注地址后面库自带配置了,与ssd1306不同实现功能:采用I2C读取mpu6050传感器的角加速度,角速度和温度示例2、RA6M4开发板3、USB下载线,ch340串口和附带6根母母线,rx—p613;tx—p6142.2 软件配置Renesas RA6M4开发板环境配置参照:【基于 RT-Thread Studio的CPK-RA6M4 开发板环境搭建】1、新建项目RA6M4-mpu6050工程2、点击RT-theard Setting,在软件包下添加软件包,然后搜索mpu相关软件支持包,点击添加即可,然后出现对应包。3、配置ssd306,右键选择配置项4、在软件包中开启示例程序。5、在硬件中,启动I2C,设置端口SDA—p505;SCL—p5066、全部保存刚刚的配置,更新当前配置文件保存完是灰色,没有保存是蓝色。3. 代码分析1、刚刚加载软件包在packages文件夹下,mpu6xxx.c代码更改为如下(或者头文件添加#include "bsp_api.h",否则会报错unitx_t,根据提示全部改为rt_unitx_t也OK,下面是第二种方法,增加了手动校准)😅😅😅mpu6xxx.c/* * Copyright (c) 2006-2022, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-10-23 flybreak the first version * 2021-09-09 scratch-er added setting and getting sensor offsets */ #include <rtthread.h> #include <rtdevice.h> #include <string.h> #include <stdlib.h> #define DBG_TAG "mpu6xxx" #define DBG_LVL DBG_INFO #include <rtdbg.h> #include "mpu6xxx.h" #include "mpu6xxx_reg.h" #ifdef PKG_USING_MPU6XXX_MAG #include "ak8963_reg.h" #endif #define MPU6XXX_ACCEL_SEN (16384) #define MPU6XXX_GYRO_SEN (1310) #define MPU60X0_SPI_MAX_SPEED (1000 * 1000) #define MPU60X0_TEMP_SEN (340) #define MPU60X0_TEMP_OFFSET (36.5) #define MPU6500_TEMP_SEN (333.87) #define MPU6500_TEMP_OFFSET (21) // MAG #define AK8963_RANGE (4912) #define AK8963_FULLSCALE (32760) /** * This function writes the value of the register for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param data value to write * * @return the writing status, RT_EOK reprensents writing the value of the register successfully. */ static rt_err_t mpu6xxx_write_reg(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t data) { rt_int8_t res = 0; #ifdef RT_USING_I2C struct rt_i2c_msg msgs; rt_uint8_t buf[2] = {reg, data}; #endif if (dev->bus->type == RT_Device_Class_I2CBUS) { #ifdef RT_USING_I2C msgs.addr = dev->i2c_addr; /* slave address */ msgs.flags = RT_I2C_WR; /* write flag */ msgs.buf = buf; /* Send data pointer */ msgs.len = 2; if (rt_i2c_transfer((struct rt_i2c_bus_device *)dev->bus, &msgs, 1) == 1) { res = RT_EOK; } else { res = -RT_ERROR; } #endif } else { #ifdef RT_USING_SPI res = rt_spi_send_then_send((struct rt_spi_device *)dev->bus, &reg, 1, &data, 1); #endif } return res; } /** * This function reads the value of registers for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param len number of register * @param buf read data pointer * * @return the reading status, RT_EOK reprensents reading the value of registers successfully. */ static rt_err_t mpu6xxx_read_regs(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf) { rt_int8_t res = 0; #ifdef RT_USING_I2C struct rt_i2c_msg msgs[2]; #endif #ifdef RT_USING_SPI rt_uint8_t tmp; #endif if (dev->bus->type == RT_Device_Class_I2CBUS) { #ifdef RT_USING_I2C msgs[0].addr = dev->i2c_addr; /* Slave address */ msgs[0].flags = RT_I2C_WR; /* Write flag */ msgs[0].buf = &reg; /* Slave register address */ msgs[0].len = 1; /* Number of bytes sent */ msgs[1].addr = dev->i2c_addr; /* Slave address */ msgs[1].flags = RT_I2C_RD; /* Read flag */ msgs[1].buf = buf; /* Read data pointer */ msgs[1].len = len; /* Number of bytes read */ if (rt_i2c_transfer((struct rt_i2c_bus_device *)dev->bus, msgs, 2) == 2) { res = RT_EOK; } else { res = -RT_ERROR; } #endif } else { #ifdef RT_USING_SPI //The first bit of the first byte contains the Read/Write bit and indicates the Read (1) or Write (0) operation. tmp = reg | 0x80; res = rt_spi_send_then_recv((struct rt_spi_device *)dev->bus, &tmp, 1, buf, len); #endif } return res; } /** * This function writes a bit value of registers for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param bit the position of the register * @param data value to write * * @return the writing status, RT_EOK reprensents writing a bit value of registers successfully. */ static rt_err_t mpu6xxx_write_bit(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t bit, rt_uint8_t data) { rt_uint8_t byte; rt_err_t res; res = mpu6xxx_read_regs(dev, reg, 1, &byte); if (res != RT_EOK) { return res; } byte = (data != 0) ? (byte | (1 << bit)) : (byte & ~(1 << bit)); return mpu6xxx_write_reg(dev, reg, byte); } /** * This function reads a bit value of registers for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param bit the position of the register * @param data read data pointer * * @return the reading status, RT_EOK reprensents reading a bit value of registers successfully. */ static rt_err_t mpu6xxx_read_bit(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t bit, rt_uint8_t *data) { rt_uint8_t byte; rt_err_t res; res = mpu6xxx_read_regs(dev, reg, 1, &byte); if (res != RT_EOK) { return res; } *data = byte & (1 << bit); return RT_EOK; } /** * This function writes multi-bit value of registers for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param start_bit the start position of the register * @param len number of bits to write * @param data value to write * * @return the writing status, RT_EOK reprensents writing multi-bit value of registers successfully. */ static rt_err_t mpu6xxx_write_bits(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t start_bit, rt_uint8_t len, rt_uint8_t data) { rt_uint8_t byte, mask; rt_err_t res; res = mpu6xxx_read_regs(dev, reg, 1, &byte); if (res != RT_EOK) { return res; } mask = ((1 << len) - 1) << (start_bit - len + 1); data <<= (start_bit - len + 1); // shift data into correct position data &= mask; // zero all non-important bits in data byte &= ~(mask); // zero all important bits in existing byte byte |= data; // combine data with existing byte return mpu6xxx_write_reg(dev, reg, byte); } /** * This function reads multi-bit value of registers for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param start_bit the start position of the register * @param len number of bits to write * @param data read data pointer * * @return the reading status, RT_EOK reprensents reading multi-bit value of registers successfully. */ static rt_err_t mpu6xxx_read_bits(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t start_bit, rt_uint8_t len, rt_uint8_t *data) { rt_uint8_t byte, mask; rt_err_t res; res = mpu6xxx_read_regs(dev, reg, 1, &byte); if (res != RT_EOK) { return res; } mask = ((1 << len) - 1) << (start_bit - len + 1); byte &= mask; byte >>= (start_bit - len + 1); *data = byte; return RT_EOK; } // MAG #ifdef PKG_USING_MPU6XXX_MAG #define MAG_READ_DELAY_TIME 50 static void mpu92_mag_write_reg(struct mpu6xxx_device *dev, rt_uint8_t addr, rt_uint8_t data) { rt_uint8_t status = 0; rt_uint32_t timeout = MAG_READ_DELAY_TIME; mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV4_ADDR, AK8963_I2C_ADDR); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV4_REG, addr); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV4_DO, data); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV4_CTRL, MPU6500_I2C_SLVx_EN); do { mpu6xxx_read_regs(dev, MPU6XXX_RA_I2C_MST_STATUS, 1, &status); rt_thread_mdelay(1); } while (((status & MPU6500_I2C_SLV4_DONE) == 0) && (timeout--)); } #endif // PKG_USING_MPU6XXX_MAG /** * This function gets the raw data of the accelerometer * * @param dev the pointer of device driver structure * @param accel the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ static rt_err_t mpu6xxx_get_accel_raw(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *accel) { rt_uint8_t buffer[6]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_ACCEL_XOUT_H, 6, buffer); if (res != RT_EOK) { return res; } accel->x = ((rt_uint16_t)buffer[0] << 8) + buffer[1]; accel->y = ((rt_uint16_t)buffer[2] << 8) + buffer[3]; accel->z = ((rt_uint16_t)buffer[4] << 8) + buffer[5]; return RT_EOK; } /** * This function gets the raw data of the gyroscope * * @param dev the pointer of device driver structure * @param gyro the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ static rt_err_t mpu6xxx_get_gyro_raw(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *gyro) { rt_uint8_t buffer[6]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_GYRO_XOUT_H, 6, buffer); if (res != RT_EOK) { return res; } gyro->x = ((rt_uint16_t)buffer[0] << 8) + buffer[1]; gyro->y = ((rt_uint16_t)buffer[2] << 8) + buffer[3]; gyro->z = ((rt_uint16_t)buffer[4] << 8) + buffer[5]; return RT_EOK; } #ifdef PKG_USING_MPU6XXX_MAG /** * This function gets the raw data of the magnetometer * * @param dev the pointer of device driver structure * @param mag the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ static rt_err_t mpu6xxx_get_mag_raw(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *mag) { rt_uint8_t buffer[8]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_EXT_SENS_DATA_00, 8, buffer); if (res != RT_EOK) { return res; } mag->x = ((rt_uint16_t)buffer[2] << 8) + buffer[1]; mag->y = ((rt_uint16_t)buffer[4] << 8) + buffer[3]; mag->z = ((rt_uint16_t)buffer[6] << 8) + buffer[5]; return RT_EOK; } #endif /** * This function gets the raw data of the temperature * * @param dev the pointer of device driver structure * @param temp read data pointer * * @return the reading status, RT_EOK reprensents reading the data successfully. */ static rt_err_t mpu6xxx_get_temp_raw(struct mpu6xxx_device *dev, rt_int16_t *temp) { rt_uint8_t buffer[2]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_TEMP_OUT_H, 2, buffer); if (res != RT_EOK) { return res; } *temp = ((rt_uint16_t)buffer[0] << 8) + buffer[1]; return RT_EOK; } /** * This function gets mpu6xxx parameters. * * @param dev the pointer of device driver structure * @param cmd Configuration item * @param param read data pointer * * @return the reading status, RT_EOK reprensents reading the data successfully. */ static rt_err_t mpu6xxx_get_param(struct mpu6xxx_device *dev, enum mpu6xxx_cmd cmd, rt_uint16_t *param) { rt_uint8_t data = 0; rt_err_t res = RT_EOK; RT_ASSERT(dev); switch (cmd) { case MPU6XXX_GYRO_RANGE: /* Gyroscope full scale range */ res = mpu6xxx_read_bits(dev, MPU6XXX_RA_GYRO_CONFIG, MPU6XXX_GCONFIG_FS_SEL_BIT, MPU6XXX_GCONFIG_FS_SEL_LENGTH, &data); *param = data; break; case MPU6XXX_ACCEL_RANGE: /* Accelerometer full scale range */ res = mpu6xxx_read_bits(dev, MPU6XXX_RA_ACCEL_CONFIG, MPU6XXX_ACONFIG_AFS_SEL_BIT, MPU6XXX_ACONFIG_AFS_SEL_LENGTH, &data); *param = data; break; case MPU6XXX_DLPF_CONFIG: /* Digital Low Pass Filter */ res = mpu6xxx_read_bits(dev, MPU6XXX_RA_CONFIG, MPU6XXX_CFG_DLPF_CFG_BIT, MPU6XXX_CFG_DLPF_CFG_LENGTH, &data); *param = data; break; case MPU6XXX_SAMPLE_RATE: /* Sample Rate */ /* Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV) */ res = mpu6xxx_read_bits(dev, MPU6XXX_RA_CONFIG, MPU6XXX_CFG_DLPF_CFG_BIT, MPU6XXX_CFG_DLPF_CFG_LENGTH, &data); if (res != RT_EOK) { break; } if (data == 0 || data == 7) /* dlpf is disable */ { res = mpu6xxx_read_regs(dev, MPU6XXX_RA_SMPLRT_DIV, 1, &data); *param = 8000 / (data + 1); } else /* dlpf is enable */ { res = mpu6xxx_read_regs(dev, MPU6XXX_RA_SMPLRT_DIV, 1, &data); *param = 1000 / (data + 1); } break; case MPU6XXX_SLEEP: /* sleep mode */ res = mpu6xxx_read_bit(dev, MPU6XXX_RA_PWR_MGMT_1, MPU6XXX_PWR1_SLEEP_BIT, &data); *param = data; break; } return res; } /** * This function set mpu6xxx parameters. * * @param dev the pointer of device driver structure * @param cmd Configuration item * @param param Configuration item parameter * * @return the setting status, RT_EOK reprensents setting the parameter successfully. */ rt_err_t mpu6xxx_set_param(struct mpu6xxx_device *dev, enum mpu6xxx_cmd cmd, rt_uint16_t param) { rt_uint8_t data = 0; rt_err_t res = RT_EOK; RT_ASSERT(dev); switch (cmd) { case MPU6XXX_GYRO_RANGE: /* Gyroscope full scale range */ res = mpu6xxx_write_bits(dev, MPU6XXX_RA_GYRO_CONFIG, MPU6XXX_GCONFIG_FS_SEL_BIT, MPU6XXX_GCONFIG_FS_SEL_LENGTH, param); dev->config.gyro_range = param; break; case MPU6XXX_ACCEL_RANGE: /* Accelerometer full scale range */ res = mpu6xxx_write_bits(dev, MPU6XXX_RA_ACCEL_CONFIG, MPU6XXX_ACONFIG_AFS_SEL_BIT, MPU6XXX_ACONFIG_AFS_SEL_LENGTH, param); dev->config.accel_range = param; break; case MPU6XXX_DLPF_CONFIG: /* Digital Low Pass Filter */ res = mpu6xxx_write_bits(dev, MPU6XXX_RA_CONFIG, MPU6XXX_CFG_DLPF_CFG_BIT, MPU6XXX_CFG_DLPF_CFG_LENGTH, param); break; case MPU6XXX_SAMPLE_RATE: /* Sample Rate = 16-bit unsigned value. Sample Rate = [1000 - 4]HZ when dlpf is enable Sample Rate = [8000 - 32]HZ when dlpf is disable */ //Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV) res = mpu6xxx_read_bits(dev, MPU6XXX_RA_CONFIG, MPU6XXX_CFG_DLPF_CFG_BIT, MPU6XXX_CFG_DLPF_CFG_LENGTH, &data); if (res != RT_EOK) { break; } if (data == 0 || data == 7) /* dlpf is disable */ { if (param > 8000) data = 0; else if (param < 32) data = 0xFF; else data = 8000 / param - 1; } else /* dlpf is enable */ { if (param > 1000) data = 0; else if (param < 4) data = 0xFF; else data = 1000 / param - 1; } res = mpu6xxx_write_reg(dev, MPU6XXX_RA_SMPLRT_DIV, data); break; case MPU6XXX_SLEEP: /* Configure sleep mode */ res = mpu6xxx_write_bit(dev, MPU6XXX_RA_PWR_MGMT_1, MPU6XXX_PWR1_SLEEP_BIT, param); break; } return res; } /** * This function gets the data of the accelerometer, unit: mg(mm/s^2) * * @param dev the pointer of device driver structure * @param accel the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ rt_err_t mpu6xxx_get_accel(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *accel) { struct mpu6xxx_3axes tmp; rt_uint16_t sen; rt_err_t res; res = mpu6xxx_get_accel_raw(dev, &tmp); if (res != RT_EOK) { return res; } sen = MPU6XXX_ACCEL_SEN >> dev->config.accel_range; accel->x = (rt_int32_t)tmp.x * 1000 / sen; accel->y = (rt_int32_t)tmp.y * 1000 / sen; accel->z = (rt_int32_t)tmp.z * 1000 / sen; return RT_EOK; } /** * This function gets the data of the gyroscope, unit: deg/10s * Here deg/10s means 10 times higher precision than deg/s. * * @param dev the pointer of device driver structure * @param gyro the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ rt_err_t mpu6xxx_get_gyro(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *gyro) { struct mpu6xxx_3axes tmp; rt_uint16_t sen; rt_err_t res; res = mpu6xxx_get_gyro_raw(dev, &tmp); if (res != RT_EOK) { return res; } sen = MPU6XXX_GYRO_SEN >> dev->config.gyro_range; gyro->x = (rt_int32_t)tmp.x * 100 / sen; gyro->y = (rt_int32_t)tmp.y * 100 / sen; gyro->z = (rt_int32_t)tmp.z * 100 / sen; return RT_EOK; } #ifdef PKG_USING_MPU6XXX_MAG /** * This function gets the data of the magnetometer, unit: uT * * @param dev the pointer of device driver structure * @param gyro the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ rt_err_t mpu6xxx_get_mag(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *mag) { struct mpu6xxx_3axes tmp; rt_err_t res; res = mpu6xxx_get_mag_raw(dev, &tmp); if (res != RT_EOK) { return res; } mag->x = ((rt_int32_t)tmp.x * AK8963_RANGE) / AK8963_FULLSCALE; mag->y = ((rt_int32_t)tmp.y * AK8963_RANGE) / AK8963_FULLSCALE; mag->z = ((rt_int32_t)tmp.z * AK8963_RANGE) / AK8963_FULLSCALE; return RT_EOK; } #endif /** * This function gets the data of the temperature, unit: Centigrade * * @param dev the pointer of device driver structure * @param temp read data pointer * * @return the reading status, RT_EOK reprensents reading the data successfully. */ rt_err_t mpu6xxx_get_temp(struct mpu6xxx_device *dev, float *temp) { rt_int16_t tmp; rt_err_t res; res = mpu6xxx_get_temp_raw(dev, &tmp); if (res != RT_EOK) { return res; } if (dev->id == MPU6050_WHO_AM_I) { /* mpu60x0: Temperature in degrees C = (TEMP_OUT Register Value as a signed quantity)/340 + 36.53 */ *temp = (double)tmp / MPU60X0_TEMP_SEN + MPU60X0_TEMP_OFFSET; } else { /* mpu6500: ((TEMP_OUT - RoomTemp_Offset)/Temp_Sensitivity)+ 21degC */ *temp = (double)tmp / MPU6500_TEMP_SEN + MPU6500_TEMP_OFFSET; } return RT_EOK; } /** * This function sets the offset of the accelerometer * * @param dev the pointer of device driver structure * @param offset the pointer of 3axes structure of offsets * * @return the setting status, RT_EOK reprensents setting the offsets successfully. */ rt_err_t mpu6xxx_set_accel_offset(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *offset) { rt_err_t res=0; res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_XA_OFFS_H, (offset->x)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_XA_OFFS_L_TC, (offset->x)&0x00ff); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_YA_OFFS_H, (offset->y)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_YA_OFFS_L_TC, (offset->y)&0x00ff); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_ZA_OFFS_H, (offset->z)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_ZA_OFFS_L_TC, (offset->z)&0x00ff); return res; } /** * This function gets the offset of the accelerometer * * @param dev the pointer of device driver structure * @param offset the pointer of 3axes structure of offsets * * @return the setting status, RT_EOK reprensents reading the offsets successfully. */ rt_err_t mpu6xxx_get_accel_offset(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *offset) { rt_uint8_t buffer[6]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_XA_OFFS_H, 6, buffer); if (res != RT_EOK) { return res; } offset->x = ((rt_uint16_t)buffer[0] << 8) + buffer[1]; offset->y = ((rt_uint16_t)buffer[2] << 8) + buffer[3]; offset->z = ((rt_uint16_t)buffer[4] << 8) + buffer[5]; return RT_EOK; } /** * This function sets the offset of the gyroscope * * @param dev the pointer of device driver structure * @param offset the pointer of 3axes structure of offsets * * @return the setting status, RT_EOK reprensents setting the offsets successfully. */ rt_err_t mpu6xxx_set_gyro_offset(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *offset) { rt_err_t res=0; res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_XG_OFFS_USRH, (offset->x)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_XG_OFFS_USRL, (offset->x)&0x00ff); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_YG_OFFS_USRH, (offset->y)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_YG_OFFS_USRL, (offset->y)&0x00ff); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_ZG_OFFS_USRH, (offset->z)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_ZG_OFFS_USRL, (offset->z)&0x00ff); return res; } /** * This function gets the offset of the gyroscope * * @param dev the pointer of device driver structure * @param offset the pointer of 3axes structure of offsets * * @return the setting status, RT_EOK reprensents reading the offsets successfully. */ rt_err_t mpu6xxx_get_gyro_offset(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *offset) { rt_uint8_t buffer[6]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_XG_OFFS_USRH, 6, buffer); if (res != RT_EOK) { return res; } offset->x = ((rt_uint16_t)buffer[0] << 8) + buffer[1]; offset->y = ((rt_uint16_t)buffer[2] << 8) + buffer[3]; offset->z = ((rt_uint16_t)buffer[4] << 8) + buffer[5]; return RT_EOK; } /** * This function initialize the mpu6xxx device. * * @param dev_name the name of transfer device * @param param the i2c device address for i2c communication, RT_NULL for spi * * @return the pointer of device driver structure, RT_NULL reprensents initialization failed. */ struct mpu6xxx_device *mpu6xxx_init(const char *dev_name, rt_uint8_t param) { struct mpu6xxx_device *dev = RT_NULL; rt_uint8_t reg = 0xFF, res = RT_EOK; RT_ASSERT(dev_name); dev = rt_calloc(1, sizeof(struct mpu6xxx_device)); if (dev == RT_NULL) { LOG_E("Can't allocate memory for mpu6xxx device on '%s' ", dev_name); goto __exit; } dev->bus = rt_device_find(dev_name); if (dev->bus == RT_NULL) { LOG_E("Can't find device:'%s'", dev_name); goto __exit; } if (dev->bus->type == RT_Device_Class_I2CBUS) { if (param != RT_NULL) { dev->i2c_addr = param; } else { /* find mpu6xxx device at address: 0x68 */ dev->i2c_addr = MPU6XXX_ADDRESS_AD0_LOW; if (mpu6xxx_read_regs(dev, MPU6XXX_RA_WHO_AM_I, 1, &reg) != RT_EOK) { /* find mpu6xxx device at address 0x69 */ dev->i2c_addr = MPU6XXX_ADDRESS_AD0_HIGH; if (mpu6xxx_read_regs(dev, MPU6XXX_RA_WHO_AM_I, 1, &reg) != RT_EOK) { LOG_E("Can't find device at '%s'!", dev_name); goto __exit; } } LOG_D("Device i2c address is:'0x%x'!", dev->i2c_addr); } } else if (dev->bus->type == RT_Device_Class_SPIDevice) { #ifdef RT_USING_SPI struct rt_spi_configuration cfg; cfg.data_width = 8; cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB; cfg.max_hz = MPU60X0_SPI_MAX_SPEED; /* Set spi max speed */ rt_spi_configure((struct rt_spi_device *)dev->bus, &cfg); #endif } else { LOG_E("Unsupported device:'%s'!", dev_name); goto __exit; } if (mpu6xxx_read_regs(dev, MPU6XXX_RA_WHO_AM_I, 1, &reg) != RT_EOK) { LOG_E("Failed to read device id!"); goto __exit; } dev->id = reg; switch (dev->id) { case MPU6050_WHO_AM_I: LOG_I("Find device: mpu6050!"); break; case MPU6500_WHO_AM_I: LOG_I("Find device: mpu6500!"); break; case MPU9250_WHO_AM_I: LOG_I("Find device: mpu9250!"); break; case ICM20608G_WHO_AM_I: case ICM20608D_WHO_AM_I: LOG_I("Find device: icm20608!"); break; case 0xFF: LOG_E("No device connection!"); goto __exit; default: LOG_W("Unknown device id: 0x%x!", reg); } res += mpu6xxx_get_param(dev, MPU6XXX_ACCEL_RANGE, &dev->config.accel_range); res += mpu6xxx_get_param(dev, MPU6XXX_GYRO_RANGE, &dev->config.gyro_range); res += mpu6xxx_write_bits(dev, MPU6XXX_RA_PWR_MGMT_1, MPU6XXX_PWR1_CLKSEL_BIT, MPU6XXX_PWR1_CLKSEL_LENGTH, MPU6XXX_CLOCK_PLL_XGYRO); res += mpu6xxx_set_param(dev, MPU6XXX_GYRO_RANGE, MPU6XXX_GYRO_RANGE_250DPS); res += mpu6xxx_set_param(dev, MPU6XXX_ACCEL_RANGE, MPU6XXX_ACCEL_RANGE_2G); res += mpu6xxx_set_param(dev, MPU6XXX_SLEEP, MPU6XXX_SLEEP_DISABLE); #ifdef PKG_USING_MPU6XXX_MAG mpu6xxx_write_reg(dev, MPU6XXX_RA_USER_CTRL, 0x20); mpu92_mag_write_reg(dev, AK8963_REG_CNTL2, 0x01); /* [0] Reset Device */ rt_thread_mdelay(1); mpu92_mag_write_reg(dev, AK8963_REG_CNTL1, 0x00); /* [1] Power-down mode */ mpu92_mag_write_reg(dev, AK8963_REG_CNTL1, 0x0F); /* [2] Fuse ROM access mode */ mpu92_mag_write_reg(dev, AK8963_REG_CNTL1, 0x00); /* [3] Power-down mode */ rt_thread_mdelay(1); // 100us mpu92_mag_write_reg(dev, AK8963_REG_CNTL1, 0x16); /* [4] 16bits and Continuous measurement mode 2 */ /* config mpu9250 i2c */ rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_MST_CTRL, 0x5D); rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV0_ADDR, AK8963_I2C_ADDR | 0x80); rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV0_REG, AK8963_REG_ST1); rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV0_CTRL, MPU6500_I2C_SLVx_EN | 8); rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV4_CTRL, 0x09); rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_MST_DELAY_CTRL, 0x81); #endif if (res == RT_EOK) { LOG_I("Device init succeed!"); } else { LOG_W("Error in device initialization!"); } return dev; __exit: if (dev != RT_NULL) { rt_free(dev); } return RT_NULL; } /** * This function releases memory * * @param dev the pointer of device driver structure */ void mpu6xxx_deinit(struct mpu6xxx_device *dev) { RT_ASSERT(dev); rt_free(dev); } static void mpu6xxx(int argc, char **argv) { static struct mpu6xxx_device *dev = RT_NULL; /* If the number of arguments less than 2 */ if (argc < 2) { rt_kprintf("\n"); rt_kprintf("mpu6xxx [OPTION] [PARAM]\n"); rt_kprintf(" probe <dev_name> Probe mpu6xxx by given name,dev_name such as i2c1 \n"); rt_kprintf(" sr <var> Set sample rate to var\n"); rt_kprintf(" var = [1000 - 4] when dlpf is enable\n"); rt_kprintf(" var = [8000 - 32] when dlpf is disable\n"); rt_kprintf(" gr <var> Set gyro range to var\n"); rt_kprintf(" var = [0 - 3] means [250 - 2000DPS]\n"); rt_kprintf(" ar <var> Set accel range to var\n"); rt_kprintf(" var = [0 - 3] means [2 - 16G]\n"); rt_kprintf(" sleep <var> Set sleep status\n"); rt_kprintf(" var = 0 means disable, = 1 means enable\n"); rt_kprintf(" read [num] read [num] times mpu6xxx\n"); rt_kprintf(" num default 5\n"); return ; } else if (!strcmp(argv[1], "read")) { struct mpu6xxx_3axes accel, gyro, mag; float temp; rt_uint16_t num = 5; if (dev == RT_NULL) { rt_kprintf("Please probe mpu6xxx first!\n"); return ; } if (argc == 3) { num = atoi(argv[2]); } while (num --) { mpu6xxx_get_accel(dev, &accel); mpu6xxx_get_gyro(dev, &gyro); mpu6xxx_get_mag(dev, &mag); mpu6xxx_get_temp(dev, &temp); rt_kprintf("accel.x = %4d mg, accel.y = %4d mg, accel.z = %4d mg, ", accel.x+50, accel.y, accel.z-800); rt_kprintf("gyro.x = %4d deg/10s, gyro.y = %4d deg/10s, gyro.z = %4d deg/10s, ", gyro.x-70, gyro.y+22, gyro.z-9); rt_kprintf("mag.x = %4d uT, mag.y = %4d uT, mag.z = %4d uT", mag.x, mag.y, mag.z); rt_kprintf("temp = %d.%d ℃\n", (int)(temp * 100) / 100, (int)(temp * 100) % 100); rt_thread_mdelay(100); } } else if (argc == 3) { if (!strcmp(argv[1], "probe")) { if (dev) { mpu6xxx_deinit(dev); } dev = mpu6xxx_init(argv[2], RT_NULL); } else if (dev == RT_NULL) { rt_kprintf("Please probe mpu6xxx first!\n"); return ; } else if (!strcmp(argv[1], "sr")) { mpu6xxx_set_param(dev, MPU6XXX_SAMPLE_RATE, atoi(argv[2])); } else if (!strcmp(argv[1], "sleep")) { mpu6xxx_set_param(dev, MPU6XXX_SLEEP, atoi(argv[2])); } else if (!strcmp(argv[1], "gr")) { mpu6xxx_set_param(dev, MPU6XXX_GYRO_RANGE, atoi(argv[2])); } else if (!strcmp(argv[1], "ar")) { mpu6xxx_set_param(dev, MPU6XXX_ACCEL_RANGE, atoi(argv[2])); } else { rt_kprintf("Unknown command, please enter 'mpu6xxx' get help information!\n"); } } else { rt_kprintf("Unknown command, please enter 'mpu6xxx' get help information!\n"); } } #ifdef FINSH_USING_MSH MSH_CMD_EXPORT(mpu6xxx, mpu6xxx sensor function); #endif mpu6050.c/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2022-07-11 Asus the first version */ #include "sensor_inven_mpu6xxx.h" int rt_hw_mpu6xxx_port(void) { struct rt_sensor_config cfg; cfg.intf.dev_name = "i2c1"; cfg.intf.user_data = (void *)MPU6XXX_ADDR_DEFAULT; cfg.irq_pin.pin = RT_PIN_NONE; rt_hw_mpu6xxx_init("mpu", &cfg); return 0; } INIT_APP_EXPORT(rt_hw_mpu6xxx_port); 3、main.c文件在re_gen文件夹下,主程序围绕“hal_entry();”函数(在src文件夹),这些默认不变4. 下载验证1、编译重构编译成功2、下载程序下载成功3、CMD串口调试然后板载复位,开始串口打印显示!🎉🎉🎉开始测试,输入mpu6xxx接着校准mpu6050,输入mpu6xxx probe i2c1晃动传感器,读取角加速度,角速度和温度,输入mpu6xxx read 20效果如下打印日志 \ | / - RT - Thread Operating System / | \ 4.1.0 build Jul 13 2022 21:35:51 2006 - 2022 Copyright by RT-Thread team [I/mpu6xxx] Find device: mpu6050! [I/mpu6xxx] Device init succeed! [I/sensor] rt_sensor[acce_mpu] init success [I/sensor] rt_sensor[gyro_mpu] init success [I/sensor] rt_sensor[mag_mpu] init success [I/sensor.inven.mpu6xxx] sensor init success Hello RT-Thread! msh >mpu6xxx mpu6xxx [OPTION] [PARAM] probe <dev_name> Probe mpu6xxx by given name such as i2c1 sr <var> Set sample rate to var var = [1000 - 4] when dlpf is enable var = [8000 - 32] when dlpf is disable gr <var> Set gyro range to var var = [0 - 3] means [250 - 2000DPS] ar <var> Set accel range to var var = [0 - 3] means [2 - 16G] sleep <var> Set sleep status var = 0 means disable, = 1 means enable read [num] read [num] times mpu6xxx num default 5 msh >mpu6xxx probe i2c1 [I/mpu6xxx] Find device: mpu6050! [I/mpu6xxx] Device init succeed! msh >mpu6xxx read 20 accel.x = 200 mg, accel.y = -4 mg, accel.z = 3 mg, gyro.x = 0 deg/10s, gyro.y = -1 deg/10s, gyro.z = -2 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.65 ℃℃ accel.x = 203 mg, accel.y = -4 mg, accel.z = 19 mg, gyro.x = -1 deg/10s, gyro.y = -1 deg/10s, gyro.z = 0 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.65 ℃℃ accel.x = 194 mg, accel.y = -9 mg, accel.z = 6 mg, gyro.x = -1 deg/10s, gyro.y = 1 deg/10s, gyro.z = -2 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.60 ℃℃ accel.x = 210 mg, accel.y = 11 mg, accel.z = 15 mg, gyro.x = -6 deg/10s, gyro.y = 0 deg/10s, gyro.z = -1 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.60 ℃℃ accel.x = 389 mg, accel.y = 408 mg, accel.z = 499 mg, gyro.x = 25 deg/10s, gyro.y = -127 deg/10s, gyro.z = 353 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.65 ℃℃ accel.x = 187 mg, accel.y = -218 mg, accel.z = -70 mg, gyro.x = 37 deg/10s, gyro.y = -15 deg/10s, gyro.z = 478 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.74 ℃℃ accel.x = -149 mg, accel.y = -561 mg, accel.z = 246 mg, gyro.x = -2571 deg/10s, gyro.y = 479 deg/10s, gyro.z = 121 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.60 ℃℃ accel.x = 104 mg, accel.y = -109 mg, accel.z = -42 mg, gyro.x = -1431 deg/10s, gyro.y = -1333 deg/10s, gyro.z = -1885 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.70 ℃℃ accel.x = 677 mg, accel.y = -592 mg, accel.z = 330 mg, gyro.x = -313 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -1443 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.55 ℃℃ accel.x = 749 mg, accel.y = -57 mg, accel.z = -410 mg, gyro.x = -1377 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -611 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.65 ℃℃ accel.x = 512 mg, accel.y = -146 mg, accel.z = -1845 mg, gyro.x = -799 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -149 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.55 ℃℃ accel.x = -180 mg, accel.y = 420 mg, accel.z = -2800 mg, gyro.x = 519 deg/10s, gyro.y = 1497 deg/10s, gyro.z = 140 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.60 ℃℃ accel.x = 237 mg, accel.y = 243 mg, accel.z = -1148 mg, gyro.x = 1585 deg/10s, gyro.y = 2523 deg/10s, gyro.z = 1265 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.60 ℃℃ accel.x = 77 mg, accel.y = -667 mg, accel.z = -257 mg, gyro.x = 907 deg/10s, gyro.y = 2523 deg/10s, gyro.z = 1608 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.51 ℃℃ accel.x = -239 mg, accel.y = -726 mg, accel.z = 644 mg, gyro.x = 557 deg/10s, gyro.y = 2523 deg/10s, gyro.z = 651 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.51 ℃℃ accel.x = -230 mg, accel.y = -556 mg, accel.z = 181 mg, gyro.x = 215 deg/10s, gyro.y = 294 deg/10s, gyro.z = -54 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.65 ℃℃ accel.x = -385 mg, accel.y = -600 mg, accel.z = 570 mg, gyro.x = -1 deg/10s, gyro.y = -2045 deg/10s, gyro.z = -128 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.55 ℃℃ accel.x = -335 mg, accel.y = -419 mg, accel.z = -310 mg, gyro.x = -1128 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -1016 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.55 ℃℃ accel.x = 534 mg, accel.y = 100 mg, accel.z = -1428 mg, gyro.x = -1368 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -1052 deg/10s, mag.x = 0 uT, mag. y = 0 uT, mag.z = 0 uTtemp = 31.55 ℃℃ accel.x = 469 mg, accel.y = 265 mg, accel.z = -1841 mg, gyro.x = -1220 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -656 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.46 ℃℃ 数据显示一开始没有怎么变化,后面就会变化加快(我手抖了😁),mpu6050不支持磁力所以全部为零。
1. 数据可视化:tensorboard作为Tensorflow中强大的可视化工具,已经被广泛使用但针对其他框架,例如Pytorch,之前一直没有这么好的可视化工具可用,好在目前Pytorch也可以支持Tensorboard了,那就是通过使用tensorboardX,真是Pytorcher的福利!可以看到 tensorboardX完美支持了tensorboard常用的functionGithub传送门:Tensorboard , TensorboardX下面介绍tensorboardX安装和基本使用方法:2. tensorboardX安装:因为tensorboardX是对tensorboard进行了封装后,开放出来使用,所以必须先安装tensorboard, 再安装tensorboardX,(而如果不需要,可以不安装tensorflow,只是有些功能会受限)直接使用pip/conda安装:pip install tensorboard pip install tensorboardX 3. tensorboardX使用:安装好后,剩下的和tensorboard使用方法基本一致,先跑一遍example中的实例,git clone https://github.com/lanpa/tensorboardX.git 可以看到example 文件夹有很多实例运行demo.py:python demo.py demo.py运行后,会在该目录生成默认的runs文件夹,里面存储了Demo程序写入的log文件(通过pytorch),这样就可以通过tensorboard对这些数据可视化了:tensorboard --logdir "log路径" --port 6006 和往常一样启动tensorboard,web组件会在localhost搭建一个Port默认为6006这时候打开浏览器(最好用chrome)进入http://localhost:6006/ ,就可以查看数据。
1. 下载tftb-0.2安装包链接地址1:tftb-0.2下载第三个解压就好链接地址2:Matlab时频工具箱tftb-0.22. 解压下载的安装包2.1 解压2.2 打开matlab所在位置2.3 添加到matlab相邻位置3. 添加工具箱tftb的路径打开matlab主页,点击设置路径最后点击确认,即完成4. 测试我们已经知道,⼩波变换专业处理时变信号。时变信号就是信号的频率是随着时间变化的,单纯从时域来看只能通过观察图像变紧缩或舒张来判断频率是否变化,这是不精确的!如果能绘制⼀张横坐标是时间/采样点、纵坐标是频率的图像,那样就可以很好的观察频率随时间的变化!这样的需求就需要做"时频分析"来实现,得到的图像叫作"时频图"。clear all; clc; N = 1024; % 总采样点 fs = 1000; % 采样频率 tt = (0:N-1)'/fs; % 时间刻度 % 构成信号: 注意x和tt都是列向量 f1 = 400 ; f2 = 200 ; f3 = 100 ; f4 = 50 ; x = sin(2*pi*f1*tt).*(tt<=0.3) + sin(2*pi*f2*tt).*(tt>0.3&tt<=0.6) + ... sin(2*pi*f3*tt).*(tt>0.6&tt<=0.8) + sin(2*pi*f4*tt).*(tt>0.8); figure(4); plot(tt,x); axis([0 max(tt) -inf inf]); xlabel('时间/s'); ylabel('振幅'); title('原始时域信号'); % 短时傅里叶变换操作: figure(5); % 因为tfr把频率轴限制在-0.5~0.5之间,因此恢复"真实频率"的时候要x2 h = hanning(63); % 63个节点的汉宁窗 [tfr,t,f] = tfrstft(x,1:N,N,h); % 参数一个都不能少 subplot(2,2,1); contour( tt, f(1:N/2)*fs*2, abs(tfr(1:N/2,:)) ); % 等值线图 xlabel('时间/s'); ylabel('频率/Hz'); title('63节点汉宁窗时频图'); grid on; h = hanning(127); % 127个节点的汉宁窗 [tfr,t,f] = tfrstft(x,1:N,N,h); % 参数一个都不能少 subplot(2,2,2); contour( tt, f(1:N/2)*fs*2, abs(tfr(1:N/2,:)) ); % 等值线图 xlabel('时间/s'); ylabel('频率/Hz'); title('127节点汉宁窗时频图'); grid on; h = hanning(255); % 255个节点的汉宁窗 [tfr,t,f] = tfrstft(x,1:N,N,h); % 参数?个都不能少 subplot(2,2,3); contour( tt, f(1:N/2)*fs*2, abs(tfr(1:N/2,:)) ); % 等值线图 xlabel('时间/s'); ylabel('频率/Hz'); title('255节点汉宁窗时频图'); grid on; h = hanning(511); % 511个节点的汉宁窗 [tfr,t,f] = tfrstft(x,1:N,N,h); % 参数?个都不能少 subplot(2,2,4); contour( tt, f(1:N/2)*fs*2, abs(tfr(1:N/2,:)) ); % 等值线图 xlabel('时间/s'); ylabel('频率/Hz'); title('511节点汉宁窗时频图'); grid on;
1. 密度泛函理论密度泛函理论(Density Functional Theory)是一种研究多电子体系电子结构的量子力学方法。密度泛函理论在物理和化学上都有广泛的应用,特别是用来研究分子和凝聚态的性质,是凝聚态物理和计算化学领域最常用的方法之一。电子结构理论的经典方法,特别是Hartree-Fock方法和后Hartree-Fock方法,是基于复杂的多电子波函数的。密度泛函理论的主要目标就是用电子密度取代波函数做为研究的基本量。因为多电子波函数有3N个变量(N 为电子数,每个电子包含三个空间变量),而电子密度仅是三个变量的函数,无论在概念上还是实际上都更方便处理。Hohenberg-Kohn定理为泛函理论提供了坚实的理论基础:第一定理指出体系的基态能量仅仅是电子密度的泛函。第二定理证明了以基态密度为变量,将体系能量通过变分得到最小值之后就得到了基态能量。密度泛函理论最普遍的应用是通过Kohn-Sham方法实现的。在Kohn-Sham DFT框架中,最难处理的多体问题被简化成了一个没有相互作用的电子在有效势场中的运动问题。2. Numpy 1D-DFThttp://dcwww.camd.dtu.dk/~askhl/files/python-dft-exercises.pdfGoal: write our own Kohn-Sham (KS) DFT codeTarget: a harmonic oscillator including kinetic energy, electrostatic repulsion between the electrons, and the local density approximation for electronic interactions, ignoring correlation.Hamiltonian:What we have to do?Represent the HamiltonianCalculate the KS wavefunctions, the densityimport numpy as np import matplotlib.pyplot as plt2.1 Differential operatorIn order to represent kinetic operator2.1.1 First order differentiationn_grid=200 x=np.linspace(-5,5,n_grid) h=x[1]-x[0] D=-np.eye(n_grid)+np.diagflat(np.ones(n_grid-1),1) D = D / h2.1.2 Second oorder differentiationD2=D.dot(-D.T) D2[-1,-1]=D2[0,0]2.2 Non-interacting electronsThis is the Hamiltonian of non-interacting free particles in a box given by the size of grid:eig_non, psi_non=np.linalg.eigh(-D2/2)plot (energies are shown in the label)for i in range(3): plt.plot(x,psi_non[:,i], label=f"{eig_non[i]:.4f}") plt.legend(loc=1)2.3 Harmonic oscillatorX=np.diagflat(x*x)and solve the KS.eig_harm, psi_harm = np.linalg.eigh(-D2/2+X)plotfor i in range(5): plt.plot(x,psi_harm[:,i], label=f"{eig_harm[i]:.4f}") plt.legend(loc=1)2.4 DensityWe will want to include the Coulomb or Hatree interacion as well as LDA exchangeBoth of which are density functinalsSo we need to calculate the electron density# integral def integral(x,y,axis=0): dx=x[1]-x[0] return np.sum(y*dx, axis=axis)number of electronsnum_electron=17densitydef get_nx(num_electron, psi, x): # normalization I=integral(x,psi**2,axis=0) normed_psi=psi/np.sqrt(I)[None, :] # occupation num fn=[2 for _ in range(num_electron//2)] if num_electron % 2: fn.append(1) # density res=np.zeros_like(normed_psi[:,0]) for ne, psi in zip(fn,normed_psi.T): res += ne*(psi**2) return resplotplt.plot(get_nx(num_electron,psi_non, x), label="non") plt.plot(get_nx(num_electron,psi_harm, x), label="harm") plt.legend(loc=1)2.5 Exchange energydef get_exchange(nx,x): energy=-3./4.*(3./np.pi)**(1./3.)*integral(x,nx**(4./3.)) potential=-(3./np.pi)**(1./3.)*nx**(1./3.) return energy, potential2.6 coulomb potentialdef get_hatree(nx,x, eps=1e-1): h=x[1]-x[0] energy=np.sum(nx[None,:]*nx[:,None]*h**2/np.sqrt((x[None,:]-x[:,None])**2+eps)/2) potential=np.sum(nx[None,:]*h/np.sqrt((x[None,:]-x[:,None])**2+eps),axis=-1) return energy, potential2.7 Solve the KS equation:Self-consistency loopinitialize the density (you can take an arbitrary constant)Calculate the Exchange and Hatree potentialsCalculate the HamiltonianCalculate the wavefunctions and eigen valuesIf not converged, calculate the density and back to 1.def print_log(i,log): print(f"step: {i:<5} energy: {log['energy'][-1]:<10.4f} energy_diff: {log['energy_diff'][-1]:.10f}") max_iter=1000 energy_tolerance=1e-5 log={"energy":[float("inf")], "energy_diff":[float("inf")]} nx=np.zeros(n_grid) for i in range(max_iter): ex_energy, ex_potential=get_exchange(nx,x) ha_energy, ha_potential=get_hatree(nx,x) # Hamiltonian H=-D2/2+np.diagflat(ex_potential+ha_potential+x*x) energy, psi= np.linalg.eigh(H) # log log["energy"].append(energy[0]) energy_diff=energy[0]-log["energy"][-2] log["energy_diff"].append(energy_diff) print_log(i,log) # convergence if abs(energy_diff) < energy_tolerance: print("converged!") break # update density nx=get_nx(num_electron,psi,x) else: print("not converged")plotfor i in range(5): plt.plot(x,psi[:,i], label=f"{energy[i]:.4f}") plt.legend(loc=1)compare the density to free particlesplt.plot(nx) plt.plot(get_nx(num_electron,psi_harm,x), label="no-interaction") plt.legend()
1. 前言蒙特卡罗方法(Monte Carlo method),也称统计模拟方法,是一种以概率统计理论为指导的数值计算方法。它使用随机数(或更常见的伪随机数)来解决科学和工程中的很多计算问题。通常蒙特卡罗方法可以粗略地分成两类:一类是所求解的问题本身具有内在的随机性,借助计算机的运算能力可以直接模拟这种随机的过程。例如模拟核裂变过程。另一种类型是所求解问题可以转化为某种随机分布的特征数,比如随机事件出现的概率,或者随机变量的期望值。通过随机抽样的方法,以随机事件出现的频率估计其概率,或者以抽样的数字特征估算随机变量的数字特征,并将其作为问题的解。例如求解复杂的多维积分问题。示例 使用蒙特卡罗方法估算π \piπ值import numpy as np import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(4, 4)) x = np.linspace(0,1,100) y = np.sqrt(1 - x**2) ax.plot(x, y, c='b') ax.fill_between(x, 0, y, alpha=0.5) ax.fill_between(x, y, 1, alpha=0.5)from ipywidgets import interactive np.random.seed(0) def pi(n): N = 10**n x = np.random.random(N) y = np.random.random(N) dist = x**2 + y**2 pi = np.sum(dist < 1) / N * 4 X = np.linspace(0,1,100) Y = np.sqrt(1 - X**2) fig, ax = plt.subplots(figsize=(4, 4)) ax.plot(X, Y, c='b') ax.scatter(x, y, s=1, alpha=0.5) plt.show() print('Number of Data Point %d' %(N)) print('Estimate Value of Pi %f' %(pi)) interact_plot = interactive(pi, n=(1, 7)) interact_plot2. 伪随机数生成器(PRNG)经典计算机的数据都是由确定性算法生成的,因此随机数生成算法只能得到伪随机数序列。虽然伪随机数并不真正的随机,但具有类似于随机数的统计特征,如均匀性、独立性等。真正的随机数必须使用专门的设备,比如热噪信号、用户按键盘的位置与速度、移动设备加速度传感器等,或者使用量子计算机。密码学中使用伪随机数要小心,其可计算性是一个可以攻击的地方。统计学、蒙特卡罗方法上使用的伪随机数也必须挑选周期极长、随机性够高的随机函数,以确保计算结果有足够的随机性。2.1 线性同余发生器(LCG)def lcg(m=2**32, a=1103515245, b=12345): lcg.current = (a*lcg.current + b) % m return lcg.current/m # setting the seed lcg.current = 1 [lcg() for i in range(10)]2.2 逆变换采样逆变换采样是伪随机数采样的一种基本方法。在已知任意概率分布的累积分布函数时,可用于从该分布中生成随机样本。def expon_pdf(x, lmabd=1): """指数分布的概率密度函数""" return lmabd*np.exp(-lmabd*x) def expon_cdf(x, lambd=1): """指数分布的累积分布函数""" return 1 - np.exp(-lambd*x) def expon_icdf(p, lambd=1): """指数分布的累积分布函数逆函数,即分位函数""" return -np.log(1-p)/lambd import scipy.stats as stats dist = stats.expon() x = np.linspace(0,4,100) y = np.linspace(0,1,100) plt.figure(figsize=(12,4)) plt.subplot(121) plt.plot(x, expon_cdf(x)) plt.axis([0, 4, 0, 1]) for q in [0.5, 0.8]: plt.arrow(0, q, expon_icdf(q)-0.1, 0, head_width=0.05, head_length=0.1, fc='b', ec='b') plt.arrow(expon_icdf(q), q, 0, -q+0.1, head_width=0.1, head_length=0.05, fc='b', ec='b') plt.ylabel('1: Generate a (0,1) uniform PRNG') plt.xlabel('2: Find the inverse CDF') plt.title('Inverse transform method'); plt.subplot(122) np.random.seed(0) N = 10**6 u = np.random.random(N) v = expon_icdf(u) plt.hist(v, histtype='step', bins=100, density=True, linewidth=2) plt.plot(x, expon_pdf(x), linewidth=2) plt.axis([0,4,0,1]) plt.title('Histogram of exponential PRNGs');2.3 Python中的随机数生成器numpy.random和scipy.stats中提供的随机数生成函数都是基于梅森旋转(Mersenne Twister)演算法,可以快速产生高质量的伪随机数。SciPy中还提供了有关概率密度函数(PDF)和累积分布函数(CDF)相关的工具。scipy.stats支持的分布函数包括均匀分布、正态分布、指数分布、beta分布、泊松分布、柯西分布等,我们会在相应章节对其专门介绍。# Using scipy import scipy.stats as ss n = 5 xs = [0.1, 0.5, 0.9] rv = ss.beta(a=0.5, b=0.5) print(rv.pdf(xs)) print(rv.cdf(xs)) print(rv.ppf(xs)) # ppf是cdf的反函数,即分位函数 print(rv.rvs(n)) # 随机变量# And here is a plot of the PDF for the beta distribution xs = np.linspace(0, 1, 100) plt.plot(xs, ss.beta.pdf(xs, a=0.5, b=0.5)) 3. 蒙特卡罗积分假设我们需要进行如下积分:3.1 有限积分x = np.linspace(0, 1, 100) plt.plot(x, np.exp(x)); pts = np.random.uniform(0,1,(100, 2)) pts[:, 1] *= np.e plt.scatter(pts[:, 0], pts[:, 1]) plt.xlim([0,1]) plt.ylim([0, np.e])# Check analytic solution from sympy import symbols, integrate, exp x = symbols('x') expr = integrate(exp(x), (x,0,1)) expr.evalf()# Using numerical quadrature from scipy import integrate integrate.quad(exp, 0, 1)# Monte Carlo approximation for n in 10**np.array([1,2,3,4,5,6]): pts = np.random.uniform(0, 1, (n, 2)) pts[:, 1] *= np.e count = np.sum(pts[:, 1] < np.exp(pts[:, 0])) volume = np.e * 1 # volume of region sol = (volume * count)/n print('%10d %.6f' % (n, sol))大数定律 样本数量越多,则其算术平均值就有越高的概率接近期望值。大数定律说明了一些随机事件的均值的长期稳定性,即偶然之中包含着必然。3.2 方差估计蒙特卡罗积分的结果是否收敛对于结果的准确性非常重要。因此,我们需要对方差进行估计。一个获取结果置信区间的简单方法是重复进行多次蒙特卡罗模拟。n = 10**7 sol = [] for i in range(10): pts = np.random.uniform(0, 1, (n, 2)) pts[:, 1] *= np.e count = np.sum(pts[:, 1] < np.exp(pts[:, 0])) volume = np.e * 1 sol.append((volume * count)/n) np.percentile(sol, [2.5, 50, 97.5])3.3 方差缩减蒙特卡罗积分的期望误差与/n成反比,精度可以通过增加模拟的次数,但是速度较慢。提高计算精度更有效的途径是减小方差。常见的方差缩减技术有分层抽样法、重要性抽样法、条件期望法、对偶变量法、控制变量法、准随机数等。重要性抽样使用常规蒙特卡罗方法计算标准正态分布的尾部几率P ( X > 5 ) P(X > 5)P(X>5)是非常困难的。因为10^7个随机采样中,只有平均3个采样大于5。n = 10**6 y = ss.norm().rvs(n) h_mc = 1.0/n * np.sum(y > 5) print(h_mc)n = 10**4 y = ss.expon(loc=5).rvs(n) h_is = 1.0/n * np.sum(ss.norm().pdf(y)/ss.expon(loc=5).pdf(y)) print(h_is)准随机数准随机数发生器(QRNG)可以产生高度均匀的单位超立方体样本。与普通伪随机数不同,准随机序列寻求均匀填充空间。在统计意义上,准随机数过于均匀,不能通过传统的随机性测试。在蒙特卡罗积分中使用准随机序列以减小方差的思路与分层抽样法类似,二者的目的都是让随机样本更均匀地分布在空间中。Gacha手游的随机抽奖环节实际上使用的就是伪随机数,例如普遍存在的保底机制。3.4 无穷积分def f(x): return x**2 n = 10**5 pts = np.random.randn(n) np.mean(f(pts))# Check analytic solution from sympy import symbols, integrate, exp, sqrt, pi, oo x = symbols('x') expr = integrate( x**2 / sqrt(2*pi) * exp(-x**2/2), (x, -oo, oo)) expr.evalf()1.03.5 多重积分当增加积分变量时,数值方法计算多重积分的计算量(正比于 n^d )快速增长。def f(*args): return np.exp(-np.sum(np.array(args)**2)) from scipy import integrate %time print(integrate.nquad(f, [(0,1)] * 1)) %time print(integrate.nquad(f, [(0,1)] * 2)) %time print(integrate.nquad(f, [(0,1)] * 3)) %time print(integrate.nquad(f, [(0,1)] * 4))蒙特卡罗积分的精度较低,但是在维度上的拓展性非常好。def mc(n, d): pts = np.random.uniform(0, 1, (n, d)) sum = 0 for i in pts: sum += f(i) return sum/len(pts) n = 10**5 %time print(mc(n, 1)) %time print(mc(n, 2)) %time print(mc(n, 3)) %time print(mc(n, 4))4. 蒙特卡罗数值优化4.1 模拟退火算法模拟退火物理退火变量粒子状态目标函数能量最优解能量最低态设定动能(控制参数)材料熔解Metropolis采样等温过程控制参数下降材料冷却模拟退火算法也常用于机器学习,特别是强化学习的算法中。一般情况下,针对得到的样本数据集创建相对模糊的模型,通过蒙特卡洛方法对于模型中的参数进行选取,使之于原始数据的残差尽可能的小。从而达到创建模型拟合样本的目的。4.2 函数优化使用蒙特卡罗模拟退火算法进行函数优化是按照以下步骤进行的:使用随机数生成器在变量空间中产生一个随机的位置坐标。对此位置做无规则的改变,产生一个新的位置坐标。计算新的位置坐标处的函数值。比较新的位置坐标与改变前的位置坐标的函数值变化,判断是否接受该坐标。若新的位置坐标函数值低于原位置坐标的函数值,则接受新的坐标,使用这个坐标重复再做下一次迭代。若新的位置坐标函数值高于原位置坐标的函数值,则计算玻尔兹曼因子,并产生一个随机数。若这个随机数大于所计算出的玻尔兹曼因子,则放弃这个坐标,重新计算。若这个随机数小于所计算出的玻尔兹曼因子,则接受这个坐标,使用这个坐标重复再做下一次迭代。如此进行迭代计算,直至最后搜索出低于所给函数值条件的位置坐标结束。import numpy as np x = np.linspace(-1, 1, 200) y = np.linspace(-1, 1, 200) z = np.linspace(-1, 1, 200) Y, Z, X = np.meshgrid(x, y, z) def gaussian(x0, y0, z0): return np.exp(-(X - x0)**2 - (Y - y0)**2 - (Z - z0)**2) # 局部极小值在(-0.5, -0.5, -0.5)附近,全局极小值在(0.5, 0.5, 0.5)附近 data = gaussian(0.1, -0.1, -0.1) - gaussian(-0.5, -0.5, -0.5) - gaussian(0.5, 0.5, 0.5) * 2 np.unravel_index(np.argmin(data), data.shape), np.min(data)def annealing(pos, step, KbT): for i in range(step): value = data[tuple(pos)] new_pos = pos + np.round(np.random.random(3)) * 2 - 1 new_pos = np.int32(new_pos % 200) # pbc new_value = data[tuple(new_pos)] if new_value < value: pos = new_pos value = new_value else: delta = new_value - value p = np.exp(-delta/KbT) if p > np.random.random(): pos = new_pos value = new_value return pos, value step = 10**5 KbT = 0.01 #np.random.seed(0) pos1 = [50, 50, 50] # 初始位置在局部极小附近 print(annealing(pos1, step, KbT)) pos1 = [150, 150, 150] # 初始位置在全局极小附近 print(annealing(pos1, step, KbT))可以看到,在温度/动能较低时,蒙特卡罗模拟不能保证系统在有限的时间内收敛到最低点。增加模拟时间或者增加温度,可以增大系统从局部势阱约束中逃逸的几率。'''变温''' KbT = 0.1 pos = np.int32(np.random.random(3)*200) for i in range(5): pos, value = annealing(pos, step, KbT / 10**i) print(KbT, pos, value)相对于数值算法只能收敛到局部最优解,模拟退火算法所得解依概率收敛到全局最优解。模拟退火算法对变量数目不敏感,可以很轻松处理高维问题。
1. 数据插值插值是一种从离散数据点构建函数的数学方法。插值函数或者插值方法应该与给定的数据点完全一致。插值可能的应用场景:根据给定的数据集绘制平滑的曲线对计算量很大的复杂函数进行近似求值插值和前面介绍过的最小二乘拟合有些类似。在最小二乘拟合中,我们感兴趣的是使用数据点和超定方程组,将函数拟合到数组点,使得误差平方和最小。在插值中,我们需要一个方程能够与已有的数据点完全重合,仅使用与插值函数自由参数个数相同的数据点。因此,最小二乘法适合将大量数据点拟合到模型函数,插值是根据少量数据点创建函数。外插(extrapolation)是与插值(interpolation)相关的一个概念。外插是在采样范围之外计算函数的估计值。我们这里只介绍插值。2. 导入模块本部分我们将使用NumPy中的polynomial模块和SciPy的interpolation模块。import numpy as np from scipy import linalg import matplotlib.pyplot as plt from numpy import polynomial as P from scipy import interpolate %reload_ext version_information %version_information numpy, matplotlib, scipy 3. 插值函数为了简洁起见,我们这里只考虑一维插值问题。对于给定的数据点的集合 {(xi,yi)}i=1n,找到插值函数f(xi)=yi。插值函数的选择并不是唯一的,事实上有无数函数满足插值标准。通常可以把插值函数写为一组基函数ϕ ( x )的线性组合,即f(x)=j=1∑ncjϕj(x),其中c j是未知系数。将给定的数据点代入线性组合,可以得到未知系数的线性方程组:这里基函数的数量与数据点的数量想用,可以使用求解方程组的标准方法得到系数向c cc的唯一解。如果基函数的数量小于数据点的数量,该方程组是超定的,可能需要使用最小二乘拟合进行近似插值。3.1 多项式NumPy库包含的polynominal模块提供了处理多项式的函数和类。要创建Polynominal类的实例,可以将系数数组传给该类的构造函数。p1 = P.Polynomial([1,2,3]) p1 也可以使用Polynomial.fromroots方法,通过指定多项式的根来初始化多项式。p2 = P.Polynomial.fromroots([-1, 1]) p2 我们可以通过实例的方法访问其特性:p1.roots() # 根 p1.coef # 系数Polynomial实例包括domain和windows两个参数,可以用于把多项式的输入域映射到另外一个区间。p1.domainp1.window多项式在用Polynomial实例表示后可以很容易计算任何x xx的多项式值。p1(np.array([1.5, 2.5, 3.5]))Polynomial实例支持标准的算术运算符。p1 + p2分解因式p3 = P.Polynomial([1,1]) # 等价于 P.Polynomial.fromroots(-1) p2 // p3P.Polynomial.fromroots(-1)除了标准幂基多项式的Polynomial类,polynomial模块还提供了切比雪夫多项式、勒让德多项式、拉盖尔多项式、埃尔米特多项式的类。l1 = P.Legendre([1,2,3]) # 勒让德多项式 l1l1.roots()3.2 多项式插值求解多项式插值问题,首先需要根据提供的基函数计算矩阵ϕ ( x ) \phi(x)ϕ(x),然后求解得到的线性方程组。polynomial模块中的每个多项式类都提供了方便的函数来计算相应基的范德蒙矩阵。例如,假设存在数据点(1, 1)、(2, 3)、(3, 5)、(4, 4)。x = np.array([1, 2, 3, 4]) y = np.array([1, 3, 5, 4]) deg = len(x) - 1 A = P.polynomial.polyvander(x, deg) # 范德蒙矩阵 Ac = linalg.solve(A, y) c找到的插值多项式是f ( x ) =2−3.5x+3x2−0.5x3。f1 = P.Polynomial(c) f1(2.5)下面,我们使用切比雪夫多项式重新对数据进行插值。A = P.chebyshev.chebvander(x, deg) Ac = linalg.solve(A, y) cf2 = P.Chebyshev(c) f2(2.5)将函数f 1 和f 2进行对比,验证不同基函数进行插值,得到了一致的插值函数。xx = np.linspace(x.min(), x.max(), 100) fig, ax = plt.subplots(1, 1, figsize=(8, 4)) ax.plot(xx, f1(xx), 'b', lw=2, label='Power basis interp.') ax.plot(xx, f2(xx), 'r--', lw=2, label='Chebyshev basis interp.') ax.scatter(x, y, label='data points') ax.legend(loc=4) ax.set_xticks(x) ax.set_ylabel(r"$y$", fontsize=18) ax.set_xlabel(r"$x$", fontsize=18)polynomial模块还提供了更快捷的方法计算插值多项式。每个多项式类都有fit方法用于计算插值,deg参数用于控制多项式的次数。如果多项式的次数少于数据点的数目减1,fit方法会使用最小二乘拟合而不是精确插值。f1b = P.Polynomial.fit(x, y, deg) f1bf2b = P.Chebyshev.fit(x, y, deg) f2b注意在使用fit方法时,实例中的domain属性会自动设置为数据点中相应的x值,上述示例中为[1, 4],并相应调整系数。将插值数据映射到某个基函数最合适的范围,可以明显提高插值的数值稳定性,减小范德蒙矩阵的条件数。np.linalg.cond(P.chebyshev.chebvander(x, deg))np.linalg.cond(P.chebyshev.chebvander((2*x-5)/3.0, deg))当数据点的数量增加时,需要使用次数更多的多项式才能得到精确的插值。这会带来多方面问题:次数更多的多项式插值计算和插值函数的确定,计算量很大。高次多项式插值可能会在插值点之间带来不可预料的行为,插值函数在数据点之间可能变化很大。下面我们将使用龙格函数演示这种行为:def runge(x): return 1/(1 + 25 * x**2) def runge_interpolate(n): x = np.linspace(-1, 1, n+1) p = P.Polynomial.fit(x, runge(x), deg=n) return x, p xx = np.linspace(-1, 1, 250) fig, ax = plt.subplots(1, 1, figsize=(8, 4)) ax.plot(xx, runge(xx), 'k', lw=2, label="Runge's function") n = 13 x, p = runge_interpolate(n) ax.plot(x, runge(x), 'ro') ax.plot(xx, p(xx), 'r', label='interp. order %d' % n) n = 14 x, p = runge_interpolate(n) ax.plot(x, runge(x), 'go') ax.plot(xx, p(xx), 'g', label='interp. order %d' % n) ax.legend(loc=8) ax.set_xlim(-1.1, 1.1) ax.set_ylim(-1, 2) ax.set_xticks([-1, -0.5, 0, 0.5, 1]) ax.set_ylabel(r"$y$", fontsize=18) ax.set_xlabel(r"$x$", fontsize=18)可以看到,高阶插值函数在远端采样点之间急剧震荡。这种不良特性违背了插值的初衷。一个可行的解决方法是,当面对大量数据点时,使用分段低次多项式进行插值。3.3 样条插值对于包含n nn个数据点的集合,在整个数据区间上有n − 1 n-1n−1个子区间。连接两个子区间的数据点在分段多项式插值中被称为节点。在每个子区间上使用k kk次多项式对n nn个数据点进行插值,需要确定( k + 1 ) ( n − 1 ) (k+1)(n-1)(k+1)(n−1)个参数。所有节点的值可以给出2 ( n − 1 ) 2(n-1)2(n−1)个方程。为了保证分段多项式的平滑,节点处导数和高阶导数的连续性也会给出相应方程。样条是一种特殊类型的分段式插值函数。最常用的是三次样条,k = 3 k=3k=3,需要4 ( n − 1 ) 4(n-1)4(n−1)个参数。在n − 2 n-2n−2个节点处,一阶和二阶导数的连续性可以给出2 ( n − 1 ) 2(n-1)2(n−1)个方程,总方程的数目为4 ( n − 1 ) − 2 4(n-1)-24(n−1)−2。此时还剩下两个未确定的参数。一种常见的方法是要求端点处的二阶导数为0,这被称为自然样条。SciPy的interpolate模块提供了用于样条插值的多个函数和类。下面我们将再次使用龙格函数,演示使用interpolate.interp1d函数。这里设置kind=3来计算三次样条。x = np.linspace(-1, 1, 11) y = runge(x) f = interpolate.interp1d(x, y, kind=3) f(0.05)xx = np.linspace(-1, 1, 100) fig, ax = plt.subplots(figsize=(8, 4)) ax.plot(xx, runge(xx), 'k', lw=1, label="Runge's function") ax.plot(x, y, 'ro', label='sample points') ax.plot(xx, f(xx), 'r--', lw=2, label='spline order 3') ax.legend() ax.set_ylim(0, 1.1) ax.set_xticks([-1, -0.5, 0, 0.5, 1]) ax.set_ylabel(r"$y$", fontsize=18) ax.set_xlabel(r"$x$", fontsize=18)这里使用了11个数据点和三次样条,可以看到插值很好地与原始函数吻合。为了说明阶数对样条插值的影响,我们下面准备了8个数据点使用不同阶数的样条进行插值。x = np.array([0, 1, 2, 3, 4, 5, 6, 7]) y = np.array([3, 4, 3.5, 2, 1, 1.5, 1.25, 0.9]) xx = np.linspace(x.min(), x.max(), 100) fig, ax = plt.subplots(figsize=(8, 4)) ax.scatter(x, y) for n in [1, 2, 3, 5]: f = interpolate.interp1d(x, y, kind=n) ax.plot(xx, f(xx), label='order %d' % n) ax.legend() ax.set_ylabel(r"$y$", fontsize=18) ax.set_xlabel(r"$x$", fontsize=18)可以看到,二阶或三阶样条已经能够提供较好的插值。高阶样条会出现高阶多项式插值中类似的数值震荡问题。3.4 多变量插值多项式插值和样条插值都可以直接推广到多变量情况。SciPy为多变量插值提供了多个函数和类。我们将介绍两个最常用的双变量插值函数:interpolate.interp2d和interpolate.griddata。3.4.1 均匀网格interpolate.interp2d函数是interpolate.interp1d函数的推广,要求数据点位于x和y坐标组成的规则且均匀的网格中。为了演示函数用法,我们在已知函数中添加随机噪声来模拟测量噪声。为了构造插值问题,我们在x和y坐标的[-2, 2]区间上采样10个点。def f(x, y): return np.exp(-(x + .5)**2 - 2*(y + .5)**2) - np.exp(-(x - .5)**2 - 2*(y - .5)**2) x = y = np.linspace(-2, 2, 10) X, Y = np.meshgrid(x, y) # simulate noisy data at fixed grid points X, Y Z = f(X, Y) + 0.05 * np.random.randn(*X.shape) f_interp = interpolate.interp2d(x, y, Z, kind='cubic') # 三次样条插值 xx = yy = np.linspace(x.min(), x.max(), 100) ZZ_interp = f_interp(xx, yy) XX, YY = np.meshgrid(xx, yy) fig, axes = plt.subplots(1, 2, figsize=(12, 5)) c = axes[0].contourf(XX, YY, f(XX, YY), 15, cmap=plt.cm.RdBu) axes[0].set_xlabel(r"$x$", fontsize=20) axes[0].set_ylabel(r"$y$", fontsize=20) axes[0].set_title("exact / high sampling") cb = fig.colorbar(c, ax=axes[0]) cb.set_label(r"$z$", fontsize=20) c = axes[1].contourf(XX, YY, ZZ_interp, 15, cmap=plt.cm.RdBu) axes[1].set_ylim(-2.1, 2.1) axes[1].set_xlim(-2.1, 2.1) axes[1].set_xlabel(r"$x$", fontsize=20) axes[1].set_ylabel(r"$y$", fontsize=20) axes[1].scatter(X, Y, marker='x', color='k') axes[1].set_title("interpolation of noisy data / low sampling") cb = fig.colorbar(c, ax=axes[1]) cb.set_label(r"$z$", fontsize=20)对于更高维的问题,可以使用interpolate.interpnd函数,它是对N维问题的推广。3.4.2 不均匀网格另一种多变量插值的常见场景是从不规则的坐标网络中采样数据,例如实验室数据等。为了能够使用现有的工具对数据进行可视化分析,可能需要将它们插值到规则的坐标网格中。在SciPy中,可以使用interpolate.griddata函数来完成这项工作。该函数的第一个参数是坐标向量构成的元组,第二个参数是对应的数据点的值,第三个参数是待插值的新数据点的坐标数组或坐标矩阵。我们考虑函数f(x,y)=exp(−x2−y2)在x和y坐标区间[-1, 1]上随机选择的采样点,并对采样数据进行插值。def f(x, y): return np.exp(-x**2 - y**2) * np.cos(4*x) * np.sin(6*y) x = y = np.linspace(-1, 1, 100) X, Y = np.meshgrid(x, y) Z = f(X, Y) np.random.seed(0) N = 500 xdata = np.random.uniform(-1, 1, N) ydata = np.random.uniform(-1, 1, N) zdata = f(xdata, ydata)我们画出函数 𝑓(𝑥,𝑦) 的等高线图,以及500个采样点的位置。fig, ax = plt.subplots(figsize=(8, 6)) c = ax.contourf(X, Y, Z, 15, cmap=plt.cm.RdBu); ax.scatter(xdata, ydata, marker='.') ax.set_ylim(-1,1) ax.set_xlim(-1,1) ax.set_xlabel(r"$x$", fontsize=20) ax.set_ylabel(r"$y$", fontsize=20) cb = fig.colorbar(c, ax=ax) cb.set_label(r"$z$", fontsize=20) 随后,我们使用X和Y坐标数组定义更细小间隔(超采样)的网格中对数据进行插值。我们将比较最近邻点插值(0阶插值)、线性插值(1阶插值)和三次样条插值在不用数据点数目下的效果区别。def z_interpolate(xdata, ydata, zdata): Zi_0 = interpolate.griddata((xdata, ydata), zdata, (X, Y), method='nearest') Zi_1 = interpolate.griddata((xdata, ydata), zdata, (X, Y), method='linear') Zi_3 = interpolate.griddata((xdata, ydata), zdata, (X, Y), method='cubic') return Zi_0, Zi_1, Zi_3 fig, axes = plt.subplots(3, 3, figsize=(12, 12), sharex=True, sharey=True) n_vec = [50, 150, 500] for idx, n in enumerate(n_vec): Zi_0, Zi_1, Zi_3 = z_interpolate(xdata[:n], ydata[:n], zdata[:n]) axes[idx, 0].contourf(X, Y, Zi_0, 15, cmap=plt.cm.RdBu) axes[idx, 0].set_ylabel("%d data points\ny" % n, fontsize=16) axes[idx, 0].set_title("nearest", fontsize=16) axes[idx, 1].contourf(X, Y, Zi_1, 15, cmap=plt.cm.RdBu) axes[idx, 1].set_title("linear", fontsize=16) axes[idx, 2].contourf(X, Y, Zi_3, 15, cmap=plt.cm.RdBu) axes[idx, 2].set_title("cubic", fontsize=16) for m in range(len(n_vec)): axes[idx, m].set_xlabel("x", fontsize=16) 只要采样点能够有效覆盖我们感兴趣的区域,就可以通过非结构化的样本数据进行插值来重建函数。上面例子中,三次样条插值的效果要远优于最近邻点插值和线性插值。
1. SeabornSeaborn是Python中的一个高级可视化库,是对Matplotlib进行二次封装而成。Seaborn的很多图表接口和参数设置与Matplotlib很是接近。相比Matplotlib而言,Seaborn的几个鲜明特点如下:绘图接口更为集成,可通过少量参数设置实现大量封装绘图多数图表具有统计学含义,例如分布、关系、统计、回归等对Pandas和Numpy数据类型支持非常友好风格设置更为多样,例如风格、绘图环境和颜色配置等参考资料Seaborn 教程Seaborn 示例import numpy as np import seaborn as sns penguins = sns.load_dataset("penguins") penguins # DataFrame sns.jointplot( data=penguins, x="bill_length_mm", y="bill_depth_mm", hue="species", kind="kde" ) 2. IpyvolumeIPyvolume is a Python library to visualize 3d volumes and glyphs (e.g. 3d scatter plots), in the Jupyter notebook, with minimal configuration and effort. It is currently pre-1.0, so use at own risk. IPyvolume’s volshow is to 3d arrays what matplotlib’s imshow is to 2d arrays.————————————————版权声明:本文为CSDN博主「2345VOR」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/vor234/article/details/124835600参考资料Ipyvolume 手册Ipyvolume 示例import numpy as np import ipyvolume as ipv V = np.zeros((128,128,128)) # our 3d array # outer box V[30:-30,30:-30,30:-30] = 0.75 V[35:-35,35:-35,35:-35] = 0.0 # inner box V[50:-50,50:-50,50:-50] = 0.25 V[55:-55,55:-55,55:-55] = 0.0 ipv.figure() ipv.volshow(V, level=[0.25, 0.75], opacity=0.03, level_width=0.1, data_min=0, data_max=1) ipv.view(-30, 40) ipv.show() 3. NglviewAn IPython/Jupyter widget to interactively view molecular structures and trajectories. Utilizes the embeddable NGL Viewer for rendering. Support for showing data from the file-system, RCSB PDB, simpletraj and from objects of analysis libraries mdtraj, pytraj, mdanalysis, ParmEd, rdkit, ase, HTMD, biopython, cctbx, pyrosetta, schrodinger’s Structure————————————————版权声明:本文为CSDN博主「2345VOR」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/vor234/article/details/124835600参考资料nglview 手册nglview 示例import nglview as nv view = nv.show_pdbid("5R7Y") # COVID-19 主蛋白酶 view 4. BqplotBqplot是用于Jupyter的交互式2D绘图库,其中绘图的每个属性都是一个交互式小部件,只需几行Python代码就可以创建丰富的可视化效果。Bqplot构建在widgets框架之上,它利用widget基础提供第一个在Python和JavaScript代码之间通信的绘图库。Bqplot的可视化基于D3.js和SVG,支持快速交互和漂亮的动画。————————————————版权声明:本文为CSDN博主「2345VOR」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/vor234/article/details/124835600参考资料bqplot 手册bqplot 示例import numpy as np from bqplot import pyplot as plt size = 100 np.random.seed(0) x_data = np.arange(size) y_data = np.cumsum(np.random.randn(size)) figure = plt.figure(title='Bqplot Plot') scatter = plt.scatter(x_data, y_data) plt.show() scatter.y = np.cumsum(np.random.randn(size)) # 更新数据 scatter.colors = ['Green'] # 更新颜色 4.1 动画import time for i in range(100): # Update Chart scatter.y = np.insert(scatter.y[:-1], 0 , scatter.y[-1]) time.sleep(0.1) 4.2 交互调整滑块实现调频和调幅import numpy as np from bqplot import pyplot as plt from ipywidgets import interactive, FloatSlider, jslink x = np.linspace(-5, 5, 100) fig = plt.figure(title='Bqplot Plot') line = plt.plot(x, np.sin(x)) plt.set_lim(-2, 2, 'y') plt.show() def f(a, b): line.y = a * np.sin(b*x) interact_plot = interactive(f, a=(1.0, 2.0), b=(1.0, 5.0)) interact_plot 参考文献来自桑鸿乾老师的课件:科学计算和人工智能————————————————版权声明:本文为CSDN博主「2345VOR」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/vor234/article/details/124835600————————————————版权声明:本文为CSDN博主「2345VOR」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/vor234/article/details/124835600
1. simscape能做什么? 当你在CAD软件中做好一个装配体时,需要对其进行运动仿真或者是动力学仿真,可以尝试用simulink中的simscape模块。这个模块可以让你很清楚的了解机构之间的装配与运动关系,在此基础上也可以去做一些优化设计。simscape multibody link可以将你的CAD模型转化为Simscape Multibody环境中的程序结构,目前该插件支持在Solidworks、Autodesk Inventor和Creo等三维软件中进行转换。2. 如何安装搭建simulink与CAD软件之间的接口?软件:你的电脑上需要安装MATLAB和支持的三维设计软件,注意这两种软件之间必须有相同的系统架构,比如说,都是Win 64版本的。安装文件首先去Simscape Multibody Link下载页面下载安装文件,选择对应MATLAB版本的安装文件,比如说,smlink.r2017b.win64.zip和install_addon.m文件以管理员身份运行MATLAB,将MATLAB当前文件夹定位到你下载的插件文件的位置在命令行窗口输入install_addon('smlink.r2017b.win64.zip')等待连接成功,再输入regmatlabserver,回车regmatlabserver再输入smlink_linksw,回车smlink_linksw开启SolidWorks,在主界面工具那一栏选择插件,勾上Simscape Multibody Link的对话框,前后两个框都要勾上,新建一个装配体文件,就能在工具界面看到simscape multibody link的插件接口,此时安装完成。3. 如何将SolidWorks模型导出(以xml格式导出给Matlab) 在SolidWorks顶部菜单栏中,选择“工具”找到“Simscape Multibody Link”然后点击导出,然后保存为“.xml”格式文件即可。 在设置好插件后,使用插件导出xml文件时,SW报错:solidworks could not start Matlab,这一步也很好解决,参考SW导出错误解决方法最后再使用:smimport('pen.xml'),即可获得相应的仿真文件。smimport('pen.xml')4. 总结 本文学习了安装Simscape Multibody Link插件,后期会分享更多有趣物联网的操作从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
01 easy Scholar点击下载文件,修改后缀名为zip文件,解压添加 即可在用知网、PubMed、Web of Science、百度学术时,会发现:文献太多了!如何才能分辨它们的好坏呢?借助easy Scholar帮你一秒判断论文质量。装上插件后,你会发现以上几个文献库的检索页面会自动显示期刊等级,省去手动查质量的麻烦。论文质量好不好,哪些文章是值得读的,一目了然。拥有easy Scholar,相当于还拥有了一键谷歌翻译神器。选中文字按小写的t实现直接翻译,能中英文互译。具体使用方法: easyScholar简介 02 EasyPubMedPubMed的检索页面是非常不直观的,而安装EasyPubMed插件后,检索页面会直接展示期刊的影响因子、JCR分区、中科院分区、文章被引用次数,让检索结果、文献期刊质量更清晰。还可以通过左侧的文献筛选功能,按影响因子、JCR分区、中科院分区、引用次数筛选文献。比如我只想看IF>4分的杂志收录的文献,就可以这样设置,灵活筛选有用的期刊文献。EasyPubMed支持展示完整的摘要,不用再一篇篇点进去查看了。支持一键下载全文,自动从Sci-Hub、Libgen等多渠道获取PDF。更重要的是,你可以收藏、管理想要的文献,在管理助手里实现全文PDF批量下载,而且自动按标题重命名,乱码文件名从此消失。具体使用方法:EasyPubMed更新03 Sci-Hub X Now!当我们在PubMed、Wed of Science等文献网站,找到了想要的论文,需要先复制DOI到Sci-Hub再下载。有了这款插件后,任何网页中只要出现DOI,点击图标就能实现一键下载文献,免除贴来贴去的繁琐,提高学术效率。 具体使用方法:Sci-Hub Now插件04 总结 本文介绍3款堪称神器的插件,让你的知网和PubMed强到逆天,接下来我会记录我的电脑使用学习记录,很高兴能和大家分享!🤣🤣🤣希望你能有所收获。
1. 前言最近由于项目需要,之前我们在利用GPU进行深度学习的时候,都要去NVIDIA的官网下载CUDA的安装程序和cudnn的压缩包,然后再进行很繁琐的系统环境配置。不仅环境配置麻烦,而且还特别容易配置错误,特别还有CUDA和cudnn版本的对应也特别容易搞错,但是利用anaconda安装配置pytorch和paddle环境的时候会自动帮我们配置好cuda和cudnn。2. NVIDIA驱动安装 显卡驱动程序就是用来驱动显卡的程序,它是硬件所对应的软件。驱动程序即添加到操作系统中的一小块代码,其中包含有关硬件设备的信息。正常有显卡的电脑都是有驱动程序的,但是有的时候驱动可能版本比较低,支持的cuda版本也是比较低的(但是有的人的显卡是比较老的,就不建议更新驱动,这样会导致各种各样的问题,但是搞深度学习还是要用一块好的显卡用来学习,这点是过来人有血泪教训的。首先查看电脑的显卡版本,步骤为:此电脑右击-->管理-->设备管理器-->显示适配器。就可以看到电脑显卡的版本了。 有显卡驱动的,可以直接在搜索NVIDIA,找到英伟达驱动控制面板打开就好了再得知以上的信息以后我们就可以对应我们的显卡去英伟达官网上去找相对应的显卡驱动更新或者下载了。 显卡驱动的下载地址(可能打开比较慢,多打开几遍)。 安装(更新)好了显卡驱动以后查看对应版本。我们按下win+R组合键,打开cmd命令窗口。输入如下的命令。nvidia-smi得到如下图的信息图,可以看到驱动的版本是512.15;最高支持的CUDA版本是11.6版本。得到显卡的最高支持的CUDA版本,我们就可以根据这个信息来安装环境了。 3. Anaconda 的安装 打开网址,现在是2021年8月,对应的anaconda版本是支持python3.8。如果想下载之前的版本,或者更低python版本的anaconda,可以打开网址。具体安装见教程:基于Anaconda安装环境的OpenCV机器视觉环境搭建4. Pytorch环境安装 按下开始键(win键),点击如图中的图标。打开anaconda的终端Prompt。 执行如下的指令查看有哪些环境conda env list 可以看出来,新安装的anaconda只有一个base环境。 这里先讲一下anaconda环境,首先base环境是一个大的环境,类似一个很大的一个房子(但是没有房间),当我们每创建一个环境就都会相当于在这个大房子里面用隔板创建一个房间,然后这个房间里面可以安装我们所需要的包,这样管理起来就比较方便。如图可以比较直观的诠释anaconda的环境。 创建虚拟环境conda create -n 环境名字(英文) python=x.x(python版本),如下,我就是创建了一个名字叫pytorch,python是3.8版本的环境。conda create -n pytorch python=3.8 在base环境中执行如上的命令,就会创建一个新的虚拟环境,这个虚拟环境会安装一些基础的包,如下图所示。询问是否安装的时候,输入y。就可以创建环境了。 当安装好了以后,执行conda env list这个命令,就可以看到比一开始多了一个pytorch这个环境。现在我们可以在这个环境里面安装深度学习框架和一些Python包了。执行如下命令,激活这个环境。conda activate 虚拟环境名称conda activate pytorch 安装pytorch-gup版的环境,由于pytorch的官网在国外,下载相关的环境包是比较慢的,所以我们给环境换源。在pytorch环境下执行如下的命名给环境换清华源。 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/ conda config --set show_channel_urls yes然后打开pytorch的官网,由于开头我们通过驱动检测到我的显卡为 RTX1650,最高支持cuda11.6版本,所以我们选择cuda11.3版本的cuda,然后将下面红色框框中的内容复制下来,一定不要把后面的-c pytorch也复制下来,因为这样运行就是还是在国外源下载,这样就会很慢。 将复制的内容粘贴到pytorch环境下的终端,运行就可以了conda install pytorch torchvision torchaudio cudatoolkit=11.3这时候就开始下载环境所需要的依赖包了,如果部分包一次性下载不下来,就再来一次。5. paddle环境安装如pytorch环境安装一样,首先在base环境下创建一个新的环境来安装paddlepaddle框架。首先创建一个新的环境名叫paddle。执行如下命令。conda create -n paddle python=3.8 创建好了名叫paddle这个环境以后,进入到这个环境中(可以在pytorch环境下进入),执行如下命令。conda activate paddle conda install paddlepaddle-gpu==2.2.2 cudatoolkit=11.2 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/Paddle/ -c conda-forge 运行如上的命名以后(中间会询问您是否确定安装,输入y就可以了),就可以安装paddlepaddle框架所需要的基本环境依赖包(如果中间网不好,导致有些包下载失败,从新运行如上的吗,命令就可以断点下载了)。至此。pytorch和paddlepaddle的深度学习环境就安装好了。6. pycharm安装--验证CUDA和cudnn版本打开这个pycharm网址,可以发现一共有两个版本一个是专业版(Professional),一个是社区版(Community),专业版是需要花钱的,好几百美元一年。而社区版是免费的,但是也够用了,所以就下载安装社区版就好了。 将下载好的pycharm安装包,双击。安装的地址最好不要放在C盘,我是安装在D盘(反正我 的软件是不喜欢安装在C盘的。总害怕C盘会满)。将所有的√都勾上,安装好了点击第二个框框,然后点完成就好了 打开pycharm,创建一个新的工程,来测试anaconda是否在安装pytorch和paddlepaddle框架的时候也安装了cuda和cudnn。按如下两图创建一个工程(新工程好像必须要安装一个新的python插件),新的工程最好在D盘一个新的文件夹下,有的工程很大,C盘容易装满。 按以上的方式创建了一个工程,这时候我们就要选择我们在anaconda里面安装的环境,在界面的右下角 按照如图中的选项选择我们在anaconda中创建的深度学习环境,可以看到有paddle和pytorch两个环境,我们先选择pytorch环境。 此时刚刚的右下角已经有了我们刚刚选择的pytorch环境中的python了。我们在创建的工程里面创建一个python脚本,在脚本中运行如下代码,查看是否anconda在安装pytorch环境的时候也安装了cuda和cudnn。import torch print(torch.cuda.is_available()) print(torch.backends.cudnn.is_available()) print(torch.cuda_version) print(torch.backends.cudnn.version())可以发现控制台打印出两个True,可以说明cuda和cudnn已经安装。并且可以得到cuda的版本为11.3和cudnn的版本为8.2版本。 安装如上的方法将python的版本切换为paddle环境中的python插件。运行如下的代码1. import paddle 2. print(paddle.utils.run_check()) 可以得到cudade 版本为11.2,cudnn的版本为8.1。 至此我们的深度学习环境安装就已经完全完成。接下来可以在相对的环境下进行深度学习的实验了。 最后还要申明一下,你可以创建不同的环境,在里面安装不同版本的cuda和cudnn版本。已经亲自尝试过了,是可以的。7. 总结 本文介绍win11系统下基于Anaconda安装pytorch和paddle深度学习环境,接下来我会记录我的pytorch和paddle深度学习记录,很高兴能和大家分享!🤣🤣🤣希望你能有所收获。
1.0 安装驱动首先大家下载驱动:包含BC20USB驱动,CH341驱动,FT232驱动,ST-LINK官方驱动,万能驱动1.1 FT232驱动1.2 CH341驱动2.0 BC20开发板 BC20是一款高性能、低功耗、多频段、支持GNSS定位功能的 NB-loT无线通信模块。在设计上兼容移远通 GSM/GPRS/GNSS系列的MC20模块,方便客户快速、灵活的进行产品设计和升级。BC20提供丰富的外部接和协议栈UDP/TCP/ COAP/LWM2M/MQTT/HTTP等,同时支持移动OneNET云平台/阿里云平台/电信云平台/华为云平台/湖畔云平台,为客户的应用提供极大的便利。 支持北斗、GPS、QzSS等多星座卫星系统解调算法,其定位更加精准,抗多路径干扰能力更强,比传统的单 GPS模块具有更多优势。另外,BC20模块中内置LNA和低功耗算法:前者保证更高的灵敏度,后者保证低功耗模式下更低的耗流。 BC20模块较传统NB-loT+GNSS方案体积减少40%。凭借其紧凑尺寸、超低功耗和超宽工作温度范围,BC20在各种应用中占具更大优势;其主要应用领域为:自行车和摩托车防盗、宠物追踪、金融财产追踪及行车记录仪等等。2.1 BC20核心板原理图2.2 BC20底板原理图3.0 接线NB AT指令usb-ttl接到NB-IOT-uart 四根线USART1打到485(朝右)4.0 指令调试4.1 NB AT指令调试串口助手见:超级好用的SSCOM3.2串口助手检查NB AT指令usb-ttl接到NB-IOT-uart 四根线连接串口1,选择115200波特率,打开串口,助手操作步骤:勾选发送新行发送对应AT命令查看串口显示AT+CPIN? //准备读卡,返回READY AT+CEREG? //查看注册状态,返回0,1为注册成功 AT+CSQ //查看信号质量,数字越大信号越好(参考值20) AT+CIMI //查看卡号 AT+CGPADDR=1 //查看是否分配IP地址,模块接入基站 4.2 GPS AT指令调试检查GPS AT指令usb-ttl接到NB-IOT-uart 四根线连接串口1,选择115200波特率,打开串口,助手操作步骤:勾选发送新行发送对应AT命令查看串口显示ATI //读取板载信息 AT+QGNSSC=1 //启动GPS,返回READY AT+QGNSSC? //查看启动GPS状态,返回0,1为注册成功 AT+QGNSSDB=1 //查询是否获取到GPS信息 AT+QGNSSRD? //DUG输出GPS信息 AT+QGNSSRD="NMEA/RMC" //读取RMC经纬度有用信息 5.0 总结上文教大家在电脑通过串口助手对BC20开发板进行AT指令的NB和GPS的硬件调试,对比两者各有优势,前者更加保密一些,后者更加简洁。后续会教大家更加奇特的操作,欢迎一键三连😂😂😂在以后的博文中我们将分享更多生活技巧,美好生活每一天!好好学习天天向上,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
用Keil vision5 st-linkv2下载时错误出现Error: Flash Download failed - “Cortex-M3”1.0 BUG问题新安装的keil5.31版本的软件,打开一个工程出现以下的问题。今天突然拿出STM32 BC20(带定位)WiFi来测试一段代码。用Keil vision5下载时错误:原因: 这是因为你下载时模式需要调整。2.0 解决方法2.1 下载模式我用的是st-link,选择SWD(大家选择自己的下载),Debug菜单中,Reset菜单选项(Autodetect/HWreset/sysresetReq/Vectreset)默认是AutoDetect,改成SysResetReq即可。2.2 芯片大小选错SWD模式下,Debug菜单中,主要是芯片大小选错。Flash->Configure Falsh Tools配置窗口,切换到“Utilities"页,按“Setting"按钮进入“Flash download setup"配置窗口,在“Flash download setup"配置窗口点击“Add”按钮,在“Add Flash Programming Algorlthm"窗口,根据你实际使用的芯片选择,若是STM32F103VBT6,应先择"STM32L1xx Med+ 256kB Flash"。3.0 总结用Keil vision5 st-linkv2下载时错误出现Error: Flash Download failed - "Cortex-M3"分下载模式和芯片大小选错,对症下药即可
IDE一般我喜欢用新版的,不是因为旧的不好用或者有什么bug,简单的就是想看下新版本的界面是不是看起来更好看了,是不是又包含了一些令人激动的新功能。1.0 BUG问题所以在MDK5.3出来的时候我就果断更新了。在调试硬件的时候一般我习惯于优先使用串口烧录,今天突然拿出STM32 BC20(带定位)WiFi来测试一段代码。用Keil vision5编译时出现以下更新错误:原因: 这是因为你装的MDK版本太新了,在之前mdk5.25版本是没有这个问题的,只是在mdk5.31下才出现,那也就可以确定是在MDK5.31中集成了新版stlink的接口,导致需要会强制要求用户更新stlink。2.0 解决方法暂时搜索网上解决方法2.1 方法一选择降低MDK5.31让MDK不再提示不就行了,采用mdk5.25版本。所以就做了测试把MDK安装目录下和stlink相关的部分使用旧版本的替换现在新版本的。替换以后就不会再次提示了,可以正常烧录、调试。选择安装路径替换STLink文件这两个版本的stlink组件放在网盘中,需要替换的小伙伴可以自行下载:链接:https://pan.baidu.com/s/1ca4OIkugkUCQfv_eaWMr8A提取码:jzpk3.0 总结直接降版本替换间接解决问题
我们在使用电脑的时候难免会使用一些快捷键,快捷家也是电脑技巧的一种,电脑在使用的时候是有很多的技巧的。那么大家了解的电脑技巧都有哪些呢?电脑是可以通过一些快捷键的设置直接进入某个软件或者某个程序的,学会使用电脑的技巧可以让我们在使用电脑的时候节省非常多的时间。下面,我们来学习一下电脑的使用技巧,看看电脑技巧大全。1. 推荐10个电脑技巧:1.1 win+L锁屏很多时候,需要暂时离开座位去做别的事情,如果对自己的电脑安全很重视,不妨按住windows键后,再按L键,这样电脑就直接锁屏了,这样就不用担心电脑的资料外泄啦1.2 win+E打开我的电脑要找电脑上的文件时,一般人会先找到“我的电脑”,然后点击打开,而高手总是很酷的,轻轻按下键盘上的Windows键不放然后再按E键,直接打开电脑的资源管理器,而一般人还在慢慢寻找“我的电脑”的图标呢,嗯,高手就是这样直接把一般人给秒杀!1.3 win+D闪现桌面正在玩游戏或看羞羞的东西的时候,Boss进来了!鼠标一下子点不到右下角的显示桌面,怎么办,怎么办?别紧张!直接按下Windows键和D键,看,桌面闪现! 1.4 win+Tab切换查看日值一个小花招,蛮炫的。按下windows键按后再按Tab键,可以以3D效果显示切换窗口1.5 win+Rwindows自带的录像功能。按下windows键+R,输入psr.exe回车,然后就可以开始记录了。感觉不怎么好用推荐一个录屏:ScreenToGif 使用教程 1.6 win+X电脑基础设置 你知道怎样一次过调整 显示器 亮度、音量大小,打开无线网,还能够看到本本电池电量吗?把本本的画面放到电视上,已经连好线了,需要怎么设置?小case啦,想要这些功能,你只需要按下Windows键+X,一次性满足你的所有愿望啦!1.7 win+R——osk显示键盘操作状态Windows + R输入osk,出现炫酷虚拟键盘!你按下一个键,它也会同样显示出来按下的状态喔!1.8 win+++++图片太小,眼神不好使咋办? 试试windows键和++++,放大镜出现! 反之windows键和-----缩小 1.9 Ctrl+Tab 应用互相切换OR w关闭现在很多程序,比如QQ,IE,都是在同一个窗口里面打开几个页面。用Ctrl+Tab,可以在几个页面之间互相切换。用Ctrl+w,可以关闭当前的页面。1.10 win+Fn+home按下windows+Pause Break,你就可以打开系统属性了。(其实用鼠标在我的电脑上面右键->属性也一样,不过不觉得用键盘操作更帅嘛。2. 高效插件🎞🎏知网文献最新下载技巧【关于油猴的安装和使用的教程】【关于浏览器插件的安装和使用的教程】3. 外设🎞🎞🎏🎏【解决U盘无法访问】4. 总结🎞🎞🎞🎏🎏🎏上文教大家在电脑上使用技巧。后续会教大家更加奇特的操作,欢迎一键三连😂😂😂在以后的博文中我们将分享更多生活技巧,美好生活每一天!好好学习天天向上,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
1.0 油猴简介Tampermonkey是一个神奇的网络插件,真的是新时代的黑科技,学生党的福音。Tampermonkey对于我来说可是个好东西。请一定要看下去!!😍😍😍而在众多的扩展中,就不得不提到一个浏览器插件——Tampermonkey。中文俗称油猴。相信很多人也听说过,大家可以把他理解为一个用户脚本管理器。它本身是无法为我们发挥什么作用的,它主要依靠各大社区编写的扩展脚本(JavaScript代码)运行在浏览器上,来改变被访问网页的功能,提升我们的网页浏览体验 。2.0 安装环境暂时选用Google Chrome浏览器(其他浏览器也可,以Chrome为例)2.1 安装Google Chrome我们采用电脑管家-软件管理,直接搜索Google,然后一键安装😁😁😀默认安装就好,然后有Google图标2.2 下载油猴官方网址:https://www.tampermonkey.net/index.php?ext=gz80&show=dhdg打开来页面应该如下:😆😆😆然后点击绿色的下载按钮,下载黑色的Tampermonkey Stable:可见人气很高:如果大家不能安装可以点击此文件:油猴插件和Infinity-最佳新标签页增强插件解压文件看安装说明浏览器开发者模式,添加拓展程序安装成功后如图3.0 总结上文教大家在电脑上如何安装Google和添加油猴插件,后续会教大家更加奇特的操作,欢迎一键三连😂😂😂在以后的博文中我们将分享更多生活技巧,美好生活每一天!好好学习天天向上,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
1.0 BUG问题用Keil vision5编译时出现以下错误:原因: 这是因为你装的MDK版本太新了,比如MDK5.12/5.13,它们不会从MDK安装目录去查找头文件。 所以导致这个错误。2.0 解决方法暂时搜索网上解决方法2.1 方法一点击魔法棒设置在C/C++菜单下,添加对应编译文件夹新增路径,选择对应路径可见编译成功😀😀😀2.2 方法二不过很懒的我很快就发现了这个方法比较死板,想想我后面还有好几十个工程呢。。。。。😆😆😆神答复,懒惰的我直接把目标程序\CMSIS\Include 文件夹中的内容复制🎈🎈🎈粘贴到安装目当下 ARMCC 中 ,如(我的目录是 D:\Keil_v5\ARM\ARMCC\include )🧨🧨🧨一样 可见编译成功😀😀😀3.0 总结对比两种解决方法,第二种从根源解决,明显编译时间变短,更加适合多个工程的移植
1.基于市面上典型阿克曼小车设计SolidWorks三维模型;2.小车拥有基本外形还有电池、控制器、深度摄像头等细节;3.小车的URDF模型已经搭建好,可修改导出。1. SolidWorks三维模型本人采用SolidWorks 2016 建模,设计基本外形,然后添加了雷达、深度摄像头、控制器等模块,其中转向机构采用反向阿克曼模型,并采用996舵机驱动,后轮由减速编码电机组成主动轮。整车重量在2KG左右。🎈🎆🎇小车模型见:基于ROS机器人的阿克曼小车SolidWorks三维模型和URDF模型2. 开发环境首先我们需要安装SolidWorks3. 配置URDF首先下载URDF插件,大家可以上ROS也可以进官网哟!安装教程如:【SolidWorks 的 URDF 导出器说明】3.1 检查是否安装成功安装成功可以在工具中查看插件,如下图3.2 URDF配置操作打开需要配置的机器人装配体车子body的底部中心创建参考几何体的中心点,创建完坐标系(或者需要的旋转轴),选择SolidWorks图标旁边的左拉菜单小箭头,选择工具,然后在下拉菜单中找到File,选择Export as urdf。搭建多级连杆,然后设计层级关系关节类型设置后左轮参数设置舵机设置前左轮设置摄像头设置完成后检查是否都正确🎈🎈🎈3.3 验证效果配置完成可见设计树最下方生成对应模型,也可以重新打开编辑(此状态为压缩,不可编辑)导入ROS效果4. 小结在博文中我们学会用== 阿克曼小车导出URDF模型教程 ==,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
SolidWorks 到 URDF 导出器是一个 SolidWorks 插件,可以方便地将 SW 零件和装配体导出到 URDF 文件中。导出器将创建一个类似 ROS 的包,其中包含网格、纹理和机器人(urdf 文件)的目录。对于单个 SolidWorks 零件,零件导出器将提取材料属性并在 URDF 中创建单个链接。对于程序集,导出器将构建链接并基于 SW 程序集层次创建树。导出器可以自动确定正确的关节类型、关节变换和轴。1. SolidWorks 版本兼容性SolidWorks 2018 存在一个已知的 STL 导出错误,该错误一直存在到 Service Pack 4,导致此插件无法使用。如果您使用的是 2018,请更新到 Service Pack 5 或使用 SolidWorks 2019 或更高版本。2017 年及以下也可能有效。(因此我接下来采用的是2016版也可以)🎈🎆🎇2. 开发环境首先我们需要安装SolidWorks开发环境: win10家庭版(无需关注,本人记录而已) SolidWorks版本: SOLIDWORKS(R) Premium 2016 x64版SP 1.0 最近这个插件的开发来自于几个 ROS社区成员的慷慨捐赠。如果没有这种支持或来自社区成员的拉取请求,开发将无法继续。我们也感谢任何错误或功能请求,以便我们可以在资源可用时处理它们。该项目不依赖于 ROS,可用于导出 SolidWorks 文件以满足任何 URDF 需求。URDF 将包含 rospack URI文件位置(‘package://’),因此您需要为非 ROS 系统更改这些位置(一些 Gazebo 系统可以处理 'package’URI)。 此插件已在装有 SolidWorks 2018 SP 5 64 位的 Windows 10 64位上进行了测试。它目前不安装在 32 位机器上。该插件使用最新的 SW API,因此它可能不适用于 SolidWorks 2018之前的版本(但这尚未得到证实)。要了解有关 URDF 的更多信息,请查看其文档。如果您在阅读本文档后对 SolidWorks 到URDF 导出器有任何疑问,请查看ROS Answers以获得可能的答案。如果您没有找到答案,请提交带有“sw_urdf_exporter”标签的问题。3. 安装 URDF首先下载URDF插件,大家可以上ROS也可以进官网哟!官网直达下载可作为预编译的安装程序或作为 Visual Studio C# 项目的源提供。这听起来是编造的,但您不能将文件安装到标有“SW2URDF”的目录中。由于某种原因,Windows 很难找到支持的插件,并且会抛出未处理的异常错误。3.1 预编译安装程序这将安装最新的稳定版本。如果您还没有,请至少升级到🎃.NET Framework V4.7.2。下载上面链接的安装程序。 运行安装程序。它将要求您允许对您的计算机进行更改。您的 Windows帐户需要有足够的权限才能进行这些更改。它应该安装到程序文件中的 SolidWorks 目录中。打开 SolidWorks,在“工具>插件”下,您将在最底部看到一个 SW2URDF项目。如果此安装文件不起作用,请尝试如下所述手动安装。3.2 编译源这些是最新的源文件。因为这是定期签入的,所以源文件中可能存在错误或未完成的代码。如果您需要源的稳定版本,请查看与安装程序相关的修订。要构建源代码,您需要下载Visual Studio Community。使用 git查看源代码。以管理员身份运行Visual Studio。您的 Windows 帐户需要具有这些权限才能注册 .dll。为此,请右键单击开始菜单中的 VisualC#,然后单击“以管理员身份运行”。单击“调试>开始调试”或按 F5。它将一起编译和运行 SolidWorks。这样做一次后,您只需要从 Visual Studio 运行重新编译即可。否则,仅使用该工具,您可以正常启动 SW。当 SolidWorks 打开时,在“工具>插件”下,您将在最底部看到一个 SW2URDF项目。如果此安装文件不起作用,请尝试如下所述手动安装。3.3 验证效果可以打开SolidWorks装配体文件,工具>插件”下,您将在最底部看到一个 SW2URDF 项目,说明插件安装成功。此模型为本人画的阿克曼模型,已经设置好对应的模型,所以可以直接导出。设计思路见:4. 小结通过以上内容我们对URDF 插件有了初步了解。最终实现了插件安装。在以后的博文中我们将学会用== SolidWorks装配体导出URDF 教程 ==,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
1.首先打开Anaconda Prompt终端2. 搭建tensorflow2.3.1 python 3.8.3环境请输入以下代码🎈conda create --name tensorflow2.3.1 python==3.8.3 遇到Process,直接输入“y”,回车就好!3.激活tensorflow2.3.1环境输入以下代码🎈🎈conda activate tensorflow2.3.1 4.安装cudatoolkit cudnn输入以下代🎈🎈🎈conda install cudatoolkit=10.1 cudnn=7.6.5 遇到Process,直接输入“y”,回车就好!5.安装tensorflow-gpu==2.3.1输入以下代码,镜像源采用阿里云🎈🎈🎈🎈pip install tensorflow-gpu==2.3.1 -i https://mirrors.aliyun.com/pypi/simple/ 出现这样就装好了:6. 检验是否可以使用🎈🎈🎈🎈🎈以此输入以下指令,查看对应版本,okpython import tensorflow as tf tf.__version__ print(tf.test.is_gpu_available())
关于巴法云专注于开源,智造,创新,分享。关注硬件与创新,突破技术极限,面向未来,我们是认真的。崇尚开源,发掘未知。 ————巴法科技1. 简介ESP8266-NodeMCU的环境配置已经在一篇文章有所交代,接下让我们开启巴法云的物联网开发吧!😀😀😀设计目标实现esp8266自动配网;实现ESP8266通过TCP协议连接巴法云的TCP创客云,串口发送指令控制LED的亮灭;实现ESP8266通过MQTT协议连接巴法云的MQTT设备云;串口发送指令控制LED的亮灭,还实现DHT11温湿度数据的获取,并将数据上发巴法云平台,在线显示数据;实现巴法云平台对ESP8266的OTA指令升级,基于前面两个实验。2. 实验准备本次需要做三个实验,分别是TCP点灯实验,MQTT发送温湿度和OTA指令升级,准备工作包括硬件💡💡💡和软件💻💻💻两部分。2.1 硬件你要实现巴法云的三个实验,你需要准备以下材料✨✨✨ESP8266-NodeMCU单片机(外加安卓数据线);DHT11温湿度传感器;三根母母杜邦线;硬件连接:ESP8266-NodeMCU硬件连接非常简单,只需将DHT11数据线接入D6引脚就好,这套连线三个实验都通用,具体接线如下🎀🎀🎀ESP8266-NodeMCU -----> USB VCC -----> 3.3V GND -----> GND out -----> D22.2 软件Arduino IED 1.8.5以上(越高越好);浏览器登录巴法云平台。3. 实验步骤首先搭建巴法云平台,创建的产品相关主题,检测相关数据流,上传固件和发送指令,以便后期程序端口接入开发。👩👩👩3.1 TCP点灯实验登录巴法云物联网平台,选择控制台,点击TCP创客云,然后新建light002主题,那么巴法云TCP就配置好了🎈程序设计,程序有四部分bemfa02、TCP 、motion和update,其中:🎈🎈文件名功能bemfa02程序初始化调用和主程序调用;TCP发送数据到TCP服务器,初始化wifi连接,初始化和服务器建立连接;motion检查数据,发送心跳,检查WiFi;update固件升级函数。bemfa02.ino/* * 智能语言控制控制,支持天猫、小爱、小度、google Assistent同时控制 * Time:20211127 * Author: 2345VOR * 项目实例:发送on、off的指令开关灯 * 参考文献:https://bbs.bemfa.com/84/last */ #include <ESP8266WiFi.h> #include <ESP8266httpUpdate.h> #define server_ip "bemfa.com" //巴法云服务器地址默认即可 #define server_port "8344" //服务器端口,tcp创客云端口8344 //********************需要修改的部分*******************// #define wifi_name "J09 502" //WIFI名称,区分大小写,不要写错 #define wifi_password "qwertyuiop111" //WIFI密码 String UID = "e8882ae28d5bde39766c330ea913fd46"; //用户私钥,可在控制台获取,修改为自己的UID String TOPIC = "light002"; //主题名字,可在控制台新建 const int LED_Pin = D4; //单片机LED引脚值,D2是NodeMcu引脚命名方式,其他esp8266型号将D2改为自己的引脚 String upUrl = "http://bin.bemfa.com/b/3BcZTg4ODJhZTI4ZDViZGUzOTc2NmMzMzBlYTkxM2ZkNDY=light002.bin";//固件链接,在巴法云控制台复制、粘贴到这里即可 //**************************************************// //最大字节数 #define MAX_PACKETSIZE 512 //设置心跳值30s #define KEEPALIVEATIME 30*1000 //tcp客户端相关初始化,默认即可 WiFiClient TCPclient; String TcpClient_Buff = "";//初始化字符串,用于接收服务器发来的数据 unsigned int TcpClient_BuffIndex = 0; unsigned long TcpClient_preTick = 0; unsigned long preHeartTick = 0;//心跳 unsigned long preTCPStartTick = 0;//连接 bool preTCPConnected = false; //相关函数初始化 //连接WIFI void doWiFiTick(); void startSTA(); //TCP初始化连接 void doTCPClientTick(); void startTCPClient(); void sendtoTCPServer(String p); //led控制函数,具体函数内容见下方 #define turnOnLed() digitalWrite(LED_Pin,LOW); #define turnOffLed() digitalWrite(LED_Pin,HIGH); // 初始化,相当于main 函数 void setup() { Serial.begin(115200); pinMode(LED_Pin,OUTPUT); digitalWrite(LED_Pin,HIGH); Serial.println("Beginning..."); } //循环 void loop() { doWiFiTick(); doTCPClientTick(); } TCP.ino /* *发送数据到TCP服务器 */ void sendtoTCPServer(String p){ if (!TCPclient.connected()) { Serial.println("Client is not readly"); return; } TCPclient.print(p); } /* *初始化wifi连接 */ void startSTA(){ WiFi.disconnect(); WiFi.mode(WIFI_STA); WiFi.begin(wifi_name, wifi_password); } /* *初始化和服务器建立连接 :style="value.online?'订阅设备在线':'无订阅设备'" color:#9A9A9A; */ void startTCPClient(){ if(TCPclient.connect(server_ip, atoi(server_port))){ Serial.print("\nConnected to server:"); Serial.printf("%s:%d\r\n",server_ip,atoi(server_port)); String tcpTemp=""; //初始化字符串 tcpTemp = "cmd=1&uid="+UID+"&topic="+TOPIC+"\r\n"; //构建订阅指令 sendtoTCPServer(tcpTemp); //发送订阅指令 tcpTemp="";//清空 /* //如果需要订阅多个主题,可再次发送订阅指令 tcpTemp = "cmd=1&uid="+UID+"&topic="+主题2+"\r\n"; //构建订阅指令 sendtoTCPServer(tcpTemp); //发送订阅指令 tcpTemp="";//清空 */ preTCPConnected = true; preHeartTick = millis(); TCPclient.setNoDelay(true); } else{ Serial.print("Failed connected to server:"); Serial.println(server_ip); TCPclient.stop(); preTCPConnected = false; } preTCPStartTick = millis(); } motion.ino/* *检查数据,发送心跳 */ void doTCPClientTick(){ //检查是否断开,断开后重连 if(WiFi.status() != WL_CONNECTED) return; if (!TCPclient.connected()) {//断开重连 if(preTCPConnected == true){ preTCPConnected = false; preTCPStartTick = millis(); Serial.println(); Serial.println("TCP Client disconnected."); TCPclient.stop(); } else if(millis() - preTCPStartTick > 1*1000)//重新连接 startTCPClient(); } else { if (TCPclient.available()) {//收数据 char c =TCPclient.read(); TcpClient_Buff +=c; TcpClient_BuffIndex++; TcpClient_preTick = millis(); if(TcpClient_BuffIndex>=MAX_PACKETSIZE - 1){ TcpClient_BuffIndex = MAX_PACKETSIZE-2; TcpClient_preTick = TcpClient_preTick - 200; } preHeartTick = millis(); } if(millis() - preHeartTick >= KEEPALIVEATIME){//保持心跳 preHeartTick = millis(); Serial.println("--Keep alive:"); sendtoTCPServer("ping\r\n"); //发送心跳,指令需\r\n结尾,详见接入文档介绍 } } if((TcpClient_Buff.length() >= 1) && (millis() - TcpClient_preTick>=200)) { TCPclient.flush(); Serial.print("Rev string: "); TcpClient_Buff.trim(); //去掉首位空格 Serial.println(TcpClient_Buff); //打印接收到的消息 String getTopic = ""; String getMsg = ""; if(TcpClient_Buff.length() > 15){//注意TcpClient_Buff只是个字符串,在上面开头做了初始化 String TcpClient_Buff = ""; //此时会收到推送的指令,指令大概为 cmd=2&uid=xxx&topic=light002&msg=off int topicIndex = TcpClient_Buff.indexOf("&topic=")+7; //c语言字符串查找,查找&topic=位置,并移动7位,不懂的可百度c语言字符串查找 int msgIndex = TcpClient_Buff.indexOf("&msg=");//c语言字符串查找,查找&msg=位置 getTopic = TcpClient_Buff.substring(topicIndex,msgIndex);//c语言字符串截取,截取到topic,不懂的可百度c语言字符串截取 getMsg = TcpClient_Buff.substring(msgIndex+5);//c语言字符串截取,截取到消息 Serial.print("topic:------"); Serial.println(getTopic); //打印截取到的主题值 Serial.print("msg:--------"); Serial.println(getMsg); //打印截取到的消息值 } if(getMsg == "on"){ //如果收到指令on==打开灯 turnOnLed(); }else if(getMsg == "off"){ //如果收到指令off==关闭灯 turnOffLed(); }else if(getMsg == "update"){ //如果收到指令update updateBin();//执行升级函数 } TcpClient_Buff=""; TcpClient_BuffIndex = 0; } } /************************************************************************** WIFI ***************************************************************************/ /* WiFiTick 检查是否需要初始化WiFi 检查WiFi是否连接上,若连接成功启动TCP Client 控制指示灯 */ void doWiFiTick(){ static bool startSTAFlag = false; static bool taskStarted = false; static uint32_t lastWiFiCheckTick = 0; if (!startSTAFlag) { startSTAFlag = true; startSTA(); } //未连接1s重连 if ( WiFi.status() != WL_CONNECTED ) { if (millis() - lastWiFiCheckTick > 1000) { lastWiFiCheckTick = millis(); } } //连接成功建立 else { if (taskStarted == false) { taskStarted = true; Serial.print("\r\nGet IP Address: "); Serial.println(WiFi.localIP()); startTCPClient(); } } } update.ino /** * 固件升级函数 * 在需要升级的地方,加上这个函数即可,例如setup中加的updateBin(); * 原理:通过http请求获取远程固件,实现升级 */ void updateBin(){ Serial.println("start update"); WiFiClient UpdateClient; t_httpUpdate_return ret = ESPhttpUpdate.update(UpdateClient, upUrl); switch(ret) { case HTTP_UPDATE_FAILED: //当升级失败 Serial.println("[update] Update failed."); break; case HTTP_UPDATE_NO_UPDATES: //当无升级 Serial.println("[update] Update no Update."); break; case HTTP_UPDATE_OK: //当升级成功 Serial.println("[update] Update ok."); break; } } 修改bemfa02主程序对应wifi和巴法云参数,upUrl参数可以暂时不修改,实验三再修改🎈🎈🎈编译程序,然后上传esp8266,观察esp8266和巴法云TCP控制台🎈🎈🎈🎈实验效果:在订阅的“light002”主题下,发送on或者off,可见esp8266板载灯分别会亮灭。🎈🎈🎈🎈🎈3.2 MQTT发送温湿度登录巴法云物联网平台,选择控制台,点击MQTT设备云,然后新建led002控制端和temp004状态端主题,那么巴法云MQTT设备云就配置好了🎈程序设计,程序有四部分dht11_led_OTA1.0、OTA(update)PubSubClient.cpp和PubSubClient.h,其中:🎈🎈文件名功能dht11_led_OTA1.0程序初始化调用和主程序调用,自动连接目标wifi,重新连接,led002的回调函数处理;OTA(update)固件升级函数。dht11_led_OTA1.0.ino/* Time:20211127 Author: 2345VOR 项目示例:通过MQTT协议发送on或off控制开关,温湿度上传巴法云 参考文献:https://www.cnblogs.com/bemfa/p/14590133.html */ #include <ESP8266WiFi.h>//默认,加载WIFI头文件 #include "PubSubClient.h"//默认,加载MQTT库文件 #include <ESP8266httpUpdate.h>//自动升级库 https://bbs.bemfa.com/84 #include <SimpleDHT.h>//dht11库文件 String upUrl = "http://bin.bemfa.com/b/1BcZTg4ODJhZTI4ZDViZGUzOTc2NmMzMzBlYTkxM2ZkNDY=led002.bin"; const char* ssid = "J09 502"; //修改,修改为你的路由的WIFI名字 const char* password = "qwertyuiop111"; //修改为你的WIFI密码 const char* mqtt_server = "bemfa.com"; //默认,MQTT服务器地址 const int mqtt_server_port = 9501; //默认,MQTT服务器端口 #define ID_MQTT "e8882ae28d5bde39766c330ea913fd46" //mqtt客户端ID,修改为你的开发者密钥 const char* topic = "led002"; //Led主题名字,可在巴法云控制台自行创建,名称随意 const char * dhttopic = "temp004"; //温湿度主题名字,可在巴法云mqtt控制台创建 int pinDHT11 = D2; //dht11传感器引脚输入 int B_led = D4; //控制的led引脚 long timeval = 3 * 1000; //上传的传感器时间间隔,默认3秒 #define ledstatus !digitalRead(B_led);//led状态默认0 long lastMsg = 0;//时间戳 SimpleDHT11 dht11(pinDHT11);//dht11初始化 WiFiClient espClient; PubSubClient client(espClient);//mqtt初始化 //灯光函数及引脚定义 #define turnOnLed() digitalWrite(B_led, LOW); #define turnOffLed() digitalWrite(B_led, HIGH); //自动连接目标wifi void setup_wifi() { delay(10); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } //重新连接 void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect(ID_MQTT)) {//连接mqtt Serial.println("connected"); client.subscribe(topic);//修改,修改为你的主题 } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void setup() { pinMode(B_led, OUTPUT); Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, mqtt_server_port); client.setCallback(callback); digitalWrite(B_led, HIGH); } void loop() { if (!client.connected()) {//判断mqtt是否连接 reconnect(); } client.loop();//mqtt客户端 long now = millis();//获取当前时间戳 if (now - lastMsg > timeval) {//如果达到3s,进行数据上传 lastMsg = now; // read without samples. byte temperature = 0; byte humidity = 0; int err = SimpleDHTErrSuccess; if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) { Serial.print("Read DHT11 failed, err="); Serial.println(err); delay(1000); return; } String msg = "#" + (String)temperature + "#" + (String)humidity + "#" + ledstatus; //数据封装#温度#湿度#开关状态# client.publish(dhttopic, msg.c_str());//数据上传 } } //topic = "led002"的回调函数处理 void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); String Mqtt_Buff = ""; for (int i = 0; i < length; i++) { Mqtt_Buff += (char)payload[i]; } Serial.print(Mqtt_Buff); Serial.println(); // Switch on the LED if an 1 was received as first character if (Mqtt_Buff == "on") {//如果接收字符on,亮灯 turnOnLed();//开灯函数 } else if (Mqtt_Buff == "off") {//如果接收字符off,亮灯 turnOffLed();//关灯函数 }else if (Mqtt_Buff == "update") {//如果接收字符off,亮灯 client.disconnect(); //关闭mqtt delay(100); updateBin(); //开始升级 } Mqtt_Buff = ""; } OTA(update).ino /** * 固件升级函数 * 在需要升级的地方,加上这个函数即可,例如setup中加的updateBin(); * 原理:通过http请求获取远程固件,实现升级 */ void updateBin(){ Serial.println("start update"); WiFiClient UpdateClient; t_httpUpdate_return ret = ESPhttpUpdate.update(UpdateClient, upUrl); switch(ret) { case HTTP_UPDATE_FAILED: //当升级失败 Serial.println("[update] Update failed."); break; case HTTP_UPDATE_NO_UPDATES: //当无升级 Serial.println("[update] Update no Update."); break; case HTTP_UPDATE_OK: //当升级成功 Serial.println("[update] Update ok."); break; } } PubSubClient.cppPubSubClient.h(略)修改dht11_led_OTA1.0主程序对应wifi和巴法云参数,upUrl参数可以暂时不修改,实验三再修改🎈🎈🎈编译程序,然后上传esp8266,观察esp8266和巴法云MQTT控制台🎈🎈🎈🎈实验效果:在订阅的“led002”主题下,发送on或者off,可见esp8266板载灯分别会亮灭;然后点击temp004主题的更多设置,。🎈🎈🎈🎈🎈3.3 OTA指令升级OTA升级控制图将刚刚两组实验联系起来,实现远程升级固件,通俗讲就是当你配置好实验一,在lighr002输入update指令就可以远程升级到实验二,反而言之也可以。🤩🤩🤩关于上文实验一中的upUrl填写,先生成要升级(实验二)的bin文件,导入到TCP创客云的light002的OTA固件;关于上文实验二中的upUrl填写,先生成要升级(实验一)的bin文件,导入到MQTT设备云的led002的OTA固件,把生成的固件地址复制到对应的实验一的upUrl位置(地址不会变,固件会自动迭代更新)OTA配置好后,重新下载实验一的代码,然后再TCP创客云的light002主题测试on、off和update指令,输入update就会自动升级到实验二代码,可以到MQTT设备云的led002主题下,测试on、off和update指令,这就是实验一和实验二的梦幻操作!😁😀😂实验一效果如下:4. 总结期待大家可以消化代码并且半天实现OTA升级**本文是一个难度中等的物联网项目,实现E实现esp8266自动配网;TCP协议连接巴法云的TCP创客云,串口发送指令控制LED的亮灭;实现ESP8266通过MQTT协议连接巴法云的MQTT设备云;串口发送指令控制LED的亮灭,还实现DHT11温湿度数据的获取,并将数据上发巴法云平台,在线显示数据;实现巴法云平台对ESP8266的OTA指令升级,基于前面两个实验** 😁😁😁在以后的博文中我们将学会用ESP8266做常用的物联网开发,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
1. ESP8266-NodeMCUESP8266-NodeMCU是一个开源硬件开发板,由于它支持WIFI功能,所以在物联网(IOT)领域,Arduino开发板最大的对手之一就是ESP8266-NodeMCU开发板。ESP8266-NodeMCU尺寸与Nano类似,他并不是Arduino团队开发的,但是我们也可以使用Arduino IDE对他进行开发。而且他还有一颗地道的“中国芯”—ESP8266模块。目前流行的ESP8266-NodeMCU有两块,他们只是串口烧写芯片有所不同,因此在开发之前需要安装对应板子的串口驱动,分别是CH340和CP2102驱动,然后直接用安卓数据线连接电脑。1.1 主要技术参数这里我们参考乐鑫公司技术参数项目Value核心模块ESP8266工作电压(VIN)5V输入电压(推荐)5V输入电压(极限)4.5 ~ 10 V数字输入输出引脚10个(全部可以作为PWM引脚)PWM引脚10个模拟输入引脚1个WIFI标准802.11 b / g / n工作模式STA / AP / STA + AP重量7g1.2 NodeMCU引脚功能就是使用上图左边的引脚,不使用右边的引脚可用引脚: ESP8266芯片有17个GPIO引脚(GPIO0~GPIO16)。这些引脚中的GPIO6~GPIO 11被用于连接开发板的闪存(Flash Memory)。如果在实验电路中使用GPIO6~GPIO11,NodeMCU开发板将无法正常工作。因此建议您不要使用GPIO6~GPIO 11。1.3 特殊引脚情况说明GPIO 2 引脚 在NodeMCU开发板启动时是不能连接低电平的。GPIO 15 引脚在开发板运行中一直保持低电平状态。因此请不要使用GPIO15引脚来读取开关状态或进行I²C通讯。GPIO 0 引脚在开发板运行中需要一直保持高电平状态。否则ESP8266将进入程序上传工作模式也就无法正常工作了。您无需对GPIO 0 引脚进行额外操作,因为NodeMCU的内置电路可以确保GPIO 0 引脚在工作时连接高电平而在上传程序时连接低电平。1.4 串行端口ESP8266有2个硬件串行端口(UART):串行端口0(UART0)使用GPIO1和GPIO3引脚。其中GPIO1引脚是TX0,GPIO3是RX0。串行端口1(UART1)使用GPIO2和GPIO8引脚。其中GPIO2引脚是TX1,GPIO8是RX1。请注意,由于GPIO8被用于连接闪存芯片,串行端口1只能使用GPIO2来向外发送串行数据。2. arduino开发环境首先我们需要安装Arduino ID开发环境: win10家庭版(无需关注,本人记录而已) arduino版本: 1.8.15 esp8266固件: 2.4.2 硬件:ESP8266-NodeMCU 第一步打开arduino,找到文件→首选项。在附加开发板管理中添加下面网址。http://arduino.esp8266.com/stable/package_esp8266com_index.json搜索esp8266 进行下载方法二:首先关掉Arduino IDE,直接下载8266_package安装包,直接安装exe即可。3. 配置测试移植代码,然后编译下载,验证实验效果!3.1 移植代码新建项目,然后复制以下代码,也可以打开示例选择ESP8266WiFi中的案例blinker点灯本代码实现one_wifi自动配网,在statin模式下,创建一个连接到可接入wifi热点,方便以后直接接入网络,连接成功后下次自动连接并且打印IP地址,板载灯会交替闪烁。 /** * The blue LED on the ESP-01 module is connected to GPIO2(D4) one_wifi自动配网: statin模式下,创建一个连接到可接入wifi热点,方便以后直接接入网络,连接成功后下次自动连接并且打印IP地址,板载灯会交替闪烁 @author 234vor参考单片机菜鸟 @date 2021/10/30 */ #include <ESP8266WiFi.h> #define AP_SSID "J09 502" //这里改成你的wifi名字 #define AP_PSW "qwertyuiop111"//这里改成你的wifi密码 void setup() { //设置串口波特率,以便打印信息 Serial.begin(115200); //延时2s 为了演示效果 delay(2000); Serial.println("Setup start"); //启动STA模式,并连接到wifi网络 WiFi.begin(AP_SSID, AP_PSW); Serial.print(String("Connecting to ") + AP_SSID); //判断网络状态是否连接上,没连接上就延时200ms,并且打出一个点,模拟连接过程 while (WiFi.status() != WL_CONNECTED) { delay(200); Serial.print("."); } Serial.println(""); Serial.print("Connected, IP address: "); //输出station IP地址,这里的IP地址由DHCP分配 Serial.println(WiFi.localIP()); Serial.println("Setup End"); pinMode(D4, OUTPUT); // 初始化D4引脚为输出引脚 } void loop() { digitalWrite(D4, LOW); // 亮灯 delay(1000); // 延时1s digitalWrite(D4, HIGH);// 灭灯 delay(1000); // 延时1s }3.2 编译上传先选择NodeMCU 1.0开发板,然后点击对号√编译然后选择端口上传3.3 验证效果可以打开串口监视器,会有debug打印,出现“Setup End”就实现了自动联网,板载蓝色LED交替闪烁。4. 小结通过以上内容我们对ESP8266-NodeMCU模块有了初步了解。最终实现了自动联网,板载蓝色LED交替闪烁。在以后的博文中我们将学会用NodeMCU和arduino物联网交互使用,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
🌻🌻🌻 OpenMV是一个开源,低成本,功能强大的机器视觉模块。以STM32主流芯片为核心,集成了OV7725摄像头芯片,在小巧的硬件模块上,提供Python编程接口。🌼🌼🌼使用者们(包括发明家、爱好者以及智能设备开发商)可以用Python语言使用OpenMV提供的机器视觉功能,可根据自身特定的视觉特征需要,通过python设计合理的算法,进而得到稳定可靠的输出,再配合其他单片机交互,有机统一完成对应项目,为自己的产品和发明增加有特色的竞争力。OpenMV起初是国外的开源产品,星瞳科技是OpenMV中国官方代理,还做了好多中文视频、文档教程,这个模块的目标是成为“机器视觉世界的Arduino “,博主认为未来可期😊😊😊1. OpenMV的优势人脸/眼睛检测:您可以使用 OpenMV Cam 使用内置的 Haar Cascade 特征检测算法来检测人脸并找到眼睛。您也可以精确跟踪学生。拍照:OpenMV Cam 可以将灰度或 RGB565 BMP / JPG / PPM / PGM 图像保存到连接的 μSD 卡。您也可以保存延时照片。低功耗:OpenMV Cam 在处理图像时使用的电流小于 200 mA,因此您可以像连接到 USB 端口的微控制器 (Arduino) 一样使用 OpenMV Cam。视频录制:您可以将灰度或 RGB565 MJPEG 视频和灰度或 RGB565 GIF 图像保存到附带的 SD 卡。您也可以在视频上叠加图形/文字。斑点/标记跟踪:OpenMV Cam 可以跟踪灰度或 RGB565 图像中的颜色斑点。它可以进行多色/多斑点跟踪。此外,OpenMV Cam 也可以检测颜色代码。输入/输出控制:借助 OpenMV Cam,您可以使用机器视觉来控制现实世界中的 I/O 引脚。OpenMV Cam 具有 SPI 总线、I2C 总线、异步串行总线 (RX / TX)、ADC、DAC 等。TensorFlow 支持: 分类图像从未如此简单!使用 OpenMV IDE,您可以轻松地构建一个数据集,将该数据集上传到云端的Edge Impulse,并使用迁移学习和 MobileNet 生成一个 TensorFlow Lite 卷积神经网络 (CNN),该网络将在您的 OpenMV Cam 上运行。2. OpenMV的劣势做不了复杂的算法:比如OCR识别,车牌识别,猫狗分类,深度学习之类的。IO口资源有待拓展,运行时间不能过长,发热较大也会出现变砖OpenMV故障可以参考:OpenMV固件升级(DFU)3. OpenMV的基础需要有一点图像处理的背景知识。有过一门编程语言,最好是学习了python,我们接下来的开发就是根据OpenMV IDE的python开发环境,了解if else等逻辑语句,知道变量赋值等概念。有单片机的基础,了解IO输入输出口,串口通讯等概念。4. 点亮我们的OpenMV本人采用win10 的OpenMV IDE 2.8.1开发环境,下面代码就是点亮我们的OpenMV,==打开机器的眼睛==👨💻👨💻👨💻# Hello World Example # # Welcome to the OpenMV IDE! Click on the green run arrow button below to run the script! import sensor, image, time sensor.reset() # Reset and initialize the sensor. sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE) sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240) sensor.skip_frames(time = 2000) # Wait for settings take effect. clock = time.clock() # Create a clock object to track the FPS. while(True): clock.tick() # Update the FPS clock. img = sensor.snapshot() # Take a picture and return the image. print(clock.fps()) # Note: OpenMV Cam runs about half as fast when connected # to the IDE. The FPS should increase once disconnected. 然后点击绿色三角形运行程序,显示结果:5. 总结本文介绍本文介绍OpenMV优缺点以及所需的背景知识,然后通过OpenMV IDE的python开发环境运行了“Hello World”程序,成功点亮!后期还会有更多好玩的教程更新,很高兴能和大家分享🤣🤣🤣希望你能有所收获。
本文介绍win10系统下通过Anaconda配置基于python语言的机器视觉编程环境,主要内容包括:Anaconda下载安装OpenCV下载安装测试安装结果本文安装的版本为:Anaconda3-2020.11-Windows-x86_64+Python3.8+OpenCV4.11. Anaconda下载与安装1.1 Anaconda简介官方网址:https://www.anaconda.com/Anaconda是一个开源的Python发行版本,其包含了conda、Python、Qt、PyCharm、RStudio等180多个编程语言、机器视觉相关库、数据分析包,支持 Linux, Mac, Windows三种常见系统,并方便的管理python环境。可以为python初学者提供诸多方便,同时也是一些深度学习框架官方建议的python安装库。Anaconda目前已经有5.1版本,其中Anaconda2.5.1对应python2.7版本,Anaconda3-2020.11对应现在的是python3.8。换而言之安装好Anaconda后等于python就装好了,并且python的常用的numpy、pip等库也一并安装了。关于如何使用Anaconda管理python环境和安装其他依赖包,后面请听分解。1.2 Anaconda下载安装1.2.1 下载Anaconda不同版本和平台的Anaconda均可以从官网或国内镜像网站下载,当然国内镜像要快许多。下载地址:清华镜像源:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/官网下载:https://www.anaconda.com/download/1.2.2 安装Anaconda下文以windows版本的Anaconda3.4.2为例,介绍其安装过程。下载对应版本后,双击exe文件安装。安装过程中,根据需要选择用户,默认即可。设置合适安装路径,可以自行修改路径至比较好找的位置如d:\dev文件夹,建议路径件夹使用英文命名且不要有空格。下面建议两个选项都勾选:①将Anaconda添加到我的环境变量Path中,选中此项目确保使用Python,IPython、conda和其他程序时可以使用本次安装的python。②将Anaconda设置为本机的默认的Python3.8。选中此项后,其他编译器默认将Anaconda作为默认的Python3.8环境。后续再安装其他Python的IDE(例如我推荐给大家的Pycharm等)时,这些后装的IDE将自动检测Anaconda并优先选择Anaconda的Python作为其Python解释器(interpreter)。点击install安装直至结束。1.2.3 查看python版本打开开始菜单–程序–Anaconda3(64-bit)文件夹,启动Anaconda Navigator查看Python安装版本,如下图所示,为Python 3.5.2,注意在下一步下载opencv时,需要下载对应版本的文件。我在win10系统中也做了安装测试,如果在win10系统,同样打开开始菜单,在Anaconda文件夹中运行Anaconda Prompt或者Spyder查看Python安装版本。Anaconda Prompt启动后,输入python回车,即可查看到版本信息如下图所示。如果大家安装的是Anaconda3-2020.11版本,对应的版本为python3.8.5。2.OpenCV下载与安装OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。2.1 OpenCV简介官方网址:https://opencv.org/大家后期学习可以参照Oline Documentation、Tutorials2.2 OpenCV安装Python环境中的OpenCV下载配置有多种方式。第一种方式:独立下载安装python,并分别下载安装各依赖库,再安装OpenCV,此方式可参考博文:https://blog.csdn.net/iracer/article/details/51537020第二种方式:通过Anaconda安装python和各依赖库,再使用Anaconda安装OpenCV,下文重点介绍这种方式。我们选择左侧菜单中的Environments,然后点击下方出现的Create,然后输入新环境的名称,就叫opencv好啦😁😁😁,下面就选择默认的python3.8就好,最后点击Create就等待一小会就自动搭建opencv的python环境紧接着可以看见opencv环境,然后选择all,输入opencv回车,然后apply安装就好显示结果如上我们再回到Home,install Jupyter and Spyter常用的开发环境,这样就大功告成3. 测试安装点击Launch,启动Spyder3.1 配置Lena图片首先在网络上down一下Lena照片,也可以直接复制如下图片,Lena为本次测试对象命名为test.jpg格式,保存在E:/lesson/image/文件夹(需要自己新建)3.2 验证代码在代码编辑区输入如下测试代码# -*- coding: utf-8 -*- import cv2# 导入cv2库 i=cv2.imread("E:/lesson/image/test.jpg",cv2.IMREAD_UNCHANGED)#读取E:/lesson/image/test.jpg赋值给变量i cv2.imshow("Demo",i)#显示变量i图像 cv2.waitKey(0)#等待操作 cv2.destroyAllWindows()#关闭所有窗口 cv2.imwrite("E:/lesson/image/lesson1.png",i)#将变量i写入E:/lesson/image/lesson1.png,等同于复制图片为png格式点击菜单栏绿色运行按钮或者“Run file(F5)”。然后回车关闭程序,该路径“E:/lesson/image/”会新增“lesson1.png”如果运行到此,今天的环境配置就大功告成了!4. 总结本文介绍win10系统下通过Anaconda配置基于python语言的opencv机器视觉编程环境,意见环境测试,上图我们可以清晰看见这张图,本人有感:我们每个人何尝不是满目疮痍,但是任然要微笑面对生活,接下来我会记录我的opencv的学习记录,很高兴能和大家分享!🤣🤣🤣希望你能有所收获。
1.0 idata中国知网网址:idata中国知网进入系统,注册账号,登录即可。每天五篇额度,少量够用,如果专业需求大不推荐2.0 校园网IP访问电子资源大部分学校都购买了中外文献库,其中一般包含知网、万方等文献数据库,并且为了师生使用方便,开通了校外访问入口(校园图书馆登录)。登录校园网,IP访问电子资源即可免费下载知网文献。3.0 SciHub学术导航在我们获取文献与学术论文的道路上提供了极好的便利,可以从中得到免费的文献下载,但也因为这样遭到各大出版社具体操作参照:相关链接https://sci-hub.shop/https://sci-hub.ren/https://sci-hub.tw/https://sci-hub.se/https://www.scihub.net.cn/集大成,强烈推荐😁😁4.0 Slager网址:Slager官网强烈推荐一款本地的LaTeX在线编译器-Slager, 帮你解决论文写作的两大难题—排版和公式编辑。让大家不在排版上多花1分钟,论文轻松过!也可以搜索中外文献,直接下载PDF,还有各种期刊论文、PPT、简历、海报的模板5.0 本省图书馆系统作为中国人,在这个和谐美丽的热土上生活✨✨✨,是这辈子的荣幸💖💖💖;因此所在的每个省份都有对应的图书馆,这里面的资源可以说是包罗万象,这样形容再适合不过啦!🚗🛺🚒🚜网址:湖北省图书馆总结本文为我们获取文献与学术论文的道路上提供了极好的便利。也为我们找各种资源提供了很好的途径,那就好好珍惜,积累本领,祝各位学有所成 🛹🚲🛴🛵
2023年08月
2023年04月