{ "cells": [ { "cell_type": "markdown", "id": "c842e127", "metadata": {}, "source": [ "# Qu'est-ce que le CANopen? #\n", "\n", "CANopen est un protocole de communication (couche supérieur) basé sur le réseau bus CAN.\n", "La norme CANopen permet l'interopérabilité entre les dispositifs (nœuds) et fournit des méthodes standard pour configurer les appareils, y compris après leur installation.\n", "\n", "Aujourd'hui, CANopen est largement utilisé dans la commande de moteurs (moteurs pas à pas/servomoteurs) et dans un large éventail d'autres applications, notamment l'automobile.\n", "\n", "Le réseau CANOpen est constitué de nœuds (équipements) reliés entre eux par un même bus CAN terminé par deux résistances de 120 Ohm.\n", "\n", "Trois modèles de réseau sont possibles :\n", "- Maître / Esclave\n", "- Client / Serveur\n", "- Producteur / Consommateur\n", "\n", "la norme CiA 301 stipule que CANopen est basé sur des ID CAN de 11 bits." ] }, { "cell_type": "markdown", "id": "731f3a1a", "metadata": {}, "source": [ "## Fonctionnement général ##\n", "### Liaison physique ###\n", "\n", "Le format standard CANopen ne spécifie pas de connecteurs particulier. Toutefois les connecteurs DB9 sont couramment employés suivant le câblage illustré ci-dessous:" ] }, { "cell_type": "code", "execution_count": null, "id": "2d35e527", "metadata": { "tags": [ "remove-input" ] }, "outputs": [ { "data": { "text/html": [ "\"DB9" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import HTML\n", "HTML('\"DB9" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import HTML\n", "HTML('\"trame\n", " Objets de diffusion prédéfinis (envoi à tous les nœuds)\n", " \n", " \n", " Object\n", " Function Code\n", " Décimal\n", " Héxadécimal\n", " paramètres de communication\n", " \n", " \n", " \n", " \n", " NMT\n", " 0000\n", " 0\n", " 0\n", " -\n", " \n", " \n", " SYNC\n", " 0001\n", " 128\n", " 80\n", " (1005)\n", " \n", " \n", " TIME\n", " 0010\n", " 256\n", " 100\n", " non supporté\n", " \n", " \n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from IPython.display import display, HTML\n", "\n", "html_table_code_function = \"\"\"\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Objets de diffusion prédéfinis (envoi à tous les nœuds)
ObjectFunction CodeDécimalHéxadécimalparamètres de communication
NMT000000-
SYNC000112880(1005)
TIME0010256100non supporté
\"\"\"\n", "from IPython.display import HTML, display\n", "display(HTML(html_table_code_function))" ] }, { "cell_type": "code", "execution_count": 10, "id": "315b9dc0", "metadata": { "tags": [ "remove-input" ] }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Objets prédéfinis peer-to-peer (1 nœud envoie à 1 nœud)
ObjectFunction CodeDécimalHéxadécimalparamètres de communicationpriorité
EMERGENCY0001129..25581..FFhigh
TxPDO 10011385..511181..1FF1800-
RxPDO 10100513..639201..27F1400-
TxPDO 20101641..767281..2FF1801-
RxPDO 20110769..895301..37F1401-
TxPDO 30111897..1023381..3FF1802-
RxPDO 310001025..1151401..47F1402-
TxPDO 410011153..1279481..4FF1803-
RxPDO 410101281..1407501..57F1403-
SDO (tx*)10111409..1535581..5FF--
SDO (rx*)11001537..1663601..67F--
HEARTBEAT11101793..1919701..77F(100E)low
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from IPython.display import display, HTML\n", "\n", "\n", "html_table_code_function_peer_to_peer = \"\"\"\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Objets prédéfinis peer-to-peer (1 nœud envoie à 1 nœud)
ObjectFunction CodeDécimalHéxadécimalparamètres de communicationpriorité
EMERGENCY0001129..25581..FFhigh
TxPDO 10011385..511181..1FF1800-
RxPDO 10100513..639201..27F1400-
TxPDO 20101641..767281..2FF1801-
RxPDO 20110769..895301..37F1401-
TxPDO 30111897..1023381..3FF1802-
RxPDO 310001025..1151401..47F1402-
TxPDO 410011153..1279481..4FF1803-
RxPDO 410101281..1407501..57F1403-
SDO (tx*)10111409..1535581..5FF--
SDO (rx*)11001537..1663601..67F--
HEARTBEAT11101793..1919701..77F(100E)low
\"\"\"\n", "from IPython.display import HTML, display\n", "display(HTML(html_table_code_function_peer_to_peer))" ] }, { "cell_type": "code", "execution_count": null, "id": "7599dd81", "metadata": { "tags": [ "remove-input" ] }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Définitions des Function Code
Function CodeDéfinition
NMT
(Network Management Objects)
\n", "

Les objets NMT suivent le protocole master/slave.
\n", " Un maître NMT contrôle l'« état » des esclaves par le biais de commandes NMT.
Pour modifier l'état d'un appareil, le maître NMT envoie un message avec le COB-ID 0x0, que tous les nœuds esclaves traitent. Le premier octet de données contient l'état demandé, tandis que le deuxième octet de données CAN contient l'ID du nœud ciblé.
L'ID de nœud 0 indique une commande de diffusion.
Les valeurs de demande d'état comprennent

\n", "

\"NMT

\n", "
SYNC
(Synchronization Object)
\n", "

Le message SYNC suit le protocole producer/consumer.
\n", " Un producteur (généralement le maître CANopen) diffuse périodiquement le message SYNC avec un ID de haute priorité (COB-ID 0x80). Cela permet aux consommateurs CANopen SYNC de synchroniser le moment où ils doivent, par exemple, diffuser des données via des PDO d'émission.

\n", "
TIME
(Timestamp Object)
\n", "

Le message TIME suit le protocole producer/consumer et fournit une horloge à distribuer à l'échelle du réseau.
\n", " Le producteur diffuse le message TIME avec le COB_ID 0x100 et une charge utile de 6 octets : 4 octets de données contiennent l'heure en ms après minuit et les 2 octets suivants contiennent le nombre de jours écoulés depuis le 1er janvier 1984.

\n", "
EMCY
(Emergency Object)
\n", "

L'objet emergency suit le protocole producer/consumer et est utilisé lorsqu'un dispositif subit une erreur fatale (par exemple, une défaillance de capteur), ce qui lui permet de l'indiquer au reste du réseau. Le nœud concerné envoie un seul message EMCY avec COB-ID 0x80 + ID du nœud (par exemple 0x85 pour le nœud 5). Les octets de données contiennent des informations sur l'erreur, un registre d'erreur de 1 octet et jusqu'à 5 octets d'informations d'erreur spécifiques au fabricant.

\n", "
HEARTBEAT
(Heartbeat Object)
\n", "

Le message de battement de cœur suit le protocole producer/consumer. Les esclaves CANopen peuvent diffuser périodiquement un message de battement de cœur (par exemple toutes les 100 ms) avec COB-ID 0x700 + ID du nœud (c'est-à-dire 0x705 pour le nœud 5). La charge utile contient l'état du nœud dans le premier octet de données (démarrage, préopérationnel, opérationnel, arrêté). Cela permet à un consommateur (par exemple le maître) de réagir rapidement si un nœud ne diffuse pas son battement de cœur dans un délai donné.

\n", "
SDO
(Service Data Object)
\n", "

Configurer le réseau CANOpen.
\n", " Les demandes/réponses SDO sont envoyées via le protocole « client/server ». Un « client » SDO initie la communication avec un « server » SDO. L'objectif peut être de mettre à jour une entrée du OD Object Dictionary (« SDO download ») ou de lire une entrée (« SDO upload »). Cela permet, par exemple, la configuration et le diagnostic des nœuds.

\n", "
PDO
(Process Data Object)
\n", "

Exploiter le réseau CANOpen.
\n", " Le PDO est utilisé pour le transfert efficace de données opérationnelles en temps réel entre les nœuds CANopen.
\n", " Le protocole « consumer/producer » est utilisé. Un producteur « produit des données » qu'il transmet à un ou plusieurs « consommateurs » à l'aide d'un PDO de transmission (TxPDO). Inversement, il peut recevoir des données du consommateur via un PDO de réception (RxPDO).
\n", " Les PDO peuvent être envoyés par transmission synchrone (en réponse à un SYNC) ou par transmission événementielle (par exemple, périodiquement).
\n", " NB: Le SDO pourrait être utilisé pour la même fonction mais avec beaucoup plus de surcharge. Un PDO peut contenir 8 octets de données et plusieurs valeurs de paramètres d'objet dans une seule trame.

\n", "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from IPython.display import display, HTML\n", "\n", "html_table_definition_code_function= \"\"\"\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Définitions des Function Code
Function CodeDéfinition
NMT
(Network Management Objects)
\n", "

Les objets NMT suivent le protocole master/slave.
\n", " Un maître NMT contrôle l'« état » des esclaves par le biais de commandes NMT.
Pour modifier l'état d'un appareil, le maître NMT envoie un message avec le COB-ID 0x0, que tous les nœuds esclaves traitent. Le premier octet de données contient l'état demandé, tandis que le deuxième octet de données CAN contient l'ID du nœud ciblé.
L'ID de nœud 0 indique une commande de diffusion.
Les valeurs de demande d'état comprennent

\n", "

\"NMT

\n", "
SYNC
(Synchronization Object)
\n", "

Le message SYNC suit le protocole producer/consumer.
\n", " Un producteur (généralement le maître CANopen) diffuse périodiquement le message SYNC avec un ID de haute priorité (COB-ID 0x80). Cela permet aux consommateurs CANopen SYNC de synchroniser le moment où ils doivent, par exemple, diffuser des données via des PDO d'émission.

\n", "
TIME
(Timestamp Object)
\n", "

Le message TIME suit le protocole producer/consumer et fournit une horloge à distribuer à l'échelle du réseau.
\n", " Le producteur diffuse le message TIME avec le COB_ID 0x100 et une charge utile de 6 octets : 4 octets de données contiennent l'heure en ms après minuit et les 2 octets suivants contiennent le nombre de jours écoulés depuis le 1er janvier 1984.

\n", "
EMCY
(Emergency Object)
\n", "

L'objet emergency suit le protocole producer/consumer et est utilisé lorsqu'un dispositif subit une erreur fatale (par exemple, une défaillance de capteur), ce qui lui permet de l'indiquer au reste du réseau. Le nœud concerné envoie un seul message EMCY avec COB-ID 0x80 + ID du nœud (par exemple 0x85 pour le nœud 5). Les octets de données contiennent des informations sur l'erreur, un registre d'erreur de 1 octet et jusqu'à 5 octets d'informations d'erreur spécifiques au fabricant.

\n", "
HEARTBEAT
(Heartbeat Object)
\n", "

Le message de battement de cœur suit le protocole producer/consumer. Les esclaves CANopen peuvent diffuser périodiquement un message de battement de cœur (par exemple toutes les 100 ms) avec COB-ID 0x700 + ID du nœud (c'est-à-dire 0x705 pour le nœud 5). La charge utile contient l'état du nœud dans le premier octet de données (démarrage, préopérationnel, opérationnel, arrêté). Cela permet à un consommateur (par exemple le maître) de réagir rapidement si un nœud ne diffuse pas son battement de cœur dans un délai donné.

\n", "
SDO
(Service Data Object)
\n", "

Configurer le réseau CANOpen.
\n", " Les demandes/réponses SDO sont envoyées via le protocole « client/server ». Un « client » SDO initie la communication avec un « server » SDO. L'objectif peut être de mettre à jour une entrée du OD Object Dictionary (« SDO download ») ou de lire une entrée (« SDO upload »). Cela permet, par exemple, la configuration et le diagnostic des nœuds.

\n", "
PDO
(Process Data Object)
\n", "

Exploiter le réseau CANOpen.
\n", " Le PDO est utilisé pour le transfert efficace de données opérationnelles en temps réel entre les nœuds CANopen.
\n", " Le protocole « consumer/producer » est utilisé. Un producteur « produit des données » qu'il transmet à un ou plusieurs « consommateurs » à l'aide d'un PDO de transmission (TxPDO). Inversement, il peut recevoir des données du consommateur via un PDO de réception (RxPDO).
\n", " Les PDO peuvent être envoyés par transmission synchrone (en réponse à un SYNC) ou par transmission événementielle (par exemple, périodiquement).
\n", " NB: Le SDO pourrait être utilisé pour la même fonction mais avec beaucoup plus de surcharge. Un PDO peut contenir 8 octets de données et plusieurs valeurs de paramètres d'objet dans une seule trame.

\n", "
\"\"\"\n", "from IPython.display import HTML, display\n", "display(HTML(html_table_definition_code_function))" ] }, { "cell_type": "code", "execution_count": 12, "id": "09eadb1e", "metadata": { "tags": [ "remove-input" ] }, "outputs": [ { "data": { "text/html": [ "\"CANopen" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import HTML\n", "HTML('\"CANopen" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import HTML\n", "HTML('\"function" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import HTML\n", "HTML('\"OD" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import HTML\n", "HTML('\"SDO\"\n", " \n", " \n", " \n", " 0x40\n", " \n", " Lecture d’une entré de l’OD\n", " \n", " \n", " \n", " 0x23\n", " \n", " Écriture de 32 bits (SDO receive)\n", " \n", " \n", " \n", " 0x27\n", " \n", " Écriture de 24 bits (SDO receive)\n", " \n", " \n", " \n", " 0x2B\n", " \n", " Écriture de 16 bits (SDO receive)\n", " \n", " \n", " \n", " 0x2F\n", " \n", " Écriture de 8 bits (SDO receive)\n", " \n", " \n", " \n", " 0x43\n", " \n", " Réponse de l’appareil cible sur 32 bits (SDO transmit)\n", " \n", " \n", " \n", " 0x47\n", " \n", " Réponse de l’appareil cible sur 24 bits (SDO transmit)\n", " \n", " \n", " \n", " 0x4B\n", " \n", " Réponse de l’appareil cible sur 16 bits (SDO transmit)\n", " \n", " \n", " \n", " 0x4F \n", " \n", " Réponse de l’appareil cible sur 8 bits (SDO transmit)\n", " \n", " \n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from IPython.display import display, HTML\n", "\n", "\n", "html_table_definition_message= \"\"\"\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " 0x40\n", " Lecture d’une entré de l’OD
\n", " 0x23\n", " Écriture de 32 bits (SDO receive)
\n", " 0x27\n", " Écriture de 24 bits (SDO receive)
\n", " 0x2B\n", " Écriture de 16 bits (SDO receive)
\n", " 0x2F\n", " Écriture de 8 bits (SDO receive)
\n", " 0x43\n", " Réponse de l’appareil cible sur 32 bits (SDO transmit)
\n", " 0x47\n", " Réponse de l’appareil cible sur 24 bits (SDO transmit)
\n", " 0x4B\n", " Réponse de l’appareil cible sur 16 bits (SDO transmit)
\n", " 0x4F \n", " Réponse de l’appareil cible sur 8 bits (SDO transmit)
\"\"\"\n", "from IPython.display import HTML, display\n", "display(HTML(html_table_definition_message))" ] }, { "cell_type": "markdown", "id": "3db870dd", "metadata": {}, "source": [ "- 16 bits d’index et 8 bits de sous-index : adresse du paramètre dans l’OD\n", "- 32 bits de données : les données non utilisées sont inactivées,**l’écriture est réalisée en « little endian » (le dernier bit transmis est le premier lu)**" ] }, { "cell_type": "markdown", "id": "5ca3e785", "metadata": {}, "source": [ "\n", "### Protocole PDO ###\n", "Le protocole PDO possède trois modes de configurations :\n", "- Static PDO : la configuration des PDO est fixée par le fabricant et non modifiable,\n", "- Variable PDO : la configuration est modifiable en mode pré-opérationnel,\n", "- Dynamic PDO : la configuration est modifiable en mode pré-opérationnel et opérationnel.\n", "\n", "Chaque message PDO est configuré par deux entrées : ses paramètres de communication et ses paramètres de mapping (configuration). On définit deux catégories de PDO : les RPDO pour les messages reçus et les TPDO pour les messages envoyés.\n", "\n", "Les messages PDO sont configurés sur 4 listes d’entrée du OD :\n", "- 0x1400 à 0x15FF : paramètres de communication pour les RPDO,\n", "- 0x1600 à 0x17FF : paramètres de mapping pour les RPDO,\n", "- 0x1800 à 0x19FF : paramètres de communication pour les TPDO,\n", "- 0x1A00 à 0x1BFF : paramètres de mapping pour les TPDO.\n", "\n", "Les paramètres de communication sont configurés par les sous-index :" ] }, { "cell_type": "code", "execution_count": null, "id": "d4f269cc", "metadata": { "tags": [ "remove-input" ] }, "outputs": [ { "data": { "text/html": [ "\"COB-ID\"" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import HTML\n", "HTML('\"COB-ID\"" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import HTML\n", "HTML('